newsworthycharts 1.58.0__tar.gz → 1.60.0__tar.gz
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-1.58.0 → newsworthycharts-1.60.0}/PKG-INFO +45 -6
- newsworthycharts-1.58.0/newsworthycharts.egg-info/PKG-INFO → newsworthycharts-1.60.0/README.rst +29 -17
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/newsworthycharts/__init__.py +1 -1
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/newsworthycharts/chart.py +18 -9
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/newsworthycharts/choroplethmap.py +74 -68
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/newsworthycharts/map.py +2 -2
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/newsworthycharts/serialchart.py +27 -26
- newsworthycharts-1.58.0/README.rst → newsworthycharts-1.60.0/newsworthycharts.egg-info/PKG-INFO +56 -4
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/newsworthycharts.egg-info/requires.txt +9 -8
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/setup.py +5 -4
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/test/test_main.py +6 -6
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/LICENSE.txt +0 -0
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/MANIFEST.in +0 -0
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/newsworthycharts/bubblemap.py +0 -0
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/newsworthycharts/categoricalchart.py +0 -0
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/newsworthycharts/custom/__init__.py +0 -0
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/newsworthycharts/custom/climate_cars.py +0 -0
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/newsworthycharts/datawrapper.py +0 -0
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/newsworthycharts/lib/__init__.py +0 -0
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/newsworthycharts/lib/color_fn.py +0 -0
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/newsworthycharts/lib/colors.py +0 -0
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/newsworthycharts/lib/datalist.py +0 -0
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/newsworthycharts/lib/formatter.py +0 -0
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/newsworthycharts/lib/geography.py +0 -0
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/newsworthycharts/lib/locator.py +0 -0
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/newsworthycharts/lib/mimetypes.py +0 -0
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/newsworthycharts/lib/utils.py +0 -0
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/newsworthycharts/maps/se-4.gpkg +0 -0
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/newsworthycharts/maps/se-7.gpkg +0 -0
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/newsworthycharts/rangeplot.py +0 -0
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/newsworthycharts/rc/newsworthy +0 -0
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/newsworthycharts/scatterplot.py +0 -0
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/newsworthycharts/seasonalchart.py +0 -0
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/newsworthycharts/storage.py +0 -0
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/newsworthycharts/stripechart.py +0 -0
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/newsworthycharts/translations/datawrapper_regions.csv +0 -0
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/newsworthycharts/translations/regions.py +0 -0
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/newsworthycharts/translations/se_municipalities.csv +0 -0
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/newsworthycharts.egg-info/SOURCES.txt +0 -0
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/newsworthycharts.egg-info/dependency_links.txt +0 -0
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/newsworthycharts.egg-info/not-zip-safe +0 -0
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/newsworthycharts.egg-info/top_level.txt +0 -0
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/setup.cfg +0 -0
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/test/test_categorical_chart.py +0 -0
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/test/test_choropleth_maps.py +0 -0
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/test/test_custom_climate_cars.py +0 -0
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/test/test_data_list.py +0 -0
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/test/test_datawrapper.py +0 -0
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/test/test_rangeplot.py +0 -0
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/test/test_scatterplot.py +0 -0
- {newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/test/test_serial_chart.py +0 -0
@@ -1,15 +1,29 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: newsworthycharts
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.60.0
|
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.60.0.tar.gz
|
7
7
|
Author: Jens Finnäs and Leo Wallentin, J++ Stockholm
|
8
8
|
Author-email: stockholm@jplusplus.org
|
9
9
|
License: MIT
|
10
10
|
Requires-Python: >=3.9
|
11
11
|
Description-Content-Type: text/x-rst
|
12
12
|
License-File: LICENSE.txt
|
13
|
+
Requires-Dist: boto3>=1.26
|
14
|
+
Requires-Dist: matplotlib==3.9.2
|
15
|
+
Requires-Dist: langcodes>=3.3
|
16
|
+
Requires-Dist: Babel<3,>=2.14.0
|
17
|
+
Requires-Dist: PyYAML>=3
|
18
|
+
Requires-Dist: adjustText==0.7.3
|
19
|
+
Requires-Dist: numpy>2
|
20
|
+
Requires-Dist: python-dateutil<3,>=2
|
21
|
+
Requires-Dist: Pillow==10.4.0
|
22
|
+
Requires-Dist: requests>=2.22
|
23
|
+
Requires-Dist: matplotlib-label-lines==0.5.1
|
24
|
+
Requires-Dist: geopandas>1
|
25
|
+
Requires-Dist: mapclassify==2.6.1
|
26
|
+
Requires-Dist: fiona>=1.0
|
13
27
|
|
14
28
|
This module contains methods for producing graphs and publishing them on Amazon S3, or in the location of your choice.
|
15
29
|
|
@@ -123,8 +137,8 @@ These settings are available for all chart types:
|
|
123
137
|
- yline = None # A horizontal line across the chart (Matplotlib: axhline)
|
124
138
|
- labels = [] # Optionally one label for each dataset
|
125
139
|
- annotations = [] # Manually added annotations
|
126
|
-
- interval = None # yearly
|
127
|
-
- units = 'number' # number
|
140
|
+
- interval = None # yearly, quarterly, monthly, weekly, daily
|
141
|
+
- units = 'number' # number, percent, degrees
|
128
142
|
- show_ticks = True # toggle category names, dates, etc
|
129
143
|
- subtitle = None
|
130
144
|
- note = None
|
@@ -132,6 +146,7 @@ These settings are available for all chart types:
|
|
132
146
|
- ylabel = None
|
133
147
|
- caption = None
|
134
148
|
- highlight = A position (typically a date, category label or index) to highlight. The semantics may differ somewhat between chart types.
|
149
|
+
- highlight_annotation = True # Print out values at highlighted point?
|
135
150
|
- decimals = None # None means automatically chose the best number
|
136
151
|
- logo = None # Path to image that will be embedded in the caption area. Can also be set though a style property
|
137
152
|
- color_fn = None # Custom coloring function
|
@@ -222,13 +237,37 @@ To deploy a new version to [PyPi](https://pypi.org/project/newsworthycharts):
|
|
222
237
|
|
223
238
|
Roadmap
|
224
239
|
-------
|
225
|
-
|
226
|
-
-
|
240
|
+
|
241
|
+
- Get rid of custom settings-hack
|
242
|
+
- Remove custom charts (add missing api interfaces to Chart class instead)
|
243
|
+
- Remove DataWrapper class (out-of-scope)
|
227
244
|
- Custom month locator with equal-width month bars
|
245
|
+
- Add color-ramp choropleth maps, as an alternative to binning
|
228
246
|
|
229
247
|
Changelog
|
230
248
|
---------
|
231
249
|
|
250
|
+
- 1.60.0
|
251
|
+
|
252
|
+
- [BREAKING] The default number of bins in maps is now 5, not 9
|
253
|
+
- [BREAKING] Default color ramp for choropleth maps is now `YlGn`
|
254
|
+
- GeoPandas 1.x
|
255
|
+
- numpy 2.x
|
256
|
+
- matplotlib==3.9.2
|
257
|
+
- Pillow==10.4.0
|
258
|
+
- Improved nan handling in labelling continuous choropleth maps
|
259
|
+
- Replace deprecated `.unary_union` with `.union_all()`
|
260
|
+
- Choropleth map legends now print spans for binned data
|
261
|
+
- Use Matplotlib's legend for choropleth maps, to have the same style as other charts, and for much improved flexibility
|
262
|
+
- Inset maps now (finally!) work with continuous data
|
263
|
+
- Better error handling in categorical maps
|
264
|
+
- Cast all categorical values to strings in categorical maps
|
265
|
+
- Replace deprecated imghdr with puremagic in tests
|
266
|
+
|
267
|
+
- 1.59.0
|
268
|
+
|
269
|
+
- Added `.highlight_annotation` to enable turning off the textual annotation on the highlighted point
|
270
|
+
|
232
271
|
- 1.58.0
|
233
272
|
|
234
273
|
- Matplotlib==3.9
|
newsworthycharts-1.58.0/newsworthycharts.egg-info/PKG-INFO → newsworthycharts-1.60.0/README.rst
RENAMED
@@ -1,16 +1,3 @@
|
|
1
|
-
Metadata-Version: 2.1
|
2
|
-
Name: newsworthycharts
|
3
|
-
Version: 1.58.0
|
4
|
-
Summary: Matplotlib wrapper to create charts and publish them on Amazon S3
|
5
|
-
Home-page: https://github.com/jplusplus/newsworthycharts
|
6
|
-
Download-URL: https://github.com/jplusplus/newsworthycharts/archive/1.58.0.tar.gz
|
7
|
-
Author: Jens Finnäs and Leo Wallentin, J++ Stockholm
|
8
|
-
Author-email: stockholm@jplusplus.org
|
9
|
-
License: MIT
|
10
|
-
Requires-Python: >=3.9
|
11
|
-
Description-Content-Type: text/x-rst
|
12
|
-
License-File: LICENSE.txt
|
13
|
-
|
14
1
|
This module contains methods for producing graphs and publishing them on Amazon S3, or in the location of your choice.
|
15
2
|
|
16
3
|
It is written and maintained for `Newsworthy <https://www.newsworthy.se/en/>`_, but could possibly come in handy for other people as well.
|
@@ -123,8 +110,8 @@ These settings are available for all chart types:
|
|
123
110
|
- yline = None # A horizontal line across the chart (Matplotlib: axhline)
|
124
111
|
- labels = [] # Optionally one label for each dataset
|
125
112
|
- annotations = [] # Manually added annotations
|
126
|
-
- interval = None # yearly
|
127
|
-
- units = 'number' # number
|
113
|
+
- interval = None # yearly, quarterly, monthly, weekly, daily
|
114
|
+
- units = 'number' # number, percent, degrees
|
128
115
|
- show_ticks = True # toggle category names, dates, etc
|
129
116
|
- subtitle = None
|
130
117
|
- note = None
|
@@ -132,6 +119,7 @@ These settings are available for all chart types:
|
|
132
119
|
- ylabel = None
|
133
120
|
- caption = None
|
134
121
|
- highlight = A position (typically a date, category label or index) to highlight. The semantics may differ somewhat between chart types.
|
122
|
+
- highlight_annotation = True # Print out values at highlighted point?
|
135
123
|
- decimals = None # None means automatically chose the best number
|
136
124
|
- logo = None # Path to image that will be embedded in the caption area. Can also be set though a style property
|
137
125
|
- color_fn = None # Custom coloring function
|
@@ -222,13 +210,37 @@ To deploy a new version to [PyPi](https://pypi.org/project/newsworthycharts):
|
|
222
210
|
|
223
211
|
Roadmap
|
224
212
|
-------
|
225
|
-
|
226
|
-
-
|
213
|
+
|
214
|
+
- Get rid of custom settings-hack
|
215
|
+
- Remove custom charts (add missing api interfaces to Chart class instead)
|
216
|
+
- Remove DataWrapper class (out-of-scope)
|
227
217
|
- Custom month locator with equal-width month bars
|
218
|
+
- Add color-ramp choropleth maps, as an alternative to binning
|
228
219
|
|
229
220
|
Changelog
|
230
221
|
---------
|
231
222
|
|
223
|
+
- 1.60.0
|
224
|
+
|
225
|
+
- [BREAKING] The default number of bins in maps is now 5, not 9
|
226
|
+
- [BREAKING] Default color ramp for choropleth maps is now `YlGn`
|
227
|
+
- GeoPandas 1.x
|
228
|
+
- numpy 2.x
|
229
|
+
- matplotlib==3.9.2
|
230
|
+
- Pillow==10.4.0
|
231
|
+
- Improved nan handling in labelling continuous choropleth maps
|
232
|
+
- Replace deprecated `.unary_union` with `.union_all()`
|
233
|
+
- Choropleth map legends now print spans for binned data
|
234
|
+
- Use Matplotlib's legend for choropleth maps, to have the same style as other charts, and for much improved flexibility
|
235
|
+
- Inset maps now (finally!) work with continuous data
|
236
|
+
- Better error handling in categorical maps
|
237
|
+
- Cast all categorical values to strings in categorical maps
|
238
|
+
- Replace deprecated imghdr with puremagic in tests
|
239
|
+
|
240
|
+
- 1.59.0
|
241
|
+
|
242
|
+
- Added `.highlight_annotation` to enable turning off the textual annotation on the highlighted point
|
243
|
+
|
232
244
|
- 1.58.0
|
233
245
|
|
234
246
|
- Matplotlib==3.9
|
@@ -61,6 +61,7 @@ class Chart(object):
|
|
61
61
|
self.ylabel = None
|
62
62
|
self.caption = None
|
63
63
|
self.highlight = None
|
64
|
+
self.highlight_annotation = True
|
64
65
|
self.decimals = None
|
65
66
|
self.yline = None
|
66
67
|
self.type = None
|
@@ -259,10 +260,15 @@ class Chart(object):
|
|
259
260
|
hextent = (0, self._w)
|
260
261
|
self._set_size(hextent[1] - hextent[0])
|
261
262
|
x1 = hextent[0] / self._w
|
262
|
-
text = self._fig.text(
|
263
|
-
|
264
|
-
|
265
|
-
|
263
|
+
text = self._fig.text(
|
264
|
+
x1,
|
265
|
+
0.01,
|
266
|
+
caption,
|
267
|
+
in_layout=True,
|
268
|
+
color=self._nwc_style["neutral_color"],
|
269
|
+
wrap=True,
|
270
|
+
fontsize=self._nwc_style["caption.fontsize"],
|
271
|
+
)
|
266
272
|
self._fig.canvas.draw()
|
267
273
|
wrapped_text = text._get_wrapped_text()
|
268
274
|
text.set_text(wrapped_text)
|
@@ -272,11 +278,14 @@ class Chart(object):
|
|
272
278
|
|
273
279
|
def _add_title(self, title_text):
|
274
280
|
"""Add a title."""
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
281
|
+
text = self._fig.suptitle(
|
282
|
+
title_text, wrap=True,
|
283
|
+
x=0,
|
284
|
+
y=0.985, # default: 0.98
|
285
|
+
horizontalalignment="left",
|
286
|
+
multialignment="left",
|
287
|
+
fontproperties=self._title_font,
|
288
|
+
)
|
280
289
|
|
281
290
|
self._title_elem = text
|
282
291
|
|
@@ -6,6 +6,7 @@ import geopandas as gpd
|
|
6
6
|
import numpy as np
|
7
7
|
import pandas as pd
|
8
8
|
import mapclassify
|
9
|
+
import matplotlib.patches as mpatches
|
9
10
|
|
10
11
|
|
11
12
|
class ChoroplethMap(Map):
|
@@ -29,15 +30,27 @@ class ChoroplethMap(Map):
|
|
29
30
|
|
30
31
|
df = self._prepare_map_data()
|
31
32
|
|
32
|
-
|
33
|
-
|
34
|
-
#
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
33
|
+
args = {
|
34
|
+
"categorical": True,
|
35
|
+
"legend": True, # bug in geopandas, fixed in master but not released
|
36
|
+
"legend_kwds": {
|
37
|
+
"loc": "upper left",
|
38
|
+
"bbox_to_anchor": (1.05, 1.0),
|
39
|
+
},
|
40
|
+
"edgecolor": "white",
|
41
|
+
"linewidth": 0.2,
|
42
|
+
"missing_kwds": {
|
43
|
+
"color": "gainsboro",
|
44
|
+
},
|
45
|
+
}
|
46
|
+
# This should be adjusted per basemap
|
47
|
+
label_kwargs = {
|
48
|
+
"bbox_to_anchor": (0.92, 0.95),
|
49
|
+
"loc": "upper left",
|
50
|
+
}
|
51
|
+
|
52
|
+
patches = [] # for legend
|
53
|
+
if not self.categorical:
|
41
54
|
# mapclassify doesn't work well with nan values,
|
42
55
|
# but we to keep them for plotting, hence
|
43
56
|
# this hack with cutting out nan's and re-pasting them below
|
@@ -58,44 +71,57 @@ class ChoroplethMap(Map):
|
|
58
71
|
_dict = _has_value[["id", "cats"]].set_index("id").to_dict()
|
59
72
|
df["data"] = df["id"].map(_dict["cats"])
|
60
73
|
|
61
|
-
|
62
|
-
"
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
"
|
70
|
-
"
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
74
|
+
# args["column"] = "data"
|
75
|
+
# args["cmap"] = self.color_ramp
|
76
|
+
# We can not provide vmin/vmax to geopandas, so we need to
|
77
|
+
# normalize the data ourselves, otherwise the inset maps will be off
|
78
|
+
import matplotlib.cm as cm
|
79
|
+
import matplotlib as mpl
|
80
|
+
norm = mpl.colors.Normalize(vmin=df["data"].min(), vmax=df["data"].max())
|
81
|
+
mapper = cm.ScalarMappable(norm=norm, cmap=self.color_ramp)
|
82
|
+
df["color"] = df["data"].apply(lambda x: mapper.to_rgba(x) if not np.isnan(x) else "gainsboro")
|
83
|
+
df["color"] = df["color"].fillna("gainsboro")
|
84
|
+
args["color"] = df["color"]
|
85
|
+
|
86
|
+
# Add labels legend (manually, Geopandas is too crude as of now)
|
87
|
+
fmt = self._get_value_axis_formatter()
|
88
|
+
for idx, cat in enumerate(binning.bins):
|
89
|
+
# cat is the upper limit of each category
|
90
|
+
if binning.counts[idx] == 1:
|
91
|
+
txt_val = fmt(cat)
|
92
|
+
elif idx == 0:
|
93
|
+
txt_val = f"– {fmt(cat)}"
|
94
|
+
else:
|
95
|
+
txt_val = f"{fmt(binning.bins[idx - 1])} – {fmt(cat)}"
|
96
|
+
patches.append(mpatches.Patch(color=mapper.to_rgba(cat), label=txt_val))
|
97
|
+
|
98
|
+
elif self.categorical:
|
99
|
+
# We'll categorize manually further down the line,
|
100
|
+
# to easier implement custom coloring
|
101
|
+
# df["data"] = pd.Categorical(
|
102
|
+
# df["data"],
|
103
|
+
# ordered=True,
|
104
|
+
# )
|
105
|
+
|
106
|
+
cat = df[~df["data"].isna()]["data"].astype(str).unique()
|
84
107
|
args["categories"] = cat
|
85
108
|
if self.colors:
|
86
109
|
color_map = self.colors
|
87
110
|
else:
|
88
111
|
color_map = {}
|
112
|
+
if len(cat) > len(self._nwc_style["qualitative_colors"]):
|
113
|
+
raise ValueError(
|
114
|
+
"Too many categories for the available colors in the current style. " + # noqa:W504
|
115
|
+
"Add a custom color map, or use a style with more categorical colors!"
|
116
|
+
)
|
89
117
|
for idx, cat in enumerate(cat):
|
90
118
|
color_map[cat] = self._nwc_style["qualitative_colors"][idx]
|
91
|
-
df["color"] = df["data"].map(color_map)
|
119
|
+
df["color"] = df["data"].astype(str).map(color_map)
|
92
120
|
df["color"] = df["color"].fillna("gainsboro")
|
93
121
|
args["color"] = df["color"]
|
94
122
|
|
95
123
|
# Geopandas does not handle legend if color keyword is used
|
96
124
|
# We need to add it ourselves
|
97
|
-
import matplotlib.patches as mpatches
|
98
|
-
patches = []
|
99
125
|
for label, color in color_map.items():
|
100
126
|
# A bit of an hack:
|
101
127
|
# Check if this corresponds to one of our predefined
|
@@ -104,44 +130,20 @@ class ChoroplethMap(Map):
|
|
104
130
|
color = self._nwc_style[f"{color}_color"]
|
105
131
|
patch = mpatches.Patch(color=color, label=label)
|
106
132
|
patches.append(patch)
|
107
|
-
|
108
|
-
|
109
|
-
**label_kwargs
|
110
|
-
)
|
133
|
+
if self.missing_label:
|
134
|
+
patches.append(mpatches.Patch(color="gainsboro", label=self.missing_label))
|
111
135
|
|
112
|
-
|
136
|
+
df.plot(ax=self.ax, **args)
|
113
137
|
# Add outer edge
|
114
|
-
gpd.GeoSeries(df.
|
138
|
+
gpd.GeoSeries(df.union_all()).plot(
|
115
139
|
ax=self.ax,
|
116
140
|
edgecolor="lightgrey",
|
117
141
|
linewidth=0.2,
|
118
142
|
facecolor="none",
|
119
143
|
color="none",
|
120
144
|
)
|
121
|
-
self.ax.axis("off")
|
122
|
-
|
123
|
-
# Format numbers in legend
|
124
|
-
if not self.categorical:
|
125
|
-
leg = fig.get_legend()
|
126
|
-
fmt = self._get_value_axis_formatter()
|
127
|
-
remove_last = False
|
128
|
-
for lbl in leg.get_texts():
|
129
|
-
val = lbl.get_text()
|
130
|
-
if val == "NaN": # as returned by mapclassify
|
131
|
-
if self.missing_label is not None:
|
132
|
-
val = self.missing_label
|
133
|
-
else:
|
134
|
-
remove_last = True
|
135
|
-
val = ""
|
136
|
-
else:
|
137
|
-
val = float(val)
|
138
|
-
val = fmt(val)
|
139
|
-
lbl.set_text(val)
|
140
|
-
if remove_last:
|
141
|
-
del leg.legend_handles[-1]
|
142
|
-
texts = [lbl.get_text() for lbl in leg.get_texts()]
|
143
|
-
fig.legend(handles=leg.legend_handles, labels=texts, **label_kwargs)
|
144
145
|
|
146
|
+
self.ax.axis("off")
|
145
147
|
for inset in self.insets:
|
146
148
|
if "prefix" in inset:
|
147
149
|
_df = df[df["id"].str.startswith(inset["prefix"])].copy()
|
@@ -150,12 +152,11 @@ class ChoroplethMap(Map):
|
|
150
152
|
if _df["data"].isnull().all():
|
151
153
|
# Skip if no data
|
152
154
|
continue
|
153
|
-
|
154
|
-
|
155
|
-
args["color"] = _df["color"]
|
155
|
+
|
156
|
+
args["color"] = _df["color"]
|
156
157
|
args["legend"] = False
|
157
158
|
axin = self.ax.inset_axes(inset["axes"])
|
158
|
-
gpd.GeoSeries(_df.
|
159
|
+
gpd.GeoSeries(_df.union_all()).plot(
|
159
160
|
ax=axin,
|
160
161
|
edgecolor="lightgrey",
|
161
162
|
linewidth=0.3,
|
@@ -169,3 +170,8 @@ class ChoroplethMap(Map):
|
|
169
170
|
r, (a, b, c, d) = self.ax.indicate_inset_zoom(axin)
|
170
171
|
for _line in [a, b, c, d]:
|
171
172
|
_line.set_visible(False)
|
173
|
+
|
174
|
+
self.ax.legend(
|
175
|
+
handles=patches,
|
176
|
+
**label_kwargs,
|
177
|
+
)
|
@@ -87,10 +87,10 @@ class Map(Chart):
|
|
87
87
|
|
88
88
|
def __init__(self, *args, **kwargs):
|
89
89
|
super(Map, self).__init__(*args, **kwargs)
|
90
|
-
self.bins = kwargs.get("bins",
|
90
|
+
self.bins = kwargs.get("bins", 5)
|
91
91
|
self.binning_method = kwargs.get("binning_method", "natural_breaks")
|
92
92
|
self.colors = kwargs.get("colors", None)
|
93
|
-
self.color_ramp = kwargs.get("color_ramp", "
|
93
|
+
self.color_ramp = kwargs.get("color_ramp", "YlGn") # YlOrRd
|
94
94
|
self.categorical = kwargs.get("categorical", False)
|
95
95
|
self.base_map = None
|
96
96
|
self.missing_label = None
|
@@ -409,35 +409,36 @@ class SerialChart(Chart):
|
|
409
409
|
self.ax.legend(handles=patches)
|
410
410
|
|
411
411
|
# Annotate highlighted points/bars
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
if
|
417
|
-
|
418
|
-
else:
|
419
|
-
dir = "down"
|
420
|
-
if self.type[i] == "line":
|
421
|
-
if len(highlight_values) > 1:
|
422
|
-
# When highlighting two values on the same point,
|
423
|
-
# put them in opposite direction
|
424
|
-
if hv == max(highlight_values):
|
412
|
+
if self.highlight_annotation:
|
413
|
+
for hv in highlight_values:
|
414
|
+
value_label = a_formatter(hv)
|
415
|
+
xy = (highlight_date, hv)
|
416
|
+
if self.type[i] == "bars":
|
417
|
+
if hv >= self.baseline:
|
425
418
|
dir = "up"
|
426
|
-
elif hv == min(highlight_values):
|
427
|
-
dir = "down"
|
428
419
|
else:
|
429
|
-
dir = "
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
420
|
+
dir = "down"
|
421
|
+
if self.type[i] == "line":
|
422
|
+
if len(highlight_values) > 1:
|
423
|
+
# When highlighting two values on the same point,
|
424
|
+
# put them in opposite direction
|
425
|
+
if hv == max(highlight_values):
|
426
|
+
dir = "up"
|
427
|
+
elif hv == min(highlight_values):
|
428
|
+
dir = "down"
|
429
|
+
else:
|
430
|
+
dir = "left" # To the right we have diff annotation
|
435
431
|
else:
|
436
|
-
#
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
432
|
+
# Otherwise, use what works best with the line shape
|
433
|
+
if highlight_date in dates:
|
434
|
+
i = dates.index(highlight_date)
|
435
|
+
dir = self._get_annotation_direction(i, values)
|
436
|
+
else:
|
437
|
+
# This highlight is probably out of range for this dataset
|
438
|
+
# Could happen if we have two or more lines,
|
439
|
+
# with different start and end points.
|
440
|
+
continue
|
441
|
+
self._annotate_point(value_label, xy, direction=dir)
|
441
442
|
|
442
443
|
# Add background highlights
|
443
444
|
for (x0, x1) in self.highlighted_x_ranges:
|
newsworthycharts-1.58.0/README.rst → newsworthycharts-1.60.0/newsworthycharts.egg-info/PKG-INFO
RENAMED
@@ -1,3 +1,30 @@
|
|
1
|
+
Metadata-Version: 2.1
|
2
|
+
Name: newsworthycharts
|
3
|
+
Version: 1.60.0
|
4
|
+
Summary: Matplotlib wrapper to create charts and publish them on Amazon S3
|
5
|
+
Home-page: https://github.com/jplusplus/newsworthycharts
|
6
|
+
Download-URL: https://github.com/jplusplus/newsworthycharts/archive/1.60.0.tar.gz
|
7
|
+
Author: Jens Finnäs and Leo Wallentin, J++ Stockholm
|
8
|
+
Author-email: stockholm@jplusplus.org
|
9
|
+
License: MIT
|
10
|
+
Requires-Python: >=3.9
|
11
|
+
Description-Content-Type: text/x-rst
|
12
|
+
License-File: LICENSE.txt
|
13
|
+
Requires-Dist: boto3>=1.26
|
14
|
+
Requires-Dist: matplotlib==3.9.2
|
15
|
+
Requires-Dist: langcodes>=3.3
|
16
|
+
Requires-Dist: Babel<3,>=2.14.0
|
17
|
+
Requires-Dist: PyYAML>=3
|
18
|
+
Requires-Dist: adjustText==0.7.3
|
19
|
+
Requires-Dist: numpy>2
|
20
|
+
Requires-Dist: python-dateutil<3,>=2
|
21
|
+
Requires-Dist: Pillow==10.4.0
|
22
|
+
Requires-Dist: requests>=2.22
|
23
|
+
Requires-Dist: matplotlib-label-lines==0.5.1
|
24
|
+
Requires-Dist: geopandas>1
|
25
|
+
Requires-Dist: mapclassify==2.6.1
|
26
|
+
Requires-Dist: fiona>=1.0
|
27
|
+
|
1
28
|
This module contains methods for producing graphs and publishing them on Amazon S3, or in the location of your choice.
|
2
29
|
|
3
30
|
It is written and maintained for `Newsworthy <https://www.newsworthy.se/en/>`_, but could possibly come in handy for other people as well.
|
@@ -110,8 +137,8 @@ These settings are available for all chart types:
|
|
110
137
|
- yline = None # A horizontal line across the chart (Matplotlib: axhline)
|
111
138
|
- labels = [] # Optionally one label for each dataset
|
112
139
|
- annotations = [] # Manually added annotations
|
113
|
-
- interval = None # yearly
|
114
|
-
- units = 'number' # number
|
140
|
+
- interval = None # yearly, quarterly, monthly, weekly, daily
|
141
|
+
- units = 'number' # number, percent, degrees
|
115
142
|
- show_ticks = True # toggle category names, dates, etc
|
116
143
|
- subtitle = None
|
117
144
|
- note = None
|
@@ -119,6 +146,7 @@ These settings are available for all chart types:
|
|
119
146
|
- ylabel = None
|
120
147
|
- caption = None
|
121
148
|
- highlight = A position (typically a date, category label or index) to highlight. The semantics may differ somewhat between chart types.
|
149
|
+
- highlight_annotation = True # Print out values at highlighted point?
|
122
150
|
- decimals = None # None means automatically chose the best number
|
123
151
|
- logo = None # Path to image that will be embedded in the caption area. Can also be set though a style property
|
124
152
|
- color_fn = None # Custom coloring function
|
@@ -209,13 +237,37 @@ To deploy a new version to [PyPi](https://pypi.org/project/newsworthycharts):
|
|
209
237
|
|
210
238
|
Roadmap
|
211
239
|
-------
|
212
|
-
|
213
|
-
-
|
240
|
+
|
241
|
+
- Get rid of custom settings-hack
|
242
|
+
- Remove custom charts (add missing api interfaces to Chart class instead)
|
243
|
+
- Remove DataWrapper class (out-of-scope)
|
214
244
|
- Custom month locator with equal-width month bars
|
245
|
+
- Add color-ramp choropleth maps, as an alternative to binning
|
215
246
|
|
216
247
|
Changelog
|
217
248
|
---------
|
218
249
|
|
250
|
+
- 1.60.0
|
251
|
+
|
252
|
+
- [BREAKING] The default number of bins in maps is now 5, not 9
|
253
|
+
- [BREAKING] Default color ramp for choropleth maps is now `YlGn`
|
254
|
+
- GeoPandas 1.x
|
255
|
+
- numpy 2.x
|
256
|
+
- matplotlib==3.9.2
|
257
|
+
- Pillow==10.4.0
|
258
|
+
- Improved nan handling in labelling continuous choropleth maps
|
259
|
+
- Replace deprecated `.unary_union` with `.union_all()`
|
260
|
+
- Choropleth map legends now print spans for binned data
|
261
|
+
- Use Matplotlib's legend for choropleth maps, to have the same style as other charts, and for much improved flexibility
|
262
|
+
- Inset maps now (finally!) work with continuous data
|
263
|
+
- Better error handling in categorical maps
|
264
|
+
- Cast all categorical values to strings in categorical maps
|
265
|
+
- Replace deprecated imghdr with puremagic in tests
|
266
|
+
|
267
|
+
- 1.59.0
|
268
|
+
|
269
|
+
- Added `.highlight_annotation` to enable turning off the textual annotation on the highlighted point
|
270
|
+
|
219
271
|
- 1.58.0
|
220
272
|
|
221
273
|
- Matplotlib==3.9
|
@@ -1,13 +1,14 @@
|
|
1
|
+
boto3>=1.26
|
2
|
+
matplotlib==3.9.2
|
3
|
+
langcodes>=3.3
|
1
4
|
Babel<3,>=2.14.0
|
2
|
-
Pillow==10.3.0
|
3
5
|
PyYAML>=3
|
4
6
|
adjustText==0.7.3
|
5
|
-
|
6
|
-
geopandas==0.14.4
|
7
|
-
langcodes>=3.3
|
8
|
-
mapclassify==2.6.1
|
9
|
-
matplotlib-label-lines==0.5.1
|
10
|
-
matplotlib==3.9.0
|
11
|
-
numpy<2,>=1.21.0
|
7
|
+
numpy>2
|
12
8
|
python-dateutil<3,>=2
|
9
|
+
Pillow==10.4.0
|
13
10
|
requests>=2.22
|
11
|
+
matplotlib-label-lines==0.5.1
|
12
|
+
geopandas>1
|
13
|
+
mapclassify==2.6.1
|
14
|
+
fiona>=1.0
|
@@ -25,18 +25,19 @@ setup(
|
|
25
25
|
python_requires='>=3.9',
|
26
26
|
install_requires=[
|
27
27
|
"boto3>=1.26",
|
28
|
-
"matplotlib==3.9.
|
28
|
+
"matplotlib==3.9.2",
|
29
29
|
"langcodes>=3.3",
|
30
30
|
"Babel>=2.14.0,<3",
|
31
31
|
"PyYAML>=3",
|
32
32
|
"adjustText==0.7.3",
|
33
|
-
"numpy
|
33
|
+
"numpy>2",
|
34
34
|
"python-dateutil>=2,<3",
|
35
|
-
"Pillow==10.
|
35
|
+
"Pillow==10.4.0",
|
36
36
|
"requests>=2.22",
|
37
37
|
"matplotlib-label-lines==0.5.1",
|
38
|
-
"geopandas
|
38
|
+
"geopandas>1",
|
39
39
|
"mapclassify==2.6.1",
|
40
|
+
"fiona>=1.0",
|
40
41
|
],
|
41
42
|
setup_requires=["flake8"],
|
42
43
|
include_package_data=True,
|
@@ -1,12 +1,12 @@
|
|
1
1
|
""" py.test tests for Newsworthycharts
|
2
2
|
"""
|
3
3
|
import pytest
|
4
|
+
import puremagic
|
5
|
+
import numpy as np
|
4
6
|
from newsworthycharts import Chart, SerialChart, CategoricalChart, CHART_ENGINES
|
5
7
|
from newsworthycharts.storage import DictStorage, LocalStorage
|
6
|
-
from imghdr import what
|
7
8
|
from PIL import Image
|
8
9
|
from hashlib import md5
|
9
|
-
import numpy as np
|
10
10
|
|
11
11
|
# store test charts to this folder for visual verfication
|
12
12
|
OUTPUT_DIR = "test/rendered_charts"
|
@@ -20,7 +20,7 @@ def test_generating_png():
|
|
20
20
|
c.render("test", "png")
|
21
21
|
|
22
22
|
assert "png" in container
|
23
|
-
assert
|
23
|
+
assert puremagic.from_stream(container["png"]) == ".png"
|
24
24
|
|
25
25
|
|
26
26
|
def test_generating_webp():
|
@@ -30,7 +30,7 @@ def test_generating_webp():
|
|
30
30
|
c.render("test", "webp")
|
31
31
|
|
32
32
|
assert "webp" in container
|
33
|
-
assert
|
33
|
+
assert puremagic.from_stream(container["webp"]) == ".webp"
|
34
34
|
im = Image.open(container["webp"])
|
35
35
|
assert im.size == (800, 600)
|
36
36
|
|
@@ -43,7 +43,7 @@ def test_dynamic_init():
|
|
43
43
|
c.render("test", "png")
|
44
44
|
|
45
45
|
assert "png" in container
|
46
|
-
assert
|
46
|
+
assert puremagic.from_stream(container["png"]) == ".png"
|
47
47
|
|
48
48
|
|
49
49
|
def test_factory_function():
|
@@ -56,7 +56,7 @@ def test_factory_function():
|
|
56
56
|
c.render("test", "png")
|
57
57
|
|
58
58
|
assert "png" in container
|
59
|
-
assert
|
59
|
+
assert puremagic.from_stream(container["png"]) == ".png"
|
60
60
|
|
61
61
|
# Make sure it works in a child class
|
62
62
|
c = SerialChart.init_from({
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/newsworthycharts/translations/regions.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
{newsworthycharts-1.58.0 → newsworthycharts-1.60.0}/newsworthycharts.egg-info/dependency_links.txt
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|