newsworthycharts 1.70.2__py3-none-any.whl → 1.71.1__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,10 +1,11 @@
1
- __version__ = "1.70.2"
1
+ __version__ = "1.71.1"
2
2
 
3
3
  from .chart import Chart
4
4
  from .choroplethmap import ChoroplethMap
5
5
  from .bubblemap import BubbleMap
6
6
  from .serialchart import SerialChart
7
7
  from .seasonalchart import SeasonalChart
8
+ from .rankchart import BumpChart
8
9
  from .categoricalchart import CategoricalChart, CategoricalChartWithReference, ProgressChart
9
10
  from .scatterplot import ScatterPlot
10
11
  from .datawrapper import DatawrapperChart
@@ -26,6 +27,7 @@ CHART_ENGINES = {
26
27
  "SeasonalChart": SeasonalChart,
27
28
  "SerialChart": SerialChart,
28
29
  "StripeChart": StripeChart,
30
+ "BumpChart": BumpChart,
29
31
 
30
32
  # custom
31
33
  "ClimateCarsYearlyEmissionsTo2030": ClimateCarsYearlyEmissionsTo2030,
newsworthycharts/chart.py CHANGED
@@ -66,6 +66,7 @@ class Chart(object):
66
66
  self.decimals = None
67
67
  self.yline = None
68
68
  self.type = None
69
+ self.revert_value_axis = False
69
70
  # number of decimals to show in annotations, value ticks, etc
70
71
  # None means automatically chose the best number
71
72
  self.force_decimals = False
@@ -206,9 +207,14 @@ class Chart(object):
206
207
  c = color_name
207
208
  return c
208
209
 
209
- def _annotate_point(self, text, xy,
210
- direction, offset=12,
211
- **kwargs):
210
+ def _annotate_point(
211
+ self,
212
+ text,
213
+ xy,
214
+ direction,
215
+ offset=12,
216
+ **kwargs
217
+ ):
212
218
  """Add a label to a given point.
213
219
 
214
220
  :param text: text content of label
@@ -236,11 +242,11 @@ class Chart(object):
236
242
  elif direction == "left":
237
243
  opts["verticalalignment"] = "center"
238
244
  opts["horizontalalignment"] = "right"
239
- opts["xytext"] = (-offset, 0)
245
+ opts["xytext"] = (-offset, -self._nwc_style["annotation.fontsize"] / 0.75)
240
246
  elif direction == "right":
241
247
  opts["verticalalignment"] = "center"
242
248
  opts["horizontalalignment"] = "left"
243
- opts["xytext"] = (offset, 0)
249
+ opts["xytext"] = (offset, -self._nwc_style["annotation.fontsize"] / 0.75)
244
250
  else:
245
251
  msg = f"'{direction}' is an unknown direction for an annotation"
246
252
  raise Exception(msg)
@@ -669,6 +675,19 @@ class Chart(object):
669
675
  # print(sub_canvas_height, self._note_rel_height, self._footer_rel_height)
670
676
  self._fig.subplots_adjust(bottom=sub_canvas_height)
671
677
 
678
+ if self.revert_value_axis:
679
+ if hasattr(self, "orientation") and self.orientation == "horizontal":
680
+ self.ax.invert_xaxis()
681
+ value_axis = self.ax.get_xaxis()
682
+ value_ticks = self.ax.get_xticks()
683
+ else:
684
+ self.ax.invert_yaxis()
685
+ value_axis = self.ax.get_yaxis()
686
+ value_ticks = self.ax.get_yticks()
687
+ value_ticks = [x for x in value_ticks if x <= self.data.max_val and x >= self.ymin]
688
+ value_axis.set_ticks(value_ticks)
689
+ # self.ax.set_ylim(self.data.max_val, self.ymin)
690
+
672
691
  @classmethod
673
692
  def init_from(cls, args: dict, storage=LocalStorage(),
674
693
  style: str="newsworthy", language: str='en-GB'):
@@ -0,0 +1,40 @@
1
+ """
2
+ A chart showing ranking over time (like ”most popular baby names”)
3
+ """
4
+ from .serialchart import SerialChart
5
+
6
+
7
+ class BumpChart(SerialChart):
8
+ """Plot a rank chart
9
+
10
+ Data should be a list of iterables of (rank, date string) tuples, eg:
11
+ `[ [("2010-01-01", 2), ("2011-01-01", 3)] ]`, combined with a list of
12
+ labels in the same order
13
+ """
14
+
15
+ def __init__(self, *args, **kwargs):
16
+ super(BumpChart, self).__init__(*args, **kwargs)
17
+
18
+ if self.line_width is None:
19
+ self.line_width = 0.9
20
+ self.label_placement = 'line'
21
+ self.type = "line"
22
+ self.decimals = 0
23
+ self.revert_value_axis = True
24
+ self.ymin = 1
25
+ self.allow_broken_y_axis = False
26
+ self.grid = False
27
+ self.accentuate_baseline = False
28
+
29
+ self.line_marker = "o-"
30
+ self.line_marker_size = 5
31
+
32
+ def _get_line_colors(self, i, *args):
33
+ if not self.data:
34
+ # Don't waste time
35
+ return None
36
+ if self.highlight and self.highlight in self.labels and i == self.labels.index(self.highlight):
37
+ return self._nwc_style["strong_color"]
38
+ elif self.colors and i < len(self.colors):
39
+ return self.colors[i]
40
+ return self._nwc_style["neutral_color"]
@@ -28,12 +28,18 @@ class SerialChart(Chart):
28
28
  # draw bars and cut ay axis from this line
29
29
  self.baseline = kwargs.get("baseline", 0)
30
30
  self.baseline_annotation = kwargs.get("baseline_annotation", None)
31
+ self.accentuate_baseline = True
31
32
 
32
33
  self.color_labels = kwargs.get("color_labels", None)
33
34
 
34
35
  # Set with of lines explicitly (otherwise determined by style file)
35
36
  self.line_width = None
36
37
 
38
+ self.grid = True
39
+ self.point_marker = "."
40
+ self.line_marker = "-"
41
+ self.line_marker_size = 3
42
+
37
43
  self.max_ticks = 10
38
44
 
39
45
  # Manually set tick locations and labels? Provide a list of tuples:
@@ -235,7 +241,10 @@ class SerialChart(Chart):
235
241
  else:
236
242
  lw = self.line_width
237
243
 
238
- if self.colors is not None:
244
+ if hasattr(self, "_get_line_colors"):
245
+ # Hook for sub classes
246
+ color = self._get_line_colors(i)
247
+ elif self.colors is not None:
239
248
  if self.colors == "qualitative_colors":
240
249
  color = self._nwc_style["qualitative_colors"][i]
241
250
  else:
@@ -245,18 +254,26 @@ class SerialChart(Chart):
245
254
  else:
246
255
  color = self._nwc_style["neutral_color"]
247
256
 
248
- line, = self.ax.plot(dates, values,
249
- color=color,
250
- zorder=zo,
251
- lw=lw)
257
+ line, = self.ax.plot(
258
+ dates,
259
+ values,
260
+ self.line_marker,
261
+ markersize=self.line_marker_size,
262
+ color=color,
263
+ zorder=zo,
264
+ lw=lw,
265
+ )
252
266
  # Add single, orphaned data points as markers
253
267
  # None, 1, None, 1, 1, 1 => . ---
254
268
  num_values = len(values)
255
269
  if num_values == 1:
256
- self.ax.plot(dates[0], values[0],
257
- c=color,
258
- marker='.',
259
- zorder=12)
270
+ self.ax.plot(
271
+ dates[0],
272
+ values[0],
273
+ c=color,
274
+ marker=self.point_marker,
275
+ zorder=12,
276
+ )
260
277
  elif num_values > 1:
261
278
  for j, v in enumerate(values):
262
279
  def nullish(val):
@@ -270,10 +287,12 @@ class SerialChart(Chart):
270
287
  elif nullish(values[j - 1]) and nullish(values[j + 1]):
271
288
  plot_me = True
272
289
  if plot_me:
273
- self.ax.plot(dates[j], v,
274
- c=color,
275
- marker='.',
276
- zorder=12)
290
+ self.ax.plot(
291
+ dates[j], v,
292
+ c=color,
293
+ marker=self.point_marker,
294
+ zorder=12
295
+ )
277
296
 
278
297
  if len(self.labels) > i and any([x[1] for x in serie]):
279
298
  line.set_label(self.labels[i])
@@ -286,7 +305,7 @@ class SerialChart(Chart):
286
305
  "right",
287
306
  offset=15,
288
307
  color=color,
289
- va="center"
308
+ va="center",
290
309
  )
291
310
  # store labels to check for overlap later
292
311
  line_label_elems.append(lbl)
@@ -486,13 +505,14 @@ class SerialChart(Chart):
486
505
 
487
506
  # Accentuate y=0 || y=baseline
488
507
  # if (self.data.min_val < self.baseline) or self.baseline_annotation:
489
- self.ax.axhline(
490
- y=self.baseline,
491
- linewidth=1,
492
- color="#444444",
493
- zorder=11,
494
- linestyle="--" if self.baseline else "-"
495
- )
508
+ if self.accentuate_baseline:
509
+ self.ax.axhline(
510
+ y=self.baseline,
511
+ linewidth=1,
512
+ color="#444444",
513
+ zorder=11,
514
+ linestyle="--" if self.baseline else "-"
515
+ )
496
516
  if self.baseline_annotation:
497
517
  xy = (to_date(self.data.outer_min_x), self.baseline)
498
518
  # We only allow baseline to be set for single series bar charts
@@ -559,7 +579,7 @@ class SerialChart(Chart):
559
579
  ymax=ymax + padding_top)
560
580
 
561
581
  self.ax.yaxis.set_major_formatter(y_formatter)
562
- self.ax.yaxis.grid(True)
582
+ self.ax.yaxis.grid(self.grid)
563
583
 
564
584
  if ymin > self.baseline and self.allow_broken_y_axis:
565
585
  self._mark_broken_axis()
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: newsworthycharts
3
- Version: 1.70.2
3
+ Version: 1.71.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.70.2.tar.gz
6
+ Download-URL: https://github.com/jplusplus/newsworthycharts/archive/1.71.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
@@ -174,6 +174,14 @@ These settings are available for all chart types:
174
174
 
175
175
  _ Inherits from SerialChart _
176
176
 
177
+ **BumpChart**
178
+
179
+ _ Inherits from SerialChart _
180
+
181
+ - highlight = None # The label value to of a line to highlight
182
+ - line_marker = "o-" # Matplotlib line marker type.
183
+ - line_marker_size = 5 # Matplotlib line marker size
184
+
177
185
  **BubbleMap**
178
186
 
179
187
  - bubble_size = 1 # The size of the bubbles
@@ -261,6 +269,16 @@ Roadmap
261
269
  Changelog
262
270
  ---------
263
271
 
272
+ - 1.71.1
273
+
274
+ - Allow setting line marker size and style in `BumpChart`
275
+ - Various fixes in `BumpChart`
276
+ - Take font size into account when positioning annotations
277
+
278
+ - 1.71.0
279
+
280
+ - Add `BumpChart`
281
+
264
282
  - 1.70.2
265
283
 
266
284
  - Fix edge case bug in y axis cutoff logic
@@ -1,14 +1,15 @@
1
- newsworthycharts/__init__.py,sha256=wRQAtMtzNzN2_8aMN6-JPjSE44gy1ZL53OyXh4BNvtQ,1160
1
+ newsworthycharts/__init__.py,sha256=FHI9lMZXxj8DQAOroGA-Wh60kaCHGKtJYd9O4fWKOb4,1221
2
2
  newsworthycharts/bubblemap.py,sha256=nkocWmpiFgfjEuJGAsthjY5X7Q56jXWsZHUGXw4PwgE,2587
3
3
  newsworthycharts/categoricalchart.py,sha256=YL3pzq8a7U5F0MpeRIAEwCAHw1BRDyKjoaAhf-UyRDo,18179
4
- newsworthycharts/chart.py,sha256=gAMCXLtQkhOzu93QxeR5GgcoGVEnGddzFgubzsBeZ8Y,35055
4
+ newsworthycharts/chart.py,sha256=8Ys9z-BF5mXJiBx-9_k5yEBrBLA66LscwqhfM5YU9uQ,35807
5
5
  newsworthycharts/choroplethmap.py,sha256=Si-01213rWqDKINkhmKV6x5iSMumQveJfrlCnqYcIJM,8173
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/rankchart.py,sha256=Hv5PyUOfDgaxrzr5RApsE9q6wbd203qbCYqqUjcc_hc,1271
9
10
  newsworthycharts/scatterplot.py,sha256=l2w2JkA_4WzxQG9XG1Pn62IlJOdCMm1VemMiZL0rEfU,4959
10
11
  newsworthycharts/seasonalchart.py,sha256=rr55yqJUkaYDR9Ik98jes6574oY1U8t8LwoLE3gClW4,1967
11
- newsworthycharts/serialchart.py,sha256=_TBZiOyU-TtnnkJGbP4yZcTlypdIpbxHK4AjE4Su3k8,27787
12
+ newsworthycharts/serialchart.py,sha256=zFc5ss3uOC6S61AgsW4Dm3nqeHTaWIxg40LmC1n1yv4,28380
12
13
  newsworthycharts/storage.py,sha256=myERhlpvXyExXxUByBq9eW1bWkCyfH9SwTZbsWSyy3Q,4301
13
14
  newsworthycharts/stripechart.py,sha256=9B6PX2MyLuKNQ8W0OGdKbP0-U32kju0K_NHHwwz_J68,1547
14
15
  newsworthycharts/custom/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -28,8 +29,8 @@ newsworthycharts/rc/newsworthy,sha256=yOIZvYS6PG1u19VMcdtfj9vbihKQsey5IprwqK59Kg
28
29
  newsworthycharts/translations/datawrapper_regions.csv,sha256=fzZcQRX6RFMlNNP8mpgfYNdR3Y0QAlQxDXk8FXTaWWI,9214
29
30
  newsworthycharts/translations/regions.py,sha256=Nv1McQjggD4S3JRu82rDMTG3pqUVR13E5-FBpSYbm98,239
30
31
  newsworthycharts/translations/se_municipalities.csv,sha256=br_mm-IvzQtj_W55_ATREhJ97jWnCweBFlDAVY2EBxA,7098
31
- newsworthycharts-1.70.2.dist-info/LICENSE.txt,sha256=Sq6kGICrehbhC_FolNdXf0djKjTpv3YqjFCIYsxdQN4,1069
32
- newsworthycharts-1.70.2.dist-info/METADATA,sha256=sGu65_A1eTrUDLhtVkIjrMaGBbdjehSwSBI_RoYr6E0,32089
33
- newsworthycharts-1.70.2.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91
34
- newsworthycharts-1.70.2.dist-info/top_level.txt,sha256=dn_kzIj8UgUCMsh1PHdVEQJHVGSsN7Z8YJF-8xXa8n0,17
35
- newsworthycharts-1.70.2.dist-info/RECORD,,
32
+ newsworthycharts-1.71.1.dist-info/LICENSE.txt,sha256=Sq6kGICrehbhC_FolNdXf0djKjTpv3YqjFCIYsxdQN4,1069
33
+ newsworthycharts-1.71.1.dist-info/METADATA,sha256=S3GUG2BAP-Yprx9ANeUNu6uAqH4T_Daem6yPGxCiWAo,32504
34
+ newsworthycharts-1.71.1.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91
35
+ newsworthycharts-1.71.1.dist-info/top_level.txt,sha256=dn_kzIj8UgUCMsh1PHdVEQJHVGSsN7Z8YJF-8xXa8n0,17
36
+ newsworthycharts-1.71.1.dist-info/RECORD,,