newsworthycharts 1.54.4__py3-none-any.whl → 1.54.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- newsworthycharts/__init__.py +1 -1
- newsworthycharts/lib/locator.py +4 -1
- {newsworthycharts-1.54.4.dist-info → newsworthycharts-1.54.5.dist-info}/METADATA +11 -6
- {newsworthycharts-1.54.4.dist-info → newsworthycharts-1.54.5.dist-info}/RECORD +7 -12
- {newsworthycharts-1.54.4.dist-info → newsworthycharts-1.54.5.dist-info}/WHEEL +1 -1
- newsworthycharts/datalist.py +0 -128
- newsworthycharts/formatter.py +0 -93
- newsworthycharts/locator.py +0 -60
- newsworthycharts/mimetypes.py +0 -8
- newsworthycharts/utils.py +0 -83
- {newsworthycharts-1.54.4.dist-info → newsworthycharts-1.54.5.dist-info}/LICENSE.txt +0 -0
- {newsworthycharts-1.54.4.dist-info → newsworthycharts-1.54.5.dist-info}/top_level.txt +0 -0
newsworthycharts/__init__.py
CHANGED
newsworthycharts/lib/locator.py
CHANGED
@@ -79,7 +79,10 @@ def get_best_locator(delta, points, interval=None):
|
|
79
79
|
|
80
80
|
elif interval == "daily" or interval is None:
|
81
81
|
if delta.days > 30:
|
82
|
-
# FIXME dont print every month
|
83
82
|
return MonthLocator()
|
83
|
+
elif delta.days > 21:
|
84
|
+
return DayLocator(interval=10)
|
85
|
+
elif delta.days > 7:
|
86
|
+
return DayLocator(interval=5)
|
84
87
|
else:
|
85
88
|
return DayLocator()
|
@@ -1,9 +1,9 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: newsworthycharts
|
3
|
-
Version: 1.54.
|
3
|
+
Version: 1.54.5
|
4
4
|
Summary: Matplotlib wrapper to create charts and publish them on Amazon S3
|
5
5
|
Home-page: https://github.com/jplusplus/newsworthycharts
|
6
|
-
Download-URL: https://github.com/jplusplus/newsworthycharts/archive/1.54.
|
6
|
+
Download-URL: https://github.com/jplusplus/newsworthycharts/archive/1.54.5.tar.gz
|
7
7
|
Author: Jens Finnäs and Leo Wallentin, J++ Stockholm
|
8
8
|
Author-email: stockholm@jplusplus.org
|
9
9
|
License: MIT
|
@@ -11,15 +11,15 @@ Requires-Python: >=3.9
|
|
11
11
|
Description-Content-Type: text/x-rst
|
12
12
|
License-File: LICENSE.txt
|
13
13
|
Requires-Dist: Babel <3,>=2.14.0
|
14
|
-
Requires-Dist: Pillow ==10.
|
14
|
+
Requires-Dist: Pillow ==10.2.0
|
15
15
|
Requires-Dist: PyYAML >=3
|
16
16
|
Requires-Dist: adjustText ==0.7.3
|
17
17
|
Requires-Dist: boto3 >=1.26
|
18
|
-
Requires-Dist: geopandas ==0.14.
|
18
|
+
Requires-Dist: geopandas ==0.14.3
|
19
19
|
Requires-Dist: langcodes >=3.3
|
20
20
|
Requires-Dist: mapclassify ==2.6.1
|
21
21
|
Requires-Dist: matplotlib-label-lines ==0.5.1
|
22
|
-
Requires-Dist: matplotlib ==3.8.
|
22
|
+
Requires-Dist: matplotlib ==3.8.3
|
23
23
|
Requires-Dist: numpy <2,>=1.21.0
|
24
24
|
Requires-Dist: python-dateutil <3,>=2
|
25
25
|
Requires-Dist: requests >=2.22
|
@@ -181,6 +181,11 @@ Roadmap
|
|
181
181
|
Changelog
|
182
182
|
---------
|
183
183
|
|
184
|
+
- 1.54.5
|
185
|
+
|
186
|
+
- Improved tick placement in daily charts
|
187
|
+
- Minor upgrades: matplotlib==3.8.3; Pillow==10.2.0; geopandas==0.14.3
|
188
|
+
|
184
189
|
- 1.54.4
|
185
190
|
|
186
191
|
- Use Babel 2.14, and pin version
|
@@ -213,7 +218,7 @@ Changelog
|
|
213
218
|
- 1.53.0
|
214
219
|
|
215
220
|
- Fixed bug in value_labels, trying to access a color value that didn't exist
|
216
|
-
- Dropped Python 3.
|
221
|
+
- Dropped Python 3.8 support (upstream)
|
217
222
|
- Uses Matplotlib 3.8
|
218
223
|
- Uses Pillow 10
|
219
224
|
|
@@ -1,21 +1,16 @@
|
|
1
|
-
newsworthycharts/__init__.py,sha256=
|
1
|
+
newsworthycharts/__init__.py,sha256=YejHDUN0WmsE1o9IIiZZFyVDgdMbw2LUW36azjvNuzM,1160
|
2
2
|
newsworthycharts/bubblemap.py,sha256=_AMj3RkmKDKVmrtj3FuuY776xRUSEf2qE8tG0vQ3Lyg,2619
|
3
3
|
newsworthycharts/categoricalchart.py,sha256=k2cd96pNysbVU88nZduiLGpzyjMsDXTbASAVu6ov-kI,14686
|
4
4
|
newsworthycharts/chart.py,sha256=FX8aMTAZCUYtDpY4UNvKAly7NevZSFAVraK4JNdxp5Q,30557
|
5
5
|
newsworthycharts/choroplethmap.py,sha256=KXtdiRBe-_j_zUozUgdhAWyoYN-eUdFxt9mneN10H1w,6670
|
6
|
-
newsworthycharts/datalist.py,sha256=pQTzWg1lKslAstiF04oK7FwvoxTK2-1jOvrlOy7bGpk,3721
|
7
6
|
newsworthycharts/datawrapper.py,sha256=RRkAVTpfP4updKxUIBaSmKuBi2RUVPaBRF8HDQhlGGA,11250
|
8
|
-
newsworthycharts/formatter.py,sha256=N-Z2lDQKcI7Nv9JluAg6yWK8HwPLq09PhbBrSAabGxQ,2728
|
9
|
-
newsworthycharts/locator.py,sha256=WIe4_jQKrvdpXEayK8zGGgPVyHHoFeO6KBqDTr7qE14,1944
|
10
7
|
newsworthycharts/map.py,sha256=e0WRcLTmb1KPZ7_-05QXgthMEmKrTpnci40DXnmd6Rc,5984
|
11
|
-
newsworthycharts/mimetypes.py,sha256=t_wD5FD2o1Di7NWAQGwc8ScPry48S1_7hX03_1Do-G8,129
|
12
8
|
newsworthycharts/rangeplot.py,sha256=NE1W9TnmlpK6T3RvBJOU3nd73EXqkj17OY9i5zlw_cQ,8366
|
13
9
|
newsworthycharts/scatterplot.py,sha256=6iaMoiZx__Gc-2Hcdw-8Ga5dSonrFo3oexKNmSFuir4,4959
|
14
10
|
newsworthycharts/seasonalchart.py,sha256=rr55yqJUkaYDR9Ik98jes6574oY1U8t8LwoLE3gClW4,1967
|
15
11
|
newsworthycharts/serialchart.py,sha256=mEE-9Yahas7o86wTaynJY4hyhBm1If5qPYB8gExMXlo,24563
|
16
12
|
newsworthycharts/storage.py,sha256=myERhlpvXyExXxUByBq9eW1bWkCyfH9SwTZbsWSyy3Q,4301
|
17
13
|
newsworthycharts/stripechart.py,sha256=9B6PX2MyLuKNQ8W0OGdKbP0-U32kju0K_NHHwwz_J68,1547
|
18
|
-
newsworthycharts/utils.py,sha256=aC3OF-HAsEe_WnNV2Ah_oq0QYcAETUscRZ6nQBpazQg,2842
|
19
14
|
newsworthycharts/custom/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
20
15
|
newsworthycharts/custom/climate_cars.py,sha256=WyNLgjgRCv_zRrzVuk_BmcigFSzpzudjEAYmdvdBe8I,9407
|
21
16
|
newsworthycharts/lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -24,7 +19,7 @@ newsworthycharts/lib/colors.py,sha256=U04TDkvoMQkcldRFXfnwyLOTwq1SWW2se-Ad-DNcw9
|
|
24
19
|
newsworthycharts/lib/datalist.py,sha256=fsO_esZBt4Aw_4n_l2LuswAYArbM-8Z8G9DAXo1oVZU,5376
|
25
20
|
newsworthycharts/lib/formatter.py,sha256=GNH43hE0bC17OgiV8LYH3YUrEhm7OJh9XzfSV4HVtHo,4838
|
26
21
|
newsworthycharts/lib/geography.py,sha256=K0_teFmuPJwXX7Py-amJB_1YY5_gL2kBYhz1LrRCyTg,584
|
27
|
-
newsworthycharts/lib/locator.py,sha256=
|
22
|
+
newsworthycharts/lib/locator.py,sha256=73ZqAvvLBhnWd0rKEHTyPiIL1H3MFHiUlb8aRKEm4FA,2938
|
28
23
|
newsworthycharts/lib/mimetypes.py,sha256=bL9HtVWbn2Of39LcBt4u4yelkr4bGZiyebq3OfLnfFY,237
|
29
24
|
newsworthycharts/lib/utils.py,sha256=2Ko0dNFw2eHd32zQwJFUsgDkJGWSl6VacZs4AFPgrc8,7038
|
30
25
|
newsworthycharts/maps/se-4.gpkg,sha256=oWw5j7FPVpI0ig67jNDim8qSn5SG8rcHp0014-uTKZM,290816
|
@@ -33,8 +28,8 @@ newsworthycharts/rc/newsworthy,sha256=X0btLNrmk2DRrfOsKj_WCSIgeD6btacEN2tRF_B4m8
|
|
33
28
|
newsworthycharts/translations/datawrapper_regions.csv,sha256=fzZcQRX6RFMlNNP8mpgfYNdR3Y0QAlQxDXk8FXTaWWI,9214
|
34
29
|
newsworthycharts/translations/regions.py,sha256=Nv1McQjggD4S3JRu82rDMTG3pqUVR13E5-FBpSYbm98,239
|
35
30
|
newsworthycharts/translations/se_municipalities.csv,sha256=br_mm-IvzQtj_W55_ATREhJ97jWnCweBFlDAVY2EBxA,7098
|
36
|
-
newsworthycharts-1.54.
|
37
|
-
newsworthycharts-1.54.
|
38
|
-
newsworthycharts-1.54.
|
39
|
-
newsworthycharts-1.54.
|
40
|
-
newsworthycharts-1.54.
|
31
|
+
newsworthycharts-1.54.5.dist-info/LICENSE.txt,sha256=Sq6kGICrehbhC_FolNdXf0djKjTpv3YqjFCIYsxdQN4,1069
|
32
|
+
newsworthycharts-1.54.5.dist-info/METADATA,sha256=yMQ9TNCdd4z4ovk5O7kw6_HCLd4aNJtfdi2pvaQswto,23776
|
33
|
+
newsworthycharts-1.54.5.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
34
|
+
newsworthycharts-1.54.5.dist-info/top_level.txt,sha256=dn_kzIj8UgUCMsh1PHdVEQJHVGSsN7Z8YJF-8xXa8n0,17
|
35
|
+
newsworthycharts-1.54.5.dist-info/RECORD,,
|
newsworthycharts/datalist.py
DELETED
@@ -1,128 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Holds a class for storing lists of data (timeseries etc), and related methods.
|
3
|
-
"""
|
4
|
-
from collections.abc import MutableSequence
|
5
|
-
from math import inf
|
6
|
-
from .utils import to_float, to_date
|
7
|
-
from numpy import array, isnan, interp, flatnonzero
|
8
|
-
|
9
|
-
|
10
|
-
def fill_na(arr):
|
11
|
-
"""Get an estimate for missing value based on closest non-missing values in
|
12
|
-
series.
|
13
|
-
https://stackoverflow.com/questions/9537543/replace-nans-in-numpy-array-with-closest-non-nan-value
|
14
|
-
|
15
|
-
>>> fill_na([2.0, None, 4.0])
|
16
|
-
[2.0, 3.0, 4.0]
|
17
|
-
"""
|
18
|
-
if isinstance(arr, list):
|
19
|
-
arr = array(arr)
|
20
|
-
arr = arr.astype(float)
|
21
|
-
mask = isnan(arr)
|
22
|
-
arr[mask] = interp(flatnonzero(mask),
|
23
|
-
flatnonzero(~mask),
|
24
|
-
arr[~mask])
|
25
|
-
|
26
|
-
return arr.tolist()
|
27
|
-
|
28
|
-
|
29
|
-
class DataList(MutableSequence):
|
30
|
-
""" A list of datasets, that keeps track of some useful additional data
|
31
|
-
such as min/max values.
|
32
|
-
Datasets are on the format [(x1, y1), (x2, y2), ...]
|
33
|
-
"""
|
34
|
-
|
35
|
-
def __init__(self, *args):
|
36
|
-
self.min_val = inf
|
37
|
-
self.max_val = -inf
|
38
|
-
self._x_points = set()
|
39
|
-
self.list = list()
|
40
|
-
self.extend(list(args))
|
41
|
-
|
42
|
-
def check(self, v):
|
43
|
-
# Update metadata with newly added data
|
44
|
-
values = [to_float(x[1]) for x in v]
|
45
|
-
values = [x for x in values if x is not None]
|
46
|
-
if len(values):
|
47
|
-
self.min_val = min(self.min_val, min(values))
|
48
|
-
self.max_val = max(self.max_val, max(values))
|
49
|
-
self._x_points.update([x[0] for x in v])
|
50
|
-
|
51
|
-
# Normalize to 3 digit syntax
|
52
|
-
v = [x if len(x) > 2
|
53
|
-
else (x[0], x[1], None)
|
54
|
-
for x in v]
|
55
|
-
# Automatically enumerate empty x values / category names if empty
|
56
|
-
v = [x if x[0] not in ["", None]
|
57
|
-
else (i, x[1], x[2])
|
58
|
-
for i, x in enumerate(v)]
|
59
|
-
return v
|
60
|
-
|
61
|
-
@property
|
62
|
-
def values(self):
|
63
|
-
""" Return values from each data serie """
|
64
|
-
return [[to_float(x[1]) for x in s] for s in self.list]
|
65
|
-
|
66
|
-
@property
|
67
|
-
def as_dict(self):
|
68
|
-
""" Return data points as dictionaries """
|
69
|
-
return [{x[0]: x[1] for x in s} for s in self.list]
|
70
|
-
|
71
|
-
@property
|
72
|
-
def filled_values(self):
|
73
|
-
""" Return values with all gaps filled, so that each series has the
|
74
|
-
same number of points.
|
75
|
-
|
76
|
-
>>>> dl = DataList([
|
77
|
-
[("a", 5), ("b", 6), ("c", 7)],
|
78
|
-
[("a", 1), ("c", 3)]
|
79
|
-
])
|
80
|
-
>>>> dl.filled_y_values
|
81
|
-
[[5, 6, 7], [1, 2, 3]]
|
82
|
-
"""
|
83
|
-
|
84
|
-
x_points = self.x_points
|
85
|
-
return [fill_na([to_float(d[x])
|
86
|
-
if x in d else None
|
87
|
-
for x in x_points])
|
88
|
-
for d in self.as_dict]
|
89
|
-
|
90
|
-
@property
|
91
|
-
def x_points(self):
|
92
|
-
return sorted(list(self._x_points))
|
93
|
-
|
94
|
-
@property
|
95
|
-
def inner_min_x(self):
|
96
|
-
return max(list(filter(lambda x: x[1] is not None, s))[0][0] for s in self.list)
|
97
|
-
|
98
|
-
@property
|
99
|
-
def inner_max_x(self):
|
100
|
-
return min(list(filter(lambda x: x[1] is not None, s))[-1][0] for s in self.list)
|
101
|
-
|
102
|
-
@property
|
103
|
-
def outer_min_x(self):
|
104
|
-
return min(list(filter(lambda x: x[1] is not None, s))[0][0] for s in self.list)
|
105
|
-
|
106
|
-
@property
|
107
|
-
def outer_max_x(self):
|
108
|
-
return max(list(filter(lambda x: x[1] is not None, s))[-1][0] for s in self.list)
|
109
|
-
|
110
|
-
def __len__(self):
|
111
|
-
return len(self.list)
|
112
|
-
|
113
|
-
def __getitem__(self, i):
|
114
|
-
return self.list[i]
|
115
|
-
|
116
|
-
def __delitem__(self, i):
|
117
|
-
del self.list[i]
|
118
|
-
|
119
|
-
def __setitem__(self, i, v):
|
120
|
-
v = self.check(v)
|
121
|
-
self.list[i] = v
|
122
|
-
|
123
|
-
def insert(self, i, v):
|
124
|
-
v = self.check(v)
|
125
|
-
self.list.insert(i, v)
|
126
|
-
|
127
|
-
def __str__(self):
|
128
|
-
return str(self.list)
|
newsworthycharts/formatter.py
DELETED
@@ -1,93 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Module for doing (very) simple i18n work.
|
3
|
-
"""
|
4
|
-
from babel.numbers import format_decimal, format_percent, Locale
|
5
|
-
from babel.units import format_unit
|
6
|
-
from decimal import Decimal
|
7
|
-
|
8
|
-
|
9
|
-
class Formatter(object):
|
10
|
-
"""
|
11
|
-
A formatter for a specific language and locale.
|
12
|
-
Contains some methods for number and text formatting.
|
13
|
-
|
14
|
-
Heavier i18n work should be before involving newsworthycharts.
|
15
|
-
Usage:
|
16
|
-
|
17
|
-
>>> fmt = Formatter("sv-SE")
|
18
|
-
>>> fmt.percent(0.14)
|
19
|
-
"14 %"
|
20
|
-
"""
|
21
|
-
def __init__(self, lang, decimals=None, scale="celcius"):
|
22
|
-
"""
|
23
|
-
:param decimals (int): force formatting to N number of decimals
|
24
|
-
"""
|
25
|
-
self.l = Locale.parse(lang.replace("-", "_"))
|
26
|
-
self.language = self.l.language
|
27
|
-
self.decimals = decimals
|
28
|
-
self.scale = scale
|
29
|
-
|
30
|
-
def __repr__(self):
|
31
|
-
return "Formatter: " + repr(self.l)
|
32
|
-
|
33
|
-
def __str__(self):
|
34
|
-
return self.l.get_display_name()
|
35
|
-
|
36
|
-
def percent(self, x, *args, **kwargs):
|
37
|
-
|
38
|
-
if self.decimals is None:
|
39
|
-
# Show one decimal by default if values is < 1%
|
40
|
-
if abs(x) < 0.01:
|
41
|
-
x = round(x, 1+2)
|
42
|
-
else:
|
43
|
-
x = round(x, 2)
|
44
|
-
else:
|
45
|
-
x = round(x, self.decimals+2)
|
46
|
-
|
47
|
-
return format_percent(x, locale=self.l, decimal_quantization=False)
|
48
|
-
|
49
|
-
def temperature_short(self, x, *args, **kwargs):
|
50
|
-
""" Format a temperature in deegrees, without scale letter """
|
51
|
-
|
52
|
-
decimals = self.decimals
|
53
|
-
if decimals is None:
|
54
|
-
decimals = 1
|
55
|
-
|
56
|
-
x = round(Decimal(x), decimals)
|
57
|
-
str = format_unit(x, 'temperature-generic', "short", locale=self.l)
|
58
|
-
return str
|
59
|
-
|
60
|
-
def temperature(self, x, *args, **kwargs):
|
61
|
-
""" Format a temperature in deegrees, with scale letter """
|
62
|
-
|
63
|
-
decimals = self.decimals
|
64
|
-
if decimals is None:
|
65
|
-
decimals = 1
|
66
|
-
|
67
|
-
scale = "temperature-{}".format(self.scale)
|
68
|
-
x = round(Decimal(x), decimals)
|
69
|
-
str = format_unit(x, scale, "short", locale=self.l)
|
70
|
-
return str
|
71
|
-
|
72
|
-
def number(self, x, *args, **kwargs):
|
73
|
-
"""Format as number.
|
74
|
-
|
75
|
-
:param decimals (int): number of decimals.
|
76
|
-
"""
|
77
|
-
decimals = self.decimals
|
78
|
-
if decimals is None:
|
79
|
-
# Default roundings
|
80
|
-
if abs(x) < 0.1:
|
81
|
-
decimals = 2
|
82
|
-
elif abs(x) < 1:
|
83
|
-
decimals = 1
|
84
|
-
else:
|
85
|
-
decimals = 0
|
86
|
-
x = round(Decimal(x), decimals)
|
87
|
-
return format_decimal(x, locale=self.l)
|
88
|
-
|
89
|
-
def short_month(self, x, *args, **kwargs):
|
90
|
-
return self.l.months['format']['abbreviated'][x]
|
91
|
-
|
92
|
-
def month(self, x, *args, **kwargs):
|
93
|
-
return self.l.months['format']['wide'][x]
|
newsworthycharts/locator.py
DELETED
@@ -1,60 +0,0 @@
|
|
1
|
-
""" Custom locators and related methods
|
2
|
-
"""
|
3
|
-
from matplotlib.dates import YearLocator, MonthLocator, DayLocator
|
4
|
-
from datetime import datetime
|
5
|
-
|
6
|
-
|
7
|
-
def get_year_ticks(start_date, end_date, max_ticks=5):
|
8
|
-
""" Get `max_ticks` or less evenly distributed yearly ticks, including
|
9
|
-
start and end years. All ticks fall on January 1.
|
10
|
-
"""
|
11
|
-
|
12
|
-
years = range(start_date.year, end_date.year+1)
|
13
|
-
n_years = len(years)
|
14
|
-
max_ticks = min(max_ticks, n_years)
|
15
|
-
# Avoid N2 < ticks < N, where there will be odd looking gaps
|
16
|
-
if n_years > 3:
|
17
|
-
if round(n_years/2) < max_ticks < n_years:
|
18
|
-
max_ticks = round(n_years/2)
|
19
|
-
|
20
|
-
# -2 for the ends
|
21
|
-
# +1 because cutting a cake in n+1 pieces gives n cuts
|
22
|
-
if max_ticks > 1:
|
23
|
-
cuts = n_years/(max_ticks-2+1)
|
24
|
-
else:
|
25
|
-
cuts = 0
|
26
|
-
selected_years = [years[int(x * cuts)] for x in range(0, max_ticks-1)]
|
27
|
-
|
28
|
-
# add last year
|
29
|
-
if max_ticks > 0:
|
30
|
-
selected_years.append(years[-1])
|
31
|
-
|
32
|
-
# Ticks should be on the first day of the year
|
33
|
-
selected_dates = [datetime(y, 1, 1) for y in selected_years]
|
34
|
-
return selected_dates
|
35
|
-
|
36
|
-
|
37
|
-
def get_best_locator(delta, points):
|
38
|
-
""" Get the optimal locator given a time delta and number of points.
|
39
|
-
This methods will be much more conservative than Matplotlib's AutoLocator,
|
40
|
-
trying to keep the x axis as clean as possible, while still including
|
41
|
-
enough clues for the reader to easily understand the graph.
|
42
|
-
"""
|
43
|
-
if delta.days > 365*150:
|
44
|
-
return YearLocator(100)
|
45
|
-
if delta.days > 365*45:
|
46
|
-
return YearLocator(20)
|
47
|
-
elif delta.days > 365:
|
48
|
-
if points > 20:
|
49
|
-
return YearLocator(10)
|
50
|
-
elif points > 10:
|
51
|
-
return YearLocator(5)
|
52
|
-
elif points > 5:
|
53
|
-
return YearLocator(2)
|
54
|
-
else:
|
55
|
-
return YearLocator()
|
56
|
-
elif delta.days > 30:
|
57
|
-
# FIXME dont print every month
|
58
|
-
return MonthLocator()
|
59
|
-
else:
|
60
|
-
return DayLocator()
|
newsworthycharts/mimetypes.py
DELETED
newsworthycharts/utils.py
DELETED
@@ -1,83 +0,0 @@
|
|
1
|
-
""" Various utility methods """
|
2
|
-
from matplotlib import rc_file, rcParams
|
3
|
-
from matplotlib.colors import to_rgba
|
4
|
-
from datetime import datetime
|
5
|
-
import os
|
6
|
-
import yaml
|
7
|
-
|
8
|
-
HERE = os.path.dirname(__file__)
|
9
|
-
|
10
|
-
|
11
|
-
class StyleNotFoundError(FileNotFoundError):
|
12
|
-
pass
|
13
|
-
|
14
|
-
|
15
|
-
def loadstyle(style_name):
|
16
|
-
""" Load a custom style file, adding both rcParams and custom params.
|
17
|
-
Writing a proper parser for these settings is in the Matplotlib backlog,
|
18
|
-
so let's keep calm and avoid inventing their wheel.
|
19
|
-
"""
|
20
|
-
|
21
|
-
style = {}
|
22
|
-
style_file = os.path.join(HERE, 'rc', style_name)
|
23
|
-
try:
|
24
|
-
# Check rc directory for built in styles first
|
25
|
-
rc_file(style_file)
|
26
|
-
except FileNotFoundError as e:
|
27
|
-
# Check current working dir or path
|
28
|
-
style_file = style_name
|
29
|
-
try:
|
30
|
-
rc_file(style_file)
|
31
|
-
except FileNotFoundError as e:
|
32
|
-
raise StyleNotFoundError("No such style file found")
|
33
|
-
style = rcParams.copy()
|
34
|
-
|
35
|
-
# The style files may also contain an extra section with typography
|
36
|
-
# for titles and captions (these can only be separately styled in code,
|
37
|
-
# as of Matplotlib 2.2)
|
38
|
-
# This is a hack, but it's nice to have all styling in one file
|
39
|
-
# The extra styling is prefixed with `#!`
|
40
|
-
with open(style_file, 'r') as f:
|
41
|
-
doc = f.readlines()
|
42
|
-
rcParamsNewsworthy = "\n".join([d[2:]
|
43
|
-
for d in doc if d.startswith("#!")])
|
44
|
-
rcParamsNewsworthy = yaml.safe_load(rcParamsNewsworthy)
|
45
|
-
style["title_font"] = [x.strip()
|
46
|
-
for x in rcParamsNewsworthy["title_font"]
|
47
|
-
.split(",")]
|
48
|
-
color = rcParamsNewsworthy.get("neutral_color",
|
49
|
-
rcParams["figure.edgecolor"])
|
50
|
-
strong_color = rcParamsNewsworthy.get("strong_color", color)
|
51
|
-
fill_between_color = rcParamsNewsworthy.get("fill_between_color", "F7F4F4")
|
52
|
-
fill_between_alpha = rcParamsNewsworthy.get("fill_between_alpha", 0.5)
|
53
|
-
style["neutral_color"] = to_rgba("#" + str(color), 1)
|
54
|
-
style["strong_color"] = to_rgba("#" + str(strong_color), 1)
|
55
|
-
style["fill_between_color"] = to_rgba("#" + str(fill_between_color), 1)
|
56
|
-
style["fill_between_alpha"] = float(fill_between_alpha)
|
57
|
-
if "logo" in rcParamsNewsworthy:
|
58
|
-
style["logo"] = rcParamsNewsworthy["logo"]
|
59
|
-
|
60
|
-
return style
|
61
|
-
|
62
|
-
|
63
|
-
def rpad(list_, item, length):
|
64
|
-
"""
|
65
|
-
Right pad a list to a certain length, using `item`
|
66
|
-
"""
|
67
|
-
if list_ is None:
|
68
|
-
list_ = []
|
69
|
-
return list_ + [item for i in range(max(0, length-len(list_)))]
|
70
|
-
|
71
|
-
|
72
|
-
def to_float(s):
|
73
|
-
"""Convert string to float, but also handles None and 'null'."""
|
74
|
-
if s is None:
|
75
|
-
return None
|
76
|
-
if str(s) == "null":
|
77
|
-
return
|
78
|
-
return float(s)
|
79
|
-
|
80
|
-
|
81
|
-
def to_date(s):
|
82
|
-
"""Convert date string to datetime date."""
|
83
|
-
return datetime.strptime(s, "%Y-%m-%d")
|
File without changes
|
File without changes
|