newsworthycharts 1.72.1__py3-none-any.whl → 1.73.1__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/chart.py +8 -2
- newsworthycharts/choroplethmap.py +6 -1
- newsworthycharts/lib/locator.py +17 -8
- newsworthycharts/serialchart.py +75 -39
- {newsworthycharts-1.72.1.dist-info → newsworthycharts-1.73.1.dist-info}/METADATA +16 -3
- {newsworthycharts-1.72.1.dist-info → newsworthycharts-1.73.1.dist-info}/RECORD +10 -10
- {newsworthycharts-1.72.1.dist-info → newsworthycharts-1.73.1.dist-info}/LICENSE.txt +0 -0
- {newsworthycharts-1.72.1.dist-info → newsworthycharts-1.73.1.dist-info}/WHEEL +0 -0
- {newsworthycharts-1.72.1.dist-info → newsworthycharts-1.73.1.dist-info}/top_level.txt +0 -0
newsworthycharts/__init__.py
CHANGED
newsworthycharts/chart.py
CHANGED
@@ -427,7 +427,7 @@ class Chart(object):
|
|
427
427
|
self.ax.xaxis.set_major_formatter(DateFormatter('%Y'))
|
428
428
|
|
429
429
|
else:
|
430
|
-
loc = get_best_locator(delta, len(dates), self.interval)
|
430
|
+
loc = get_best_locator(delta, len(dates), self.interval, max_ticks=self.max_ticks)
|
431
431
|
self.ax.xaxis.set_major_locator(loc)
|
432
432
|
formatter = Formatter(self._language)
|
433
433
|
|
@@ -776,7 +776,13 @@ class Chart(object):
|
|
776
776
|
'Creator': f"NWCharts {__version__}",
|
777
777
|
}
|
778
778
|
"""
|
779
|
-
|
779
|
+
"""
|
780
|
+
if img_format == "avif":
|
781
|
+
from matplotlib.animation import FuncAnimation, PillowWriter
|
782
|
+
ani = FuncAnimation(self._fig, lambda x: [], frames=[0], blit=True)
|
783
|
+
ani.save(buf, writer=PillowWriter(fps=1), dpi=self._fig.dpi * factor)
|
784
|
+
else:
|
785
|
+
"""
|
780
786
|
self._fig.savefig(buf, **args) # , bbox_inches="tight")
|
781
787
|
buf.seek(0)
|
782
788
|
self._storage.save(key, buf, img_format, storage_options)
|
@@ -174,6 +174,11 @@ class ChoroplethMap(Map):
|
|
174
174
|
# We need to add it ourselves
|
175
175
|
label_order = self.label_order or color_map.keys()
|
176
176
|
for label in reversed(label_order):
|
177
|
+
if label not in color_map:
|
178
|
+
if str(label) in color_map:
|
179
|
+
label = str(label)
|
180
|
+
else:
|
181
|
+
continue
|
177
182
|
color = color_map[label]
|
178
183
|
# A bit of an hack:
|
179
184
|
# Check if this corresponds to one of our predefined
|
@@ -229,4 +234,4 @@ class ChoroplethMap(Map):
|
|
229
234
|
handles=patches,
|
230
235
|
**label_kwargs,
|
231
236
|
)
|
232
|
-
#self.ax.get_figure().savefig("TST.png", bbox_inches="tight")
|
237
|
+
# self.ax.get_figure().savefig("TST.png", bbox_inches="tight")
|
newsworthycharts/lib/locator.py
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
""" Custom locators and related methods
|
2
2
|
"""
|
3
|
-
from matplotlib.dates import (YearLocator,
|
4
|
-
WeekdayLocator)
|
3
|
+
from matplotlib.dates import (YearLocator, DayLocator,
|
4
|
+
WeekdayLocator, AutoDateLocator)
|
5
|
+
import matplotlib.dates as mdates
|
6
|
+
|
5
7
|
from datetime import datetime
|
6
8
|
from dateutil.rrule import MO
|
7
9
|
|
@@ -36,7 +38,7 @@ def get_year_ticks(start_date, end_date, max_ticks=5):
|
|
36
38
|
return selected_dates
|
37
39
|
|
38
40
|
|
39
|
-
def get_best_locator(delta, points, interval=None):
|
41
|
+
def get_best_locator(delta, points, interval=None, max_ticks=None):
|
40
42
|
""" Get the optimal locator given a time delta and number of points.
|
41
43
|
This methods will be much more conservative than Matplotlib's AutoLocator,
|
42
44
|
trying to keep the x axis as clean as possible, while still including
|
@@ -61,10 +63,12 @@ def get_best_locator(delta, points, interval=None):
|
|
61
63
|
else:
|
62
64
|
# Less than a year:
|
63
65
|
if interval in ["monthly", "quarterly"]:
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
66
|
+
locator = AutoDateLocator(maxticks=max_ticks)
|
67
|
+
locator.intervald = {
|
68
|
+
mdates.MONTHLY: [1, 2, 3, 4, 6], # only allow monthly intervals
|
69
|
+
}
|
70
|
+
return locator
|
71
|
+
# return MonthLocator()
|
68
72
|
|
69
73
|
elif interval == "weekly":
|
70
74
|
# NB The threshold are not tested thoroughly. Consider adjusting.
|
@@ -82,7 +86,12 @@ def get_best_locator(delta, points, interval=None):
|
|
82
86
|
|
83
87
|
elif interval == "daily" or interval is None:
|
84
88
|
if delta.days > 30:
|
85
|
-
|
89
|
+
locator = AutoDateLocator(maxticks=max_ticks)
|
90
|
+
locator.intervald = {
|
91
|
+
mdates.MONTHLY: [1, 2, 3, 4, 6], # only allow monthly intervals
|
92
|
+
}
|
93
|
+
return locator
|
94
|
+
# return MonthLocator()
|
86
95
|
elif delta.days > 21:
|
87
96
|
return DayLocator(interval=10)
|
88
97
|
elif delta.days > 7:
|
newsworthycharts/serialchart.py
CHANGED
@@ -37,7 +37,7 @@ class SerialChart(Chart):
|
|
37
37
|
|
38
38
|
self.grid = True
|
39
39
|
self.point_marker = "."
|
40
|
-
self.line_marker =
|
40
|
+
self.line_marker = None
|
41
41
|
self.line_marker_size = 3
|
42
42
|
|
43
43
|
self.max_ticks = 10
|
@@ -234,16 +234,26 @@ class SerialChart(Chart):
|
|
234
234
|
highlight_value)
|
235
235
|
highlight_diff['y1'] = max(highlight_diff['y1'],
|
236
236
|
highlight_value)
|
237
|
-
if self.type[i]
|
237
|
+
if self.type[i] in ["line", "markers"]:
|
238
238
|
# Put first series on top
|
239
239
|
zo = len(series) - i + 1
|
240
240
|
zo += 10 # Make sure lines are on top of bars
|
241
241
|
|
242
|
-
|
243
|
-
|
242
|
+
lw = self.line_width
|
243
|
+
mz = self.line_marker_size
|
244
|
+
lm = self.line_marker
|
245
|
+
if self.type[i] == "markers":
|
246
|
+
if lm is None:
|
247
|
+
lm = "o"
|
248
|
+
if lw is None:
|
249
|
+
lw = self._nwc_style.get("lines.linewidth", 2) / 2
|
250
|
+
mz *= 3
|
244
251
|
else:
|
245
|
-
|
246
|
-
|
252
|
+
if lm is None:
|
253
|
+
lm = "-"
|
254
|
+
if lw is None:
|
255
|
+
lw = self._nwc_style.get("lines.linewidth", 2)
|
256
|
+
|
247
257
|
if hasattr(self, "_get_line_colors"):
|
248
258
|
# Hook for sub classes
|
249
259
|
color = self._get_line_colors(i)
|
@@ -252,6 +262,9 @@ class SerialChart(Chart):
|
|
252
262
|
color = self._nwc_style["qualitative_colors"][i]
|
253
263
|
else:
|
254
264
|
color = self.colors[i]
|
265
|
+
elif self.highlight in dates_str and self.type[i] == "markers":
|
266
|
+
# For markers, will will use a logic similar to bars
|
267
|
+
color = self._nwc_style["neutral_color"]
|
255
268
|
elif i == 0:
|
256
269
|
color = self._nwc_style["strong_color"]
|
257
270
|
else:
|
@@ -263,44 +276,67 @@ class SerialChart(Chart):
|
|
263
276
|
line, = self.ax.plot(
|
264
277
|
dates,
|
265
278
|
values,
|
266
|
-
|
267
|
-
markersize=
|
279
|
+
lm,
|
280
|
+
markersize=mz,
|
268
281
|
color=color,
|
269
282
|
markerfacecolor=marker_fill,
|
270
283
|
markeredgewidth=0,
|
271
284
|
zorder=zo,
|
272
285
|
lw=lw,
|
273
286
|
)
|
274
|
-
|
275
|
-
|
276
|
-
num_values = len(values)
|
277
|
-
if num_values == 1:
|
287
|
+
if self.highlight in dates_str and self.type[i] == "markers":
|
288
|
+
# Highlight specific date (Motplotlib has no better option than to overwrite the marker)
|
278
289
|
self.ax.plot(
|
279
|
-
|
280
|
-
|
281
|
-
c=
|
282
|
-
marker=
|
283
|
-
|
290
|
+
highlight_date,
|
291
|
+
highlight_value,
|
292
|
+
c=self._nwc_style["strong_color"],
|
293
|
+
marker=lm,
|
294
|
+
markersize=mz,
|
295
|
+
markerfacecolor=marker_fill,
|
296
|
+
markeredgewidth=0,
|
297
|
+
zorder=zo + 1,
|
298
|
+
)
|
299
|
+
|
300
|
+
if self.type[i] == "markers":
|
301
|
+
# Join the dots with a line
|
302
|
+
self.ax.plot(
|
303
|
+
dates,
|
304
|
+
values,
|
305
|
+
color=color,
|
306
|
+
zorder=zo - 1,
|
307
|
+
lw=lw,
|
284
308
|
)
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
309
|
+
else:
|
310
|
+
# Add single, orphaned data points as markers
|
311
|
+
# None, 1, None, 1, 1, 1 => . ---
|
312
|
+
num_values = len(values)
|
313
|
+
if num_values == 1:
|
314
|
+
self.ax.plot(
|
315
|
+
dates[0],
|
316
|
+
values[0],
|
317
|
+
c=color,
|
318
|
+
marker=self.point_marker,
|
319
|
+
zorder=12,
|
320
|
+
)
|
321
|
+
elif num_values > 1:
|
322
|
+
for j, v in enumerate(values):
|
323
|
+
def nullish(val):
|
324
|
+
return val is None or np.isnan(val)
|
325
|
+
plot_me = False
|
326
|
+
if not nullish(v):
|
327
|
+
if j == 0 and nullish(values[1]):
|
328
|
+
plot_me = True
|
329
|
+
elif j == num_values - 1 and nullish(values[j - 1]):
|
330
|
+
plot_me = True
|
331
|
+
elif nullish(values[j - 1]) and nullish(values[j + 1]):
|
332
|
+
plot_me = True
|
333
|
+
if plot_me:
|
334
|
+
self.ax.plot(
|
335
|
+
dates[j], v,
|
336
|
+
c=color,
|
337
|
+
marker=self.point_marker,
|
338
|
+
zorder=12
|
339
|
+
)
|
304
340
|
|
305
341
|
if len(self.labels) > i and any([x[1] for x in serie]):
|
306
342
|
line.set_label(self.labels[i])
|
@@ -460,7 +496,7 @@ class SerialChart(Chart):
|
|
460
496
|
dir = "up"
|
461
497
|
else:
|
462
498
|
dir = "down"
|
463
|
-
if self.type[i]
|
499
|
+
if self.type[i] in ["line", "markers"]:
|
464
500
|
if len(highlight_values) > 1:
|
465
501
|
# When highlighting two values on the same point,
|
466
502
|
# put them in opposite direction
|
@@ -519,7 +555,7 @@ class SerialChart(Chart):
|
|
519
555
|
y=self.baseline,
|
520
556
|
linewidth=1,
|
521
557
|
color="#444444",
|
522
|
-
zorder=11,
|
558
|
+
zorder=11 if "bars" in self.type else 9,
|
523
559
|
linestyle="--" if self.baseline else "-",
|
524
560
|
)
|
525
561
|
if self.baseline_annotation:
|
@@ -531,7 +567,7 @@ class SerialChart(Chart):
|
|
531
567
|
xy,
|
532
568
|
direction="down" if first_val and first_val >= self.baseline else "up",
|
533
569
|
color=self._nwc_style["neutral_color"],
|
534
|
-
zorder=
|
570
|
+
zorder=12,
|
535
571
|
)
|
536
572
|
|
537
573
|
# Shade area between lines if there are exactly 2 series
|
@@ -1,9 +1,9 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: newsworthycharts
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.73.1
|
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.
|
6
|
+
Download-URL: https://github.com/jplusplus/newsworthycharts/archive/1.73.1.tar.gz
|
7
7
|
Author: Jens Finnäs and Leo Wallentin, J++ Stockholm
|
8
8
|
Author-email: stockholm@jplusplus.org
|
9
9
|
License: MIT
|
@@ -154,12 +154,14 @@ These settings are available for all chart types:
|
|
154
154
|
|
155
155
|
**SerialChart**
|
156
156
|
|
157
|
-
- type = 'line' # line|bars, or a list of types for each data serie
|
157
|
+
- type = 'line' # line|bars|markers, or a list of types for each data serie
|
158
158
|
- bar_width = 0.9 # percent of data point width
|
159
159
|
- allow_broken_y_axis = True|False # default depends on chart type
|
160
160
|
- baseline = 0 # The “zero” line. Useful for plotting deviations, e.g. temperatures above/below mean
|
161
161
|
- baseline_annotation = None # A label for the baseline
|
162
162
|
- line_width = None # To override style settings
|
163
|
+
- line_marker = "-"" # Matplotlib line marker type.
|
164
|
+
- line_marker_size = 3 # Matplotlib line marker size
|
163
165
|
- max_ticks = 10 # Maximum number of ticks on the x axis. *Only used with yearly|decennial data* (this is yet to be fixed)
|
164
166
|
- ticks = None # Custom ticks on the x axis, as a list of lists or tuples: `[(2013-01-01, "-13"), (2014-01-01, "-14"), (2015-01-01, "-15")]`
|
165
167
|
- ymin = None # Minimum value on y axis. If None, it will be calculated from data
|
@@ -271,6 +273,17 @@ Roadmap
|
|
271
273
|
Changelog
|
272
274
|
---------
|
273
275
|
|
276
|
+
- 1.73.1
|
277
|
+
|
278
|
+
- More leniant label parsing in ChoroplethMap
|
279
|
+
- Make max_ticks work in monthly time series charts.
|
280
|
+
|
281
|
+
- 1.73.0
|
282
|
+
|
283
|
+
- Add `type: "markers"` to serial charts. Uses a thin line with a marker at each data point as default.
|
284
|
+
- Make sure `baseline` goes behind lines in serial charts
|
285
|
+
- Make sure baseline annotation goes above lines in serial charts
|
286
|
+
|
274
287
|
- 1.72.1
|
275
288
|
|
276
289
|
- Better interval detection in SerialChart when years are all in different decades
|
@@ -1,15 +1,15 @@
|
|
1
|
-
newsworthycharts/__init__.py,sha256=
|
1
|
+
newsworthycharts/__init__.py,sha256=j6K16TGBlydhzNJ9jIftxz03lGGYkpR8E1DcEXHuZPk,1221
|
2
2
|
newsworthycharts/bubblemap.py,sha256=nkocWmpiFgfjEuJGAsthjY5X7Q56jXWsZHUGXw4PwgE,2587
|
3
3
|
newsworthycharts/categoricalchart.py,sha256=Vr-0yFms0hEVCeUa3vLt3FYBqpX4xLQ8YGPc4LGQN_A,18368
|
4
|
-
newsworthycharts/chart.py,sha256=
|
5
|
-
newsworthycharts/choroplethmap.py,sha256=
|
4
|
+
newsworthycharts/chart.py,sha256=ebPLEIFAlUrE7N7n0aIqkzayKHHguuF0rVkXDK3OpJU,35393
|
5
|
+
newsworthycharts/choroplethmap.py,sha256=dMJYmep3Qt3pC09N3-9dSUxUO6EI3QmLktQRJ-D0bdM,9404
|
6
6
|
newsworthycharts/datawrapper.py,sha256=RRkAVTpfP4updKxUIBaSmKuBi2RUVPaBRF8HDQhlGGA,11250
|
7
7
|
newsworthycharts/map.py,sha256=EGh96tU10y7Kgu1e83_VWQSeABdjP6V-0VM6VTHDxu4,6089
|
8
8
|
newsworthycharts/rangeplot.py,sha256=NE1W9TnmlpK6T3RvBJOU3nd73EXqkj17OY9i5zlw_cQ,8366
|
9
9
|
newsworthycharts/rankchart.py,sha256=vMzNMVOv1jae6wuHC_riAdb1lm9oPltO3TT3YQpc0Oc,9376
|
10
10
|
newsworthycharts/scatterplot.py,sha256=weHubdMsDGaBTXejg2TqBNPTQ1K-QBpZqJiyQ8EOEc4,5084
|
11
11
|
newsworthycharts/seasonalchart.py,sha256=rr55yqJUkaYDR9Ik98jes6574oY1U8t8LwoLE3gClW4,1967
|
12
|
-
newsworthycharts/serialchart.py,sha256=
|
12
|
+
newsworthycharts/serialchart.py,sha256=HQv3zAGBhlwbrH6HsslaM-c7VAvl9rg5CYCv1ok_Acw,31826
|
13
13
|
newsworthycharts/storage.py,sha256=myERhlpvXyExXxUByBq9eW1bWkCyfH9SwTZbsWSyy3Q,4301
|
14
14
|
newsworthycharts/stripechart.py,sha256=9B6PX2MyLuKNQ8W0OGdKbP0-U32kju0K_NHHwwz_J68,1547
|
15
15
|
newsworthycharts/custom/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -20,7 +20,7 @@ newsworthycharts/lib/colors.py,sha256=U04TDkvoMQkcldRFXfnwyLOTwq1SWW2se-Ad-DNcw9
|
|
20
20
|
newsworthycharts/lib/datalist.py,sha256=-LdGFE0SOvjLnIRZ6eoJoijDaG3SeUPNIDPBjbm5A2U,6433
|
21
21
|
newsworthycharts/lib/formatter.py,sha256=GNH43hE0bC17OgiV8LYH3YUrEhm7OJh9XzfSV4HVtHo,4838
|
22
22
|
newsworthycharts/lib/geography.py,sha256=K0_teFmuPJwXX7Py-amJB_1YY5_gL2kBYhz1LrRCyTg,584
|
23
|
-
newsworthycharts/lib/locator.py,sha256=
|
23
|
+
newsworthycharts/lib/locator.py,sha256=9iCow6GZDdKTqvY1HIkW60p5xFmBc1rMiPqh-kodT-s,3459
|
24
24
|
newsworthycharts/lib/mimetypes.py,sha256=bL9HtVWbn2Of39LcBt4u4yelkr4bGZiyebq3OfLnfFY,237
|
25
25
|
newsworthycharts/lib/utils.py,sha256=zk2hfbZluRcwwxa-N9LocP65HKiHmvgkBw9saAq1lgU,7403
|
26
26
|
newsworthycharts/maps/se-4.gpkg,sha256=oWw5j7FPVpI0ig67jNDim8qSn5SG8rcHp0014-uTKZM,290816
|
@@ -29,8 +29,8 @@ newsworthycharts/rc/newsworthy,sha256=yOIZvYS6PG1u19VMcdtfj9vbihKQsey5IprwqK59Kg
|
|
29
29
|
newsworthycharts/translations/datawrapper_regions.csv,sha256=fzZcQRX6RFMlNNP8mpgfYNdR3Y0QAlQxDXk8FXTaWWI,9214
|
30
30
|
newsworthycharts/translations/regions.py,sha256=Nv1McQjggD4S3JRu82rDMTG3pqUVR13E5-FBpSYbm98,239
|
31
31
|
newsworthycharts/translations/se_municipalities.csv,sha256=br_mm-IvzQtj_W55_ATREhJ97jWnCweBFlDAVY2EBxA,7098
|
32
|
-
newsworthycharts-1.
|
33
|
-
newsworthycharts-1.
|
34
|
-
newsworthycharts-1.
|
35
|
-
newsworthycharts-1.
|
36
|
-
newsworthycharts-1.
|
32
|
+
newsworthycharts-1.73.1.dist-info/LICENSE.txt,sha256=Sq6kGICrehbhC_FolNdXf0djKjTpv3YqjFCIYsxdQN4,1069
|
33
|
+
newsworthycharts-1.73.1.dist-info/METADATA,sha256=W7n5cgzx9DCRCvG8vbkqplsQw9dheDi67yAxUFbUYz8,34612
|
34
|
+
newsworthycharts-1.73.1.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91
|
35
|
+
newsworthycharts-1.73.1.dist-info/top_level.txt,sha256=dn_kzIj8UgUCMsh1PHdVEQJHVGSsN7Z8YJF-8xXa8n0,17
|
36
|
+
newsworthycharts-1.73.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|