newsworthycharts 1.61.4__py3-none-any.whl → 1.63.0__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.
@@ -1,4 +1,4 @@
1
- __version__ = "1.61.4"
1
+ __version__ = "1.63.0"
2
2
 
3
3
  from .chart import Chart
4
4
  from .choroplethmap import ChoroplethMap
newsworthycharts/chart.py CHANGED
@@ -17,7 +17,8 @@ from matplotlib.font_manager import FontProperties
17
17
  from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
18
18
  from matplotlib.figure import Figure
19
19
  from matplotlib.ticker import FuncFormatter
20
- from matplotlib.dates import DateFormatter, num2date
20
+ from matplotlib.dates import DateFormatter, num2date, YearLocator
21
+
21
22
  from langcodes import standardize_tag
22
23
  from PIL import Image
23
24
  from babel import Locale
@@ -366,7 +367,10 @@ class Chart(object):
366
367
  self.ax.plot([0], transform=self.ax.transAxes, **kwargs)
367
368
 
368
369
  def _set_date_ticks(self, dates):
369
- """ Set x ticks and formatters for chart types working on date series """
370
+ """
371
+ Set x ticks and formatters for chart types working on date series.
372
+ Todo: Unify location setting, to be able to support max_ticks everywhere.
373
+ """
370
374
 
371
375
  # Number of days on x axis (Matplotlib will use days as unit here)
372
376
  xmin, xmax = to_date(self.data.x_points[0]), to_date(self.data.x_points[-1])
@@ -377,9 +381,31 @@ class Chart(object):
377
381
  self.ax.set_xticks([x[0] for x in self.ticks])
378
382
  self.ax.set_xticklabels([x[1] for x in self.ticks])
379
383
 
384
+ elif self.interval == "decennial":
385
+ # Get the intervall needed to stay below max_ticks
386
+ i = 1
387
+ while len(dates) / i > self.max_ticks:
388
+ i += 1
389
+ loc = YearLocator(10 * i)
390
+ # loc = get_best_locator(delta, len(dates), self.interval)
391
+ self.ax.xaxis.set_major_locator(loc)
392
+
393
+ formatter = Formatter(self._language)
394
+
395
+ def fmt(x, pos):
396
+ d = num2date(x).isoformat()[:10]
397
+ # 9 years later
398
+ d2 = str(int(d[:4]) + 9) + d[4:]
399
+ if len(self.data.x_points) > 7:
400
+ return formatter.date(d, "yy") + "–" + formatter.date(d2, "yy")
401
+ else:
402
+ return formatter.date(d, "y") + "–" + formatter.date(d2, "yy")
403
+ self.ax.xaxis.set_major_formatter(fmt)
404
+
380
405
  elif delta.days > 500:
381
406
  ticks = get_year_ticks(xmin, xmax, max_ticks=self.max_ticks)
382
407
  self.ax.set_xticks(ticks)
408
+
383
409
  self.ax.xaxis.set_major_formatter(DateFormatter('%Y'))
384
410
 
385
411
  else:
@@ -667,6 +693,7 @@ class Chart(object):
667
693
  'Creator': f"NWCharts {__version__}",
668
694
  }
669
695
  """
696
+
670
697
  self._fig.savefig(buf, **args) # , bbox_inches="tight")
671
698
  buf.seek(0)
672
699
  self._storage.save(key, buf, img_format, storage_options)
@@ -42,7 +42,10 @@ def get_best_locator(delta, points, interval=None):
42
42
  trying to keep the x axis as clean as possible, while still including
43
43
  enough clues for the reader to easily understand the graph.
44
44
  """
45
- if delta.days > 365 * 150:
45
+ if interval == "decennial":
46
+ # Set one tick every 10 years
47
+ return YearLocator(10)
48
+ elif delta.days > 365 * 150:
46
49
  return YearLocator(100)
47
50
  elif delta.days > 365 * 45:
48
51
  return YearLocator(20)
@@ -163,15 +163,21 @@ def outline(color="white", linewidth=3, **kwargs):
163
163
 
164
164
  def guess_date_interval(data):
165
165
  """Return a probable interval, e.g. "montly", given current data."""
166
- interval = "yearly"
166
+ interval = "decennial"
167
167
  for serie in data:
168
168
  dates = [to_date(x[0]) for x in serie]
169
169
  years = [x.year for x in dates]
170
+
171
+ # Are there decades with more than one year?
172
+ if len(years) > len(set(years)):
173
+ interval = "yearly"
174
+
170
175
  months = [x.month for x in dates]
171
176
  yearmonths = [x.strftime("%Y-%m") for x in dates]
172
177
  weeks = [str(x.year) + str(x.isocalendar()[1]) for x in dates]
178
+
173
179
  if len(years) > len(set(years)):
174
- # there are years with more than one point
180
+ # Are there years with more than one point?
175
181
  unique_months = sorted(list(set(months)))
176
182
  if len(unique_months) == 4 \
177
183
  and unique_months[0] + 3 == unique_months[1] \
@@ -47,7 +47,7 @@ class ScatterPlot(Chart):
47
47
 
48
48
  # hard coded max number of ticks for now
49
49
  # consider dynamic/more clever approach
50
- max_ticks = 5
50
+ max_ticks = 7
51
51
  self.ax.yaxis.set_major_locator(MaxNLocator(nbins=max_ticks))
52
52
  self.ax.xaxis.set_major_locator(MaxNLocator(nbins=max_ticks))
53
53
 
@@ -34,7 +34,7 @@ class SerialChart(Chart):
34
34
  # Set with of lines explicitly (otherwise determined by style file)
35
35
  self.line_width = None
36
36
 
37
- self.max_ticks = 7
37
+ self.max_ticks = 10
38
38
 
39
39
  # Manually set tick locations and labels? Provide a list of tuples:
40
40
  # [(2013-01-01, "-13"), (2014-01-01, "-14"), (2015-01-01, "-15")]
@@ -73,7 +73,8 @@ class SerialChart(Chart):
73
73
  self._ymax = val
74
74
 
75
75
  def _days_in(self, interval, d=None):
76
- """Return number of days in a given period.
76
+ """
77
+ Return number of days in a given period. This is used to set bar widths, so approximate is fine.
77
78
 
78
79
  If only interval is given, use a typical number of days.
79
80
  >>>> _days_in(monthly)
@@ -83,6 +84,7 @@ class SerialChart(Chart):
83
84
  """
84
85
  if d is None:
85
86
  return {
87
+ 'decennial': 3652,
86
88
  'yearly': 365,
87
89
  'quarterly': 91,
88
90
  'monthly': 30,
@@ -109,6 +111,10 @@ class SerialChart(Chart):
109
111
  return 7
110
112
  elif interval == "daily":
111
113
  return 1
114
+ elif interval == "decennial":
115
+ return (
116
+ (d + relativedelta(years=10)).replace(day=1, month=1) - d.replace(day=1, month=1)
117
+ ).days
112
118
 
113
119
  def _get_annotation_direction(self, index, values):
114
120
  """ Given an index and series of values, provide the estimated best
@@ -266,7 +272,7 @@ class SerialChart(Chart):
266
272
  marker='.',
267
273
  zorder=12)
268
274
 
269
- if len(self.labels) > i:
275
+ if len(self.labels) > i and any([x[1] for x in serie]):
270
276
  line.set_label(self.labels[i])
271
277
 
272
278
  if self.label_placement == "line":
@@ -284,11 +290,14 @@ class SerialChart(Chart):
284
290
 
285
291
  # add highlight marker
286
292
  if highlight_value:
287
- self.ax.plot(highlight_date, highlight_value,
288
- c=color,
289
- marker='o',
290
- markersize=5,
291
- zorder=zo)
293
+ self.ax.plot(
294
+ highlight_date,
295
+ highlight_value,
296
+ c=color,
297
+ marker='o',
298
+ markersize=5,
299
+ zorder=zo,
300
+ )
292
301
 
293
302
  elif self.type[i] == "bars":
294
303
  # Put first series on top
@@ -381,7 +390,7 @@ class SerialChart(Chart):
381
390
  bars = self.ax.bar(dates, values, **bar_kwargs)
382
391
  bar_elems.append(bars)
383
392
 
384
- if len(self.labels) > i:
393
+ if len(self.labels) > i and any([x[1] for x in serie]):
385
394
  bars.set_label(self.labels[i])
386
395
 
387
396
  # Add annotations
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: newsworthycharts
3
- Version: 1.61.4
3
+ Version: 1.63.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.61.4.tar.gz
6
+ Download-URL: https://github.com/jplusplus/newsworthycharts/archive/1.63.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
@@ -18,11 +18,11 @@ Requires-Dist: PyYAML >=3
18
18
  Requires-Dist: adjustText ==0.7.3
19
19
  Requires-Dist: numpy >2
20
20
  Requires-Dist: python-dateutil <3,>=2
21
- Requires-Dist: Pillow ==10.4.0
21
+ Requires-Dist: Pillow ==11.0.0
22
22
  Requires-Dist: requests >=2.22
23
23
  Requires-Dist: matplotlib-label-lines ==0.5.1
24
24
  Requires-Dist: geopandas >=1
25
- Requires-Dist: mapclassify ==2.6.1
25
+ Requires-Dist: mapclassify ==2.8.1
26
26
  Requires-Dist: puremagic >=1
27
27
 
28
28
  This module contains methods for producing graphs and publishing them on Amazon S3, or in the location of your choice.
@@ -154,13 +154,13 @@ These settings are available for all chart types:
154
154
 
155
155
  **SerialChart**
156
156
 
157
- - type = 'line' # line|bar|stacked_bar
157
+ - type = 'line' # line|bars
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
- - max_ticks = 7 # Maximum number of ticks on the x axis
163
+ - max_ticks = 10 # Maximum number of ticks on the x axis. *Only used with yearly|decennial data* (this is yet to be fixed)
164
164
  - 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
165
  - ymin = None # Minimum value on y axis. If None, it will be calculated from data
166
166
  - ymax = None # Maximum value on y axis. If None, it will be calculated from data
@@ -248,11 +248,21 @@ Roadmap
248
248
  - Remove custom charts (add missing api interfaces to Chart class instead)
249
249
  - Remove DataWrapper class (out-of-scope)
250
250
  - Custom month locator with equal-width month bars
251
- - Add color-ramp choropleth maps, as an alternative to binning
252
251
 
253
252
  Changelog
254
253
  ---------
255
254
 
255
+ - 1.63.0
256
+
257
+ - Added `interval: decennial` to SerialChart. Will be autodetected if all data points are 10 years apart.
258
+ - Pillow==11.0.0
259
+ - mapclassify==2.8.1
260
+
261
+ - 1.62.0
262
+
263
+ - max_ticks default is now 10 in SerialChart and 7 in ScatterPlot
264
+ - Don't print legend labels for empty series
265
+
256
266
  - 1.61.4
257
267
 
258
268
  - Make sure y axis and/or baseline is in front of bar padding
@@ -1,14 +1,14 @@
1
- newsworthycharts/__init__.py,sha256=HT7CF_Oi-hg9XDs5q5YosZK-KmBcVLqD6CJYUAx0ArI,1160
1
+ newsworthycharts/__init__.py,sha256=iyEaSC-FB3CheUeksBH1o0BZMMCGczVcLniWDXND5Us,1160
2
2
  newsworthycharts/bubblemap.py,sha256=nkocWmpiFgfjEuJGAsthjY5X7Q56jXWsZHUGXw4PwgE,2587
3
3
  newsworthycharts/categoricalchart.py,sha256=LwOZ3VbNy9vzvoK0s77AkbfMt4CXVDSAhnsnBInUIrE,14764
4
- newsworthycharts/chart.py,sha256=bCUkNKjFfuGRN6_VRQ-yCHla5LIMZ9H9a16upWbeWmY,30681
4
+ newsworthycharts/chart.py,sha256=e118gGQbFpRJZl3SWLhVCBatclG80eFdojrxJn8td5g,31664
5
5
  newsworthycharts/choroplethmap.py,sha256=bCLf4kcchp1C2djg5AxcOM8BdbaMj0xg7UHrZsDafhI,8013
6
6
  newsworthycharts/datawrapper.py,sha256=RRkAVTpfP4updKxUIBaSmKuBi2RUVPaBRF8HDQhlGGA,11250
7
7
  newsworthycharts/map.py,sha256=c409jEO4L8Yr780sJRC0RchR44roAlgOUDAkuk1SfRg,6057
8
8
  newsworthycharts/rangeplot.py,sha256=NE1W9TnmlpK6T3RvBJOU3nd73EXqkj17OY9i5zlw_cQ,8366
9
- newsworthycharts/scatterplot.py,sha256=6iaMoiZx__Gc-2Hcdw-8Ga5dSonrFo3oexKNmSFuir4,4959
9
+ newsworthycharts/scatterplot.py,sha256=l2w2JkA_4WzxQG9XG1Pn62IlJOdCMm1VemMiZL0rEfU,4959
10
10
  newsworthycharts/seasonalchart.py,sha256=rr55yqJUkaYDR9Ik98jes6574oY1U8t8LwoLE3gClW4,1967
11
- newsworthycharts/serialchart.py,sha256=vmek623WhSPRqKSJ9rEEzrW3e1j5yYBuudv4vhtm3MU,27296
11
+ newsworthycharts/serialchart.py,sha256=WrCWyDDRkXBXSqNyIhoBnm7A5RR2_wlluFPYirq_Snw,27686
12
12
  newsworthycharts/storage.py,sha256=myERhlpvXyExXxUByBq9eW1bWkCyfH9SwTZbsWSyy3Q,4301
13
13
  newsworthycharts/stripechart.py,sha256=9B6PX2MyLuKNQ8W0OGdKbP0-U32kju0K_NHHwwz_J68,1547
14
14
  newsworthycharts/custom/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -19,17 +19,17 @@ newsworthycharts/lib/colors.py,sha256=U04TDkvoMQkcldRFXfnwyLOTwq1SWW2se-Ad-DNcw9
19
19
  newsworthycharts/lib/datalist.py,sha256=fsO_esZBt4Aw_4n_l2LuswAYArbM-8Z8G9DAXo1oVZU,5376
20
20
  newsworthycharts/lib/formatter.py,sha256=GNH43hE0bC17OgiV8LYH3YUrEhm7OJh9XzfSV4HVtHo,4838
21
21
  newsworthycharts/lib/geography.py,sha256=K0_teFmuPJwXX7Py-amJB_1YY5_gL2kBYhz1LrRCyTg,584
22
- newsworthycharts/lib/locator.py,sha256=73ZqAvvLBhnWd0rKEHTyPiIL1H3MFHiUlb8aRKEm4FA,2938
22
+ newsworthycharts/lib/locator.py,sha256=rJHdgiA0LASRzdLINhTeU5zOoq1TCMgge4KOBWSagnM,3041
23
23
  newsworthycharts/lib/mimetypes.py,sha256=bL9HtVWbn2Of39LcBt4u4yelkr4bGZiyebq3OfLnfFY,237
24
- newsworthycharts/lib/utils.py,sha256=2Ko0dNFw2eHd32zQwJFUsgDkJGWSl6VacZs4AFPgrc8,7038
24
+ newsworthycharts/lib/utils.py,sha256=Io_yBHxUDTXw-9GvsizdSXnYvE_7ZtDKiWpLTAXpHfA,7171
25
25
  newsworthycharts/maps/se-4.gpkg,sha256=oWw5j7FPVpI0ig67jNDim8qSn5SG8rcHp0014-uTKZM,290816
26
26
  newsworthycharts/maps/se-7.gpkg,sha256=Vmvqudq_ZtgV0sd6TY6kuk7vzqmYZCJmaxtsJ87q2a8,331776
27
27
  newsworthycharts/rc/newsworthy,sha256=vbYTav1w3DmB5tpaaV7Xl5q7TQJsc9eou6pLCoWc2vs,1589
28
28
  newsworthycharts/translations/datawrapper_regions.csv,sha256=fzZcQRX6RFMlNNP8mpgfYNdR3Y0QAlQxDXk8FXTaWWI,9214
29
29
  newsworthycharts/translations/regions.py,sha256=Nv1McQjggD4S3JRu82rDMTG3pqUVR13E5-FBpSYbm98,239
30
30
  newsworthycharts/translations/se_municipalities.csv,sha256=br_mm-IvzQtj_W55_ATREhJ97jWnCweBFlDAVY2EBxA,7098
31
- newsworthycharts-1.61.4.dist-info/LICENSE.txt,sha256=Sq6kGICrehbhC_FolNdXf0djKjTpv3YqjFCIYsxdQN4,1069
32
- newsworthycharts-1.61.4.dist-info/METADATA,sha256=hyq--MoA3CK7V0jnG80ngjXIfm4QfJUtCcjXk2qJRSs,29000
33
- newsworthycharts-1.61.4.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91
34
- newsworthycharts-1.61.4.dist-info/top_level.txt,sha256=dn_kzIj8UgUCMsh1PHdVEQJHVGSsN7Z8YJF-8xXa8n0,17
35
- newsworthycharts-1.61.4.dist-info/RECORD,,
31
+ newsworthycharts-1.63.0.dist-info/LICENSE.txt,sha256=Sq6kGICrehbhC_FolNdXf0djKjTpv3YqjFCIYsxdQN4,1069
32
+ newsworthycharts-1.63.0.dist-info/METADATA,sha256=25lu-t46S5NLSLrKSyy5QdMSPgqLmcHtmyEdYhvRRCU,29278
33
+ newsworthycharts-1.63.0.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91
34
+ newsworthycharts-1.63.0.dist-info/top_level.txt,sha256=dn_kzIj8UgUCMsh1PHdVEQJHVGSsN7Z8YJF-8xXa8n0,17
35
+ newsworthycharts-1.63.0.dist-info/RECORD,,