newsworthycharts 1.59.0__tar.gz → 1.60.1__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.
Files changed (51) hide show
  1. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/PKG-INFO +44 -6
  2. newsworthycharts-1.59.0/newsworthycharts.egg-info/PKG-INFO → newsworthycharts-1.60.1/README.rst +28 -17
  3. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/newsworthycharts/__init__.py +1 -1
  4. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/newsworthycharts/choroplethmap.py +74 -68
  5. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/newsworthycharts/map.py +3 -9
  6. newsworthycharts-1.59.0/README.rst → newsworthycharts-1.60.1/newsworthycharts.egg-info/PKG-INFO +55 -4
  7. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/newsworthycharts.egg-info/requires.txt +9 -8
  8. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/setup.py +5 -4
  9. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/test/test_main.py +6 -6
  10. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/LICENSE.txt +0 -0
  11. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/MANIFEST.in +0 -0
  12. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/newsworthycharts/bubblemap.py +0 -0
  13. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/newsworthycharts/categoricalchart.py +0 -0
  14. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/newsworthycharts/chart.py +0 -0
  15. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/newsworthycharts/custom/__init__.py +0 -0
  16. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/newsworthycharts/custom/climate_cars.py +0 -0
  17. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/newsworthycharts/datawrapper.py +0 -0
  18. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/newsworthycharts/lib/__init__.py +0 -0
  19. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/newsworthycharts/lib/color_fn.py +0 -0
  20. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/newsworthycharts/lib/colors.py +0 -0
  21. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/newsworthycharts/lib/datalist.py +0 -0
  22. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/newsworthycharts/lib/formatter.py +0 -0
  23. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/newsworthycharts/lib/geography.py +0 -0
  24. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/newsworthycharts/lib/locator.py +0 -0
  25. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/newsworthycharts/lib/mimetypes.py +0 -0
  26. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/newsworthycharts/lib/utils.py +0 -0
  27. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/newsworthycharts/maps/se-4.gpkg +0 -0
  28. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/newsworthycharts/maps/se-7.gpkg +0 -0
  29. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/newsworthycharts/rangeplot.py +0 -0
  30. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/newsworthycharts/rc/newsworthy +0 -0
  31. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/newsworthycharts/scatterplot.py +0 -0
  32. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/newsworthycharts/seasonalchart.py +0 -0
  33. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/newsworthycharts/serialchart.py +0 -0
  34. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/newsworthycharts/storage.py +0 -0
  35. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/newsworthycharts/stripechart.py +0 -0
  36. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/newsworthycharts/translations/datawrapper_regions.csv +0 -0
  37. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/newsworthycharts/translations/regions.py +0 -0
  38. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/newsworthycharts/translations/se_municipalities.csv +0 -0
  39. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/newsworthycharts.egg-info/SOURCES.txt +0 -0
  40. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/newsworthycharts.egg-info/dependency_links.txt +0 -0
  41. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/newsworthycharts.egg-info/not-zip-safe +0 -0
  42. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/newsworthycharts.egg-info/top_level.txt +0 -0
  43. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/setup.cfg +0 -0
  44. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/test/test_categorical_chart.py +0 -0
  45. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/test/test_choropleth_maps.py +0 -0
  46. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/test/test_custom_climate_cars.py +0 -0
  47. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/test/test_data_list.py +0 -0
  48. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/test/test_datawrapper.py +0 -0
  49. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/test/test_rangeplot.py +0 -0
  50. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/test/test_scatterplot.py +0 -0
  51. {newsworthycharts-1.59.0 → newsworthycharts-1.60.1}/test/test_serial_chart.py +0 -0
@@ -1,15 +1,29 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: newsworthycharts
3
- Version: 1.59.0
3
+ Version: 1.60.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.59.0.tar.gz
6
+ Download-URL: https://github.com/jplusplus/newsworthycharts/archive/1.60.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
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.10
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|quarterly|monthly|weekly|daily
127
- - units = 'number' # number|percent|degrees
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
@@ -223,13 +237,37 @@ To deploy a new version to [PyPi](https://pypi.org/project/newsworthycharts):
223
237
 
224
238
  Roadmap
225
239
  -------
226
- - Adding more base maps
227
- - Getting rid of custom settings-hack
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)
228
244
  - Custom month locator with equal-width month bars
245
+ - Add color-ramp choropleth maps, as an alternative to binning
229
246
 
230
247
  Changelog
231
248
  ---------
232
249
 
250
+ - 1.60.1
251
+
252
+ - Don't require fiona. Geopandas now support Pyogrio
253
+
254
+ - 1.60.0
255
+
256
+ - [BREAKING] The default number of bins in maps is now 5, not 9
257
+ - [BREAKING] Default color ramp for choropleth maps is now `YlGn`
258
+ - GeoPandas 1.x
259
+ - numpy 2.x
260
+ - matplotlib==3.9.2
261
+ - Pillow==10.4.0
262
+ - Improved nan handling in labelling continuous choropleth maps
263
+ - Replace deprecated `.unary_union` with `.union_all()`
264
+ - Choropleth map legends now print spans for binned data
265
+ - Use Matplotlib's legend for choropleth maps, to have the same style as other charts, and for much improved flexibility
266
+ - Inset maps now (finally!) work with continuous data
267
+ - Better error handling in categorical maps
268
+ - Cast all categorical values to strings in categorical maps
269
+ - Replace deprecated imghdr with puremagic in tests
270
+
233
271
  - 1.59.0
234
272
 
235
273
  - Added `.highlight_annotation` to enable turning off the textual annotation on the highlighted point
@@ -1,16 +1,3 @@
1
- Metadata-Version: 2.1
2
- Name: newsworthycharts
3
- Version: 1.59.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.59.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|quarterly|monthly|weekly|daily
127
- - units = 'number' # number|percent|degrees
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
@@ -223,13 +210,37 @@ To deploy a new version to [PyPi](https://pypi.org/project/newsworthycharts):
223
210
 
224
211
  Roadmap
225
212
  -------
226
- - Adding more base maps
227
- - Getting rid of custom settings-hack
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)
228
217
  - Custom month locator with equal-width month bars
218
+ - Add color-ramp choropleth maps, as an alternative to binning
229
219
 
230
220
  Changelog
231
221
  ---------
232
222
 
223
+ - 1.60.1
224
+
225
+ - Don't require fiona. Geopandas now support Pyogrio
226
+
227
+ - 1.60.0
228
+
229
+ - [BREAKING] The default number of bins in maps is now 5, not 9
230
+ - [BREAKING] Default color ramp for choropleth maps is now `YlGn`
231
+ - GeoPandas 1.x
232
+ - numpy 2.x
233
+ - matplotlib==3.9.2
234
+ - Pillow==10.4.0
235
+ - Improved nan handling in labelling continuous choropleth maps
236
+ - Replace deprecated `.unary_union` with `.union_all()`
237
+ - Choropleth map legends now print spans for binned data
238
+ - Use Matplotlib's legend for choropleth maps, to have the same style as other charts, and for much improved flexibility
239
+ - Inset maps now (finally!) work with continuous data
240
+ - Better error handling in categorical maps
241
+ - Cast all categorical values to strings in categorical maps
242
+ - Replace deprecated imghdr with puremagic in tests
243
+
233
244
  - 1.59.0
234
245
 
235
246
  - Added `.highlight_annotation` to enable turning off the textual annotation on the highlighted point
@@ -1,4 +1,4 @@
1
- __version__ = "1.59.0"
1
+ __version__ = "1.60.1"
2
2
 
3
3
  from .chart import Chart
4
4
  from .choroplethmap import ChoroplethMap
@@ -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
- if self.categorical:
33
- # We'll categorize manually further down the line,
34
- # to easier implement custom coloring
35
- pass
36
- # df["data"] = pd.Categorical(
37
- # df["data"],
38
- # ordered=True,
39
- # )
40
- else:
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
- args = {
62
- "categorical": True,
63
- "legend": True, # bug in geopandas, fixed in master but not released
64
- "legend_kwds": {
65
- "loc": "upper left",
66
- "bbox_to_anchor": (1.05, 1.0),
67
- },
68
- "edgecolor": "white",
69
- "linewidth": 0.2,
70
- "missing_kwds": {
71
- "color": "gainsboro",
72
- },
73
- }
74
- # This should be adjusted per basemap
75
- label_kwargs = {
76
- "bbox_to_anchor": (0.92, 0.95),
77
- "loc": "upper left",
78
- }
79
- if not self.categorical:
80
- args["cmap"] = self.color_ramp
81
- args["column"] = "data"
82
- if self.categorical:
83
- cat = df[~df["data"].isna()]["data"].unique()
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
- self.ax.legend(
108
- handles=patches,
109
- **label_kwargs
110
- )
133
+ if self.missing_label:
134
+ patches.append(mpatches.Patch(color="gainsboro", label=self.missing_label))
111
135
 
112
- fig = df.plot(ax=self.ax, **args)
136
+ df.plot(ax=self.ax, **args)
113
137
  # Add outer edge
114
- gpd.GeoSeries(df.unary_union).plot(
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
- if self.categorical:
154
- # We need a series matching the filtered data
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.unary_union).plot(
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
+ )
@@ -4,7 +4,6 @@ Base class for maps
4
4
  from .chart import Chart
5
5
  from .lib.geography import haversine
6
6
  from .translations.regions import NW_MUNI_TO_CLDR
7
- from fiona.errors import DriverError
8
7
  import geopandas as gpd
9
8
  import pathlib
10
9
 
@@ -87,10 +86,10 @@ class Map(Chart):
87
86
 
88
87
  def __init__(self, *args, **kwargs):
89
88
  super(Map, self).__init__(*args, **kwargs)
90
- self.bins = kwargs.get("bins", 9)
89
+ self.bins = kwargs.get("bins", 5)
91
90
  self.binning_method = kwargs.get("binning_method", "natural_breaks")
92
91
  self.colors = kwargs.get("colors", None)
93
- self.color_ramp = kwargs.get("color_ramp", "YlOrRd")
92
+ self.color_ramp = kwargs.get("color_ramp", "YlGn") # YlOrRd
94
93
  self.categorical = kwargs.get("categorical", False)
95
94
  self.base_map = None
96
95
  self.missing_label = None
@@ -139,12 +138,7 @@ class Map(Chart):
139
138
 
140
139
  if self.df is None:
141
140
  __dir = pathlib.Path(__file__).parent.resolve()
142
- try:
143
- self.df = gpd.read_file(f"{__dir}/maps/{base_map}-{subdivisions}.gpkg")
144
- except DriverError:
145
- raise ValueError(
146
- f"No such basemap: {_bm} (parsed as base: {base_map}, subdivisions: {subdivisions})"
147
- )
141
+ self.df = gpd.read_file(f"{__dir}/maps/{base_map}-{subdivisions}.gpkg", engine="pyogrio")
148
142
  return base_map, subdivisions, subset, *opts
149
143
 
150
144
  def _prepare_map_data(self):
@@ -1,3 +1,30 @@
1
+ Metadata-Version: 2.1
2
+ Name: newsworthycharts
3
+ Version: 1.60.1
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.1.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.10
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|quarterly|monthly|weekly|daily
114
- - units = 'number' # number|percent|degrees
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
@@ -210,13 +237,37 @@ To deploy a new version to [PyPi](https://pypi.org/project/newsworthycharts):
210
237
 
211
238
  Roadmap
212
239
  -------
213
- - Adding more base maps
214
- - Getting rid of custom settings-hack
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)
215
244
  - Custom month locator with equal-width month bars
245
+ - Add color-ramp choropleth maps, as an alternative to binning
216
246
 
217
247
  Changelog
218
248
  ---------
219
249
 
250
+ - 1.60.1
251
+
252
+ - Don't require fiona. Geopandas now support Pyogrio
253
+
254
+ - 1.60.0
255
+
256
+ - [BREAKING] The default number of bins in maps is now 5, not 9
257
+ - [BREAKING] Default color ramp for choropleth maps is now `YlGn`
258
+ - GeoPandas 1.x
259
+ - numpy 2.x
260
+ - matplotlib==3.9.2
261
+ - Pillow==10.4.0
262
+ - Improved nan handling in labelling continuous choropleth maps
263
+ - Replace deprecated `.unary_union` with `.union_all()`
264
+ - Choropleth map legends now print spans for binned data
265
+ - Use Matplotlib's legend for choropleth maps, to have the same style as other charts, and for much improved flexibility
266
+ - Inset maps now (finally!) work with continuous data
267
+ - Better error handling in categorical maps
268
+ - Cast all categorical values to strings in categorical maps
269
+ - Replace deprecated imghdr with puremagic in tests
270
+
220
271
  - 1.59.0
221
272
 
222
273
  - Added `.highlight_annotation` to enable turning off the textual annotation on the highlighted point
@@ -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
- boto3>=1.26
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.10
@@ -25,18 +25,19 @@ setup(
25
25
  python_requires='>=3.9',
26
26
  install_requires=[
27
27
  "boto3>=1.26",
28
- "matplotlib==3.9.0",
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>=1.21.0,<2",
33
+ "numpy>2",
34
34
  "python-dateutil>=2,<3",
35
- "Pillow==10.3.0",
35
+ "Pillow==10.4.0",
36
36
  "requests>=2.22",
37
37
  "matplotlib-label-lines==0.5.1",
38
- "geopandas==0.14.4",
38
+ "geopandas>1",
39
39
  "mapclassify==2.6.1",
40
+ "fiona>=1.10",
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 what(container["png"]) == "png"
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 what(container["webp"]) == "webp"
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 what(container["png"]) == "png"
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 what(container["png"]) == "png"
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({