newsworthycharts 1.66.0__tar.gz → 1.68.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.
Files changed (51) hide show
  1. {newsworthycharts-1.66.0/newsworthycharts.egg-info → newsworthycharts-1.68.0}/PKG-INFO +15 -2
  2. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/README.rst +13 -0
  3. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/newsworthycharts/__init__.py +1 -1
  4. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/newsworthycharts/categoricalchart.py +69 -21
  5. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/newsworthycharts/chart.py +3 -3
  6. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/newsworthycharts/lib/datalist.py +5 -0
  7. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0/newsworthycharts.egg-info}/PKG-INFO +15 -2
  8. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/LICENSE.txt +0 -0
  9. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/MANIFEST.in +0 -0
  10. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/newsworthycharts/bubblemap.py +0 -0
  11. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/newsworthycharts/choroplethmap.py +0 -0
  12. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/newsworthycharts/custom/__init__.py +0 -0
  13. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/newsworthycharts/custom/climate_cars.py +0 -0
  14. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/newsworthycharts/datawrapper.py +0 -0
  15. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/newsworthycharts/lib/__init__.py +0 -0
  16. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/newsworthycharts/lib/color_fn.py +0 -0
  17. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/newsworthycharts/lib/colors.py +0 -0
  18. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/newsworthycharts/lib/formatter.py +0 -0
  19. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/newsworthycharts/lib/geography.py +0 -0
  20. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/newsworthycharts/lib/locator.py +0 -0
  21. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/newsworthycharts/lib/mimetypes.py +0 -0
  22. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/newsworthycharts/lib/utils.py +0 -0
  23. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/newsworthycharts/map.py +0 -0
  24. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/newsworthycharts/maps/se-4.gpkg +0 -0
  25. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/newsworthycharts/maps/se-7.gpkg +0 -0
  26. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/newsworthycharts/rangeplot.py +0 -0
  27. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/newsworthycharts/rc/newsworthy +0 -0
  28. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/newsworthycharts/scatterplot.py +0 -0
  29. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/newsworthycharts/seasonalchart.py +0 -0
  30. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/newsworthycharts/serialchart.py +0 -0
  31. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/newsworthycharts/storage.py +0 -0
  32. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/newsworthycharts/stripechart.py +0 -0
  33. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/newsworthycharts/translations/datawrapper_regions.csv +0 -0
  34. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/newsworthycharts/translations/regions.py +0 -0
  35. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/newsworthycharts/translations/se_municipalities.csv +0 -0
  36. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/newsworthycharts.egg-info/SOURCES.txt +0 -0
  37. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/newsworthycharts.egg-info/dependency_links.txt +0 -0
  38. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/newsworthycharts.egg-info/not-zip-safe +0 -0
  39. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/newsworthycharts.egg-info/requires.txt +0 -0
  40. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/newsworthycharts.egg-info/top_level.txt +0 -0
  41. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/setup.cfg +0 -0
  42. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/setup.py +0 -0
  43. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/test/test_categorical_chart.py +0 -0
  44. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/test/test_choropleth_maps.py +0 -0
  45. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/test/test_custom_climate_cars.py +0 -0
  46. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/test/test_data_list.py +0 -0
  47. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/test/test_datawrapper.py +0 -0
  48. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/test/test_main.py +0 -0
  49. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/test/test_rangeplot.py +0 -0
  50. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/test/test_scatterplot.py +0 -0
  51. {newsworthycharts-1.66.0 → newsworthycharts-1.68.0}/test/test_serial_chart.py +0 -0
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: newsworthycharts
3
- Version: 1.66.0
3
+ Version: 1.68.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.66.0.tar.gz
6
+ Download-URL: https://github.com/jplusplus/newsworthycharts/archive/1.68.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
@@ -259,6 +259,19 @@ Roadmap
259
259
  Changelog
260
260
  ---------
261
261
 
262
+ - 1.68.0
263
+
264
+ - Matplotlib==3.9.3
265
+ - More padding below chart
266
+ - Fix zorder issue in labeled multiple pie charts
267
+
268
+ - 1.67.0
269
+
270
+ - Fixed label margins in pie charts
271
+ - Trim all titles and subtitles of leading and trailing whitespace
272
+ - Improved piechart annotation
273
+ - Support `label_placement` (legend|outside|inline) in categorical charts ('legend' is still buggy in pie charts)
274
+
262
275
  - 1.66.0
263
276
 
264
277
  - Support multiple data series in pie charts (displayed as small multiples)
@@ -232,6 +232,19 @@ Roadmap
232
232
  Changelog
233
233
  ---------
234
234
 
235
+ - 1.68.0
236
+
237
+ - Matplotlib==3.9.3
238
+ - More padding below chart
239
+ - Fix zorder issue in labeled multiple pie charts
240
+
241
+ - 1.67.0
242
+
243
+ - Fixed label margins in pie charts
244
+ - Trim all titles and subtitles of leading and trailing whitespace
245
+ - Improved piechart annotation
246
+ - Support `label_placement` (legend|outside|inline) in categorical charts ('legend' is still buggy in pie charts)
247
+
235
248
  - 1.66.0
236
249
 
237
250
  - Support multiple data series in pie charts (displayed as small multiples)
@@ -1,4 +1,4 @@
1
- __version__ = "1.66.0"
1
+ __version__ = "1.68.0"
2
2
 
3
3
  from .chart import Chart
4
4
  from .choroplethmap import ChoroplethMap
@@ -1,6 +1,6 @@
1
1
  from .chart import Chart
2
2
  from .lib.utils import to_float
3
-
3
+ from adjustText import adjust_text
4
4
  import numpy as np
5
5
 
6
6
 
@@ -16,6 +16,7 @@ class CategoricalChart(Chart):
16
16
  self.stacked = False
17
17
  self.legend = True
18
18
  self.type = "bars"
19
+ self.label_placement = None # legend|inline|outside # defaults will vary
19
20
 
20
21
  # Optional: specify a list of colors (for multiple datasets)
21
22
  self.colors = None
@@ -25,11 +26,11 @@ class CategoricalChart(Chart):
25
26
  return self.stacked
26
27
 
27
28
  def _add_pie_data(self):
28
- self.legend = False
29
29
  self.show_ticks = False
30
30
 
31
31
  if len(self.data) > 1:
32
- subaxes = self._fig.subplots(1, len(self.data))
32
+ subaxes = self._fig.subplots(1, len(self.data), subplot_kw={"zorder": -1})
33
+ patches = []
33
34
  for idx, serie in enumerate(self.data):
34
35
  if len(self.data) == 1:
35
36
  subax = self.ax
@@ -45,17 +46,30 @@ class CategoricalChart(Chart):
45
46
  colors = [self._nwc_style["qualitative_colors"][i] for i in range(len(values))]
46
47
 
47
48
  explode = [0.1 if x == self.highlight else 0 for x in labels]
48
- subax.pie(
49
+ legend_placement = self.label_placement or "inline"
50
+ _pie = subax.pie(
49
51
  values,
50
- labels=labels,
52
+ labels=labels if legend_placement == "inline" else None,
51
53
  startangle=90,
52
54
  colors=colors,
53
- explode=explode
55
+ explode=explode,
54
56
  )
55
- subax.axis('equal')
57
+ if idx == 0:
58
+ patches += _pie[0]
59
+ if len(self.data) > 1:
60
+ subax.axis('equal')
56
61
  # `labels` in pie charts are used to label the series, not the values
57
62
  if self.labels:
58
- subax.set_title(self.labels[idx], loc='center', y=0.04)
63
+ subax.set_title(self.labels[idx], loc='center', y=0)
64
+ if legend_placement == "inline":
65
+ self.legend = False
66
+ elif legend_placement == "legend":
67
+ _ = self.ax.legend(patches, labels, loc='best', frameon=True, fancybox=True)
68
+ _.set(zorder=20)
69
+ # self.ax.figure.subplots_adjust()
70
+ elif legend_placement == "outside":
71
+ _ = self.ax.legend(patches, labels, bbox_to_anchor=(1.04, 1), loc="upper left")
72
+ _.set(zorder=20)
59
73
 
60
74
  self.ax.axis('off')
61
75
 
@@ -91,7 +105,7 @@ class CategoricalChart(Chart):
91
105
  serie_values.append(_values)
92
106
 
93
107
  cum_values = np.cumsum(serie_values, axis=0).tolist()
94
-
108
+ self._bars = []
95
109
  for i, data in enumerate(self.data):
96
110
 
97
111
  # Replace None values with 0's to be able to plot bars
@@ -167,6 +181,7 @@ class CategoricalChart(Chart):
167
181
  bar_pos = [x + i * bar_width
168
182
  for x in np.arange(len(values))]
169
183
 
184
+ _bar = None
170
185
  if self.bar_orientation == "horizontal":
171
186
  kwargs = dict(align='center', height=bar_width,
172
187
  color=colors, zorder=2)
@@ -174,7 +189,7 @@ class CategoricalChart(Chart):
174
189
  # To make stacked bars we need to set bottom value
175
190
  kwargs["left"] = cum_values[i - 1]
176
191
 
177
- self.ax.barh(bar_pos, values, **kwargs)
192
+ _bar = self.ax.barh(bar_pos, values, **kwargs)
178
193
 
179
194
  elif self.bar_orientation == "vertical":
180
195
  kwargs = dict(
@@ -185,7 +200,8 @@ class CategoricalChart(Chart):
185
200
  if self.stacked and i > 0:
186
201
  # To make stacked bars we need to set bottom value
187
202
  kwargs["bottom"] = cum_values[i - 1]
188
- self.ax.bar(bar_pos, values, **kwargs)
203
+ _bar = self.ax.bar(bar_pos, values, **kwargs)
204
+ self._bars.append(_bar)
189
205
 
190
206
  if self.bar_orientation == "horizontal":
191
207
  margin = 0.02 # above and below first/last bar on horizontal
@@ -207,9 +223,6 @@ class CategoricalChart(Chart):
207
223
  self.ax.set_xticklabels(categories)
208
224
  self.ax.xaxis.set_ticks_position('none')
209
225
 
210
- if len(self.data) > 1:
211
- self.ax.legend(self.labels, loc='best')
212
-
213
226
  self._setup_legend()
214
227
 
215
228
  def _setup_legend(self):
@@ -218,6 +231,31 @@ class CategoricalChart(Chart):
218
231
  legend = self.ax.get_legend()
219
232
  if legend:
220
233
  legend.remove()
234
+ else:
235
+ if len(self.data) == 0 and self.type != "pie":
236
+ return
237
+ placement = self.label_placement or "legend"
238
+ if placement == "legend":
239
+ self.ax.legend(self.labels, loc='best')
240
+ elif placement == "outside":
241
+ _ = self.ax.legend(self.labels, bbox_to_anchor=(1.04, 1), loc="upper left")
242
+ _.set(zorder=20)
243
+ elif placement == "inline":
244
+ texts = []
245
+ for idx, _bar in enumerate(self._bars):
246
+ _texts = self.ax.bar_label(
247
+ _bar,
248
+ labels=[self.labels[idx]] * self.data.num_categories,
249
+ label_type="center",
250
+ backgroundcolor="#f0f0f099",
251
+ )
252
+ if idx > 0:
253
+ texts += [*_texts]
254
+ adjust_text(
255
+ texts,
256
+ ax=self.ax,
257
+ autoalign="x" if self.bar_orientation == "horizontal" else "y",
258
+ )
221
259
 
222
260
 
223
261
  class CategoricalChartWithReference(CategoricalChart):
@@ -243,6 +281,7 @@ class CategoricalChartWithReference(CategoricalChart):
243
281
  self.value_axis.grid(True)
244
282
 
245
283
  bar_width = 0.8 / len(self.data)
284
+ self._bars = []
246
285
  for i, data in enumerate(self.data):
247
286
 
248
287
  # Replace None values with 0's to be able to plot bars
@@ -270,18 +309,30 @@ class CategoricalChartWithReference(CategoricalChart):
270
309
 
271
310
  zorder = len(self.data) - i
272
311
  if self.bar_orientation == "horizontal":
273
- self.ax.barh(bar_pos, values, height=bar_width, align='center',
274
- color=color, zorder=zorder)
312
+ bar = self.ax.barh(
313
+ bar_pos,
314
+ values,
315
+ height=bar_width,
316
+ align='center',
317
+ color=color,
318
+ zorder=zorder,
319
+ )
275
320
  self.ax.set_yticks(tick_pos)
276
321
  self.ax.set_yticklabels(categories)
277
322
  # self.ax.invert_yaxis()
278
323
 
279
324
  elif self.bar_orientation == "vertical":
280
- self.ax.bar(bar_pos, values, width=bar_width, color=color,
281
- zorder=zorder)
325
+ bar = self.ax.bar(
326
+ bar_pos,
327
+ values,
328
+ width=bar_width,
329
+ color=color,
330
+ zorder=zorder,
331
+ )
282
332
  self.ax.set_xticks(tick_pos)
283
333
  self.ax.set_xticklabels(categories)
284
334
  self.ax.xaxis.set_ticks_position('none')
335
+ self._bars.append(bar)
285
336
 
286
337
  # Make sure labels are not cropped
287
338
  yaxis_bbox = self.ax.yaxis.get_tightbbox(self._fig.canvas.get_renderer())
@@ -289,9 +340,6 @@ class CategoricalChartWithReference(CategoricalChart):
289
340
  margin -= yaxis_bbox.min[0] / float(self._w)
290
341
  self._fig.subplots_adjust(left=margin)
291
342
 
292
- if self.labels:
293
- self.ax.legend(self.labels, loc='best')
294
-
295
343
  self._setup_legend()
296
344
 
297
345
 
@@ -285,7 +285,7 @@ class Chart(object):
285
285
  def _add_title(self, title_text):
286
286
  """Add a title."""
287
287
  text = self._fig.suptitle(
288
- title_text, wrap=True,
288
+ title_text.strip(), wrap=True,
289
289
  x=0,
290
290
  y=0.985, # default: 0.98
291
291
  horizontalalignment="left",
@@ -300,7 +300,7 @@ class Chart(object):
300
300
  text = self._fig.text(
301
301
  0,
302
302
  y_pos,
303
- subtitle_text,
303
+ subtitle_text.strip(),
304
304
  wrap=True,
305
305
  verticalalignment="top",
306
306
  linespacing=1.4,
@@ -648,7 +648,7 @@ class Chart(object):
648
648
  # ticks labels
649
649
  tick_label_height
650
650
  # some padding
651
- # + 30 / self._h
651
+ + 15 / self._h
652
652
  # chart notes (if any)
653
653
  + self._note_rel_height
654
654
  # chart caption and logo (if any)
@@ -196,6 +196,11 @@ class DataSet(MutableSequence):
196
196
  values = array(self.values, dtype=float)
197
197
  return np.nansum(values, axis=0).tolist()
198
198
 
199
+ @property
200
+ def num_categories(self):
201
+ categories = set([x[0] for s in self.list for x in s])
202
+ return len(categories)
203
+
199
204
  def __len__(self):
200
205
  return len(self.list)
201
206
 
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: newsworthycharts
3
- Version: 1.66.0
3
+ Version: 1.68.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.66.0.tar.gz
6
+ Download-URL: https://github.com/jplusplus/newsworthycharts/archive/1.68.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
@@ -259,6 +259,19 @@ Roadmap
259
259
  Changelog
260
260
  ---------
261
261
 
262
+ - 1.68.0
263
+
264
+ - Matplotlib==3.9.3
265
+ - More padding below chart
266
+ - Fix zorder issue in labeled multiple pie charts
267
+
268
+ - 1.67.0
269
+
270
+ - Fixed label margins in pie charts
271
+ - Trim all titles and subtitles of leading and trailing whitespace
272
+ - Improved piechart annotation
273
+ - Support `label_placement` (legend|outside|inline) in categorical charts ('legend' is still buggy in pie charts)
274
+
262
275
  - 1.66.0
263
276
 
264
277
  - Support multiple data series in pie charts (displayed as small multiples)