newsworthycharts 1.66.0__tar.gz → 1.67.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.67.0}/PKG-INFO +9 -2
  2. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/README.rst +7 -0
  3. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/newsworthycharts/__init__.py +1 -1
  4. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/newsworthycharts/categoricalchart.py +63 -18
  5. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/newsworthycharts/chart.py +2 -2
  6. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/newsworthycharts/lib/datalist.py +5 -0
  7. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0/newsworthycharts.egg-info}/PKG-INFO +9 -2
  8. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/LICENSE.txt +0 -0
  9. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/MANIFEST.in +0 -0
  10. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/newsworthycharts/bubblemap.py +0 -0
  11. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/newsworthycharts/choroplethmap.py +0 -0
  12. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/newsworthycharts/custom/__init__.py +0 -0
  13. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/newsworthycharts/custom/climate_cars.py +0 -0
  14. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/newsworthycharts/datawrapper.py +0 -0
  15. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/newsworthycharts/lib/__init__.py +0 -0
  16. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/newsworthycharts/lib/color_fn.py +0 -0
  17. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/newsworthycharts/lib/colors.py +0 -0
  18. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/newsworthycharts/lib/formatter.py +0 -0
  19. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/newsworthycharts/lib/geography.py +0 -0
  20. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/newsworthycharts/lib/locator.py +0 -0
  21. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/newsworthycharts/lib/mimetypes.py +0 -0
  22. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/newsworthycharts/lib/utils.py +0 -0
  23. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/newsworthycharts/map.py +0 -0
  24. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/newsworthycharts/maps/se-4.gpkg +0 -0
  25. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/newsworthycharts/maps/se-7.gpkg +0 -0
  26. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/newsworthycharts/rangeplot.py +0 -0
  27. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/newsworthycharts/rc/newsworthy +0 -0
  28. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/newsworthycharts/scatterplot.py +0 -0
  29. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/newsworthycharts/seasonalchart.py +0 -0
  30. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/newsworthycharts/serialchart.py +0 -0
  31. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/newsworthycharts/storage.py +0 -0
  32. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/newsworthycharts/stripechart.py +0 -0
  33. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/newsworthycharts/translations/datawrapper_regions.csv +0 -0
  34. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/newsworthycharts/translations/regions.py +0 -0
  35. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/newsworthycharts/translations/se_municipalities.csv +0 -0
  36. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/newsworthycharts.egg-info/SOURCES.txt +0 -0
  37. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/newsworthycharts.egg-info/dependency_links.txt +0 -0
  38. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/newsworthycharts.egg-info/not-zip-safe +0 -0
  39. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/newsworthycharts.egg-info/requires.txt +0 -0
  40. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/newsworthycharts.egg-info/top_level.txt +0 -0
  41. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/setup.cfg +0 -0
  42. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/setup.py +0 -0
  43. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/test/test_categorical_chart.py +0 -0
  44. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/test/test_choropleth_maps.py +0 -0
  45. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/test/test_custom_climate_cars.py +0 -0
  46. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/test/test_data_list.py +0 -0
  47. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/test/test_datawrapper.py +0 -0
  48. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/test/test_main.py +0 -0
  49. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/test/test_rangeplot.py +0 -0
  50. {newsworthycharts-1.66.0 → newsworthycharts-1.67.0}/test/test_scatterplot.py +0 -0
  51. {newsworthycharts-1.66.0 → newsworthycharts-1.67.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.67.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.67.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,13 @@ Roadmap
259
259
  Changelog
260
260
  ---------
261
261
 
262
+ - 1.67.0
263
+
264
+ - Fixed label margins in pie charts
265
+ - Trim all titles and subtitles of leading and trailing whitespace
266
+ - Improved piechart annotation
267
+ - Support `label_placement` (legend|outside|inline) in categorical charts ('legend' is still buggy in pie charts)
268
+
262
269
  - 1.66.0
263
270
 
264
271
  - Support multiple data series in pie charts (displayed as small multiples)
@@ -232,6 +232,13 @@ Roadmap
232
232
  Changelog
233
233
  ---------
234
234
 
235
+ - 1.67.0
236
+
237
+ - Fixed label margins in pie charts
238
+ - Trim all titles and subtitles of leading and trailing whitespace
239
+ - Improved piechart annotation
240
+ - Support `label_placement` (legend|outside|inline) in categorical charts ('legend' is still buggy in pie charts)
241
+
235
242
  - 1.66.0
236
243
 
237
244
  - Support multiple data series in pie charts (displayed as small multiples)
@@ -1,4 +1,4 @@
1
- __version__ = "1.66.0"
1
+ __version__ = "1.67.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
32
  subaxes = self._fig.subplots(1, len(self.data))
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,27 @@ 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
55
  explode=explode
54
56
  )
57
+ if idx == 0:
58
+ patches += _pie[0]
55
59
  subax.axis('equal')
56
60
  # `labels` in pie charts are used to label the series, not the values
57
61
  if self.labels:
58
- subax.set_title(self.labels[idx], loc='center', y=0.04)
62
+ subax.set_title(self.labels[idx], loc='center', y=0)
63
+ if legend_placement == "inline":
64
+ self.legend = False
65
+ elif legend_placement == "legend":
66
+ self.ax.legend(patches, labels, loc='best', frameon=True, fancybox=True).set_zorder(100)
67
+ elif legend_placement == "outside":
68
+ _ = self.ax.legend(patches, labels, bbox_to_anchor=(1.04, 1), loc="upper left")
69
+ _.set(zorder=20)
59
70
 
60
71
  self.ax.axis('off')
61
72
 
@@ -91,7 +102,7 @@ class CategoricalChart(Chart):
91
102
  serie_values.append(_values)
92
103
 
93
104
  cum_values = np.cumsum(serie_values, axis=0).tolist()
94
-
105
+ self._bars = []
95
106
  for i, data in enumerate(self.data):
96
107
 
97
108
  # Replace None values with 0's to be able to plot bars
@@ -167,6 +178,7 @@ class CategoricalChart(Chart):
167
178
  bar_pos = [x + i * bar_width
168
179
  for x in np.arange(len(values))]
169
180
 
181
+ _bar = None
170
182
  if self.bar_orientation == "horizontal":
171
183
  kwargs = dict(align='center', height=bar_width,
172
184
  color=colors, zorder=2)
@@ -174,7 +186,7 @@ class CategoricalChart(Chart):
174
186
  # To make stacked bars we need to set bottom value
175
187
  kwargs["left"] = cum_values[i - 1]
176
188
 
177
- self.ax.barh(bar_pos, values, **kwargs)
189
+ _bar = self.ax.barh(bar_pos, values, **kwargs)
178
190
 
179
191
  elif self.bar_orientation == "vertical":
180
192
  kwargs = dict(
@@ -185,7 +197,8 @@ class CategoricalChart(Chart):
185
197
  if self.stacked and i > 0:
186
198
  # To make stacked bars we need to set bottom value
187
199
  kwargs["bottom"] = cum_values[i - 1]
188
- self.ax.bar(bar_pos, values, **kwargs)
200
+ _bar = self.ax.bar(bar_pos, values, **kwargs)
201
+ self._bars.append(_bar)
189
202
 
190
203
  if self.bar_orientation == "horizontal":
191
204
  margin = 0.02 # above and below first/last bar on horizontal
@@ -207,9 +220,6 @@ class CategoricalChart(Chart):
207
220
  self.ax.set_xticklabels(categories)
208
221
  self.ax.xaxis.set_ticks_position('none')
209
222
 
210
- if len(self.data) > 1:
211
- self.ax.legend(self.labels, loc='best')
212
-
213
223
  self._setup_legend()
214
224
 
215
225
  def _setup_legend(self):
@@ -218,6 +228,31 @@ class CategoricalChart(Chart):
218
228
  legend = self.ax.get_legend()
219
229
  if legend:
220
230
  legend.remove()
231
+ else:
232
+ if len(self.data) == 0 and self.type != "pie":
233
+ return
234
+ placement = self.label_placement or "legend"
235
+ if placement == "legend":
236
+ self.ax.legend(self.labels, loc='best')
237
+ elif placement == "outside":
238
+ _ = self.ax.legend(self.labels, bbox_to_anchor=(1.04, 1), loc="upper left")
239
+ _.set(zorder=20)
240
+ elif placement == "inline":
241
+ texts = []
242
+ for idx, _bar in enumerate(self._bars):
243
+ _texts = self.ax.bar_label(
244
+ _bar,
245
+ labels=[self.labels[idx]] * self.data.num_categories,
246
+ label_type="center",
247
+ backgroundcolor="#f0f0f099",
248
+ )
249
+ if idx > 0:
250
+ texts += [*_texts]
251
+ adjust_text(
252
+ texts,
253
+ ax=self.ax,
254
+ autoalign="x" if self.bar_orientation == "horizontal" else "y",
255
+ )
221
256
 
222
257
 
223
258
  class CategoricalChartWithReference(CategoricalChart):
@@ -243,6 +278,7 @@ class CategoricalChartWithReference(CategoricalChart):
243
278
  self.value_axis.grid(True)
244
279
 
245
280
  bar_width = 0.8 / len(self.data)
281
+ self._bars = []
246
282
  for i, data in enumerate(self.data):
247
283
 
248
284
  # Replace None values with 0's to be able to plot bars
@@ -270,18 +306,30 @@ class CategoricalChartWithReference(CategoricalChart):
270
306
 
271
307
  zorder = len(self.data) - i
272
308
  if self.bar_orientation == "horizontal":
273
- self.ax.barh(bar_pos, values, height=bar_width, align='center',
274
- color=color, zorder=zorder)
309
+ bar = self.ax.barh(
310
+ bar_pos,
311
+ values,
312
+ height=bar_width,
313
+ align='center',
314
+ color=color,
315
+ zorder=zorder,
316
+ )
275
317
  self.ax.set_yticks(tick_pos)
276
318
  self.ax.set_yticklabels(categories)
277
319
  # self.ax.invert_yaxis()
278
320
 
279
321
  elif self.bar_orientation == "vertical":
280
- self.ax.bar(bar_pos, values, width=bar_width, color=color,
281
- zorder=zorder)
322
+ bar = self.ax.bar(
323
+ bar_pos,
324
+ values,
325
+ width=bar_width,
326
+ color=color,
327
+ zorder=zorder,
328
+ )
282
329
  self.ax.set_xticks(tick_pos)
283
330
  self.ax.set_xticklabels(categories)
284
331
  self.ax.xaxis.set_ticks_position('none')
332
+ self._bars.append(bar)
285
333
 
286
334
  # Make sure labels are not cropped
287
335
  yaxis_bbox = self.ax.yaxis.get_tightbbox(self._fig.canvas.get_renderer())
@@ -289,9 +337,6 @@ class CategoricalChartWithReference(CategoricalChart):
289
337
  margin -= yaxis_bbox.min[0] / float(self._w)
290
338
  self._fig.subplots_adjust(left=margin)
291
339
 
292
- if self.labels:
293
- self.ax.legend(self.labels, loc='best')
294
-
295
340
  self._setup_legend()
296
341
 
297
342
 
@@ -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,
@@ -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.67.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.67.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,13 @@ Roadmap
259
259
  Changelog
260
260
  ---------
261
261
 
262
+ - 1.67.0
263
+
264
+ - Fixed label margins in pie charts
265
+ - Trim all titles and subtitles of leading and trailing whitespace
266
+ - Improved piechart annotation
267
+ - Support `label_placement` (legend|outside|inline) in categorical charts ('legend' is still buggy in pie charts)
268
+
262
269
  - 1.66.0
263
270
 
264
271
  - Support multiple data series in pie charts (displayed as small multiples)