newsworthycharts 1.71.3__tar.gz → 1.71.5__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 (53) hide show
  1. {newsworthycharts-1.71.3/newsworthycharts.egg-info → newsworthycharts-1.71.5}/PKG-INFO +13 -2
  2. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/README.rst +11 -0
  3. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/__init__.py +1 -1
  4. newsworthycharts-1.71.5/newsworthycharts/rankchart.py +232 -0
  5. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/serialchart.py +8 -1
  6. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5/newsworthycharts.egg-info}/PKG-INFO +13 -2
  7. newsworthycharts-1.71.3/newsworthycharts/rankchart.py +0 -115
  8. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/LICENSE.txt +0 -0
  9. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/MANIFEST.in +0 -0
  10. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/bubblemap.py +0 -0
  11. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/categoricalchart.py +0 -0
  12. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/chart.py +0 -0
  13. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/choroplethmap.py +0 -0
  14. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/custom/__init__.py +0 -0
  15. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/custom/climate_cars.py +0 -0
  16. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/datawrapper.py +0 -0
  17. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/lib/__init__.py +0 -0
  18. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/lib/color_fn.py +0 -0
  19. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/lib/colors.py +0 -0
  20. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/lib/datalist.py +0 -0
  21. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/lib/formatter.py +0 -0
  22. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/lib/geography.py +0 -0
  23. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/lib/locator.py +0 -0
  24. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/lib/mimetypes.py +0 -0
  25. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/lib/utils.py +0 -0
  26. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/map.py +0 -0
  27. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/maps/se-4.gpkg +0 -0
  28. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/maps/se-7.gpkg +0 -0
  29. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/rangeplot.py +0 -0
  30. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/rc/newsworthy +0 -0
  31. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/scatterplot.py +0 -0
  32. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/seasonalchart.py +0 -0
  33. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/storage.py +0 -0
  34. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/stripechart.py +0 -0
  35. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/translations/datawrapper_regions.csv +0 -0
  36. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/translations/regions.py +0 -0
  37. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/translations/se_municipalities.csv +0 -0
  38. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts.egg-info/SOURCES.txt +0 -0
  39. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts.egg-info/dependency_links.txt +0 -0
  40. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts.egg-info/not-zip-safe +0 -0
  41. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts.egg-info/requires.txt +0 -0
  42. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts.egg-info/top_level.txt +0 -0
  43. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/setup.cfg +0 -0
  44. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/setup.py +0 -0
  45. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/test/test_categorical_chart.py +0 -0
  46. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/test/test_choropleth_maps.py +0 -0
  47. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/test/test_custom_climate_cars.py +0 -0
  48. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/test/test_data_list.py +0 -0
  49. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/test/test_datawrapper.py +0 -0
  50. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/test/test_main.py +0 -0
  51. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/test/test_rangeplot.py +0 -0
  52. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/test/test_scatterplot.py +0 -0
  53. {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/test/test_serial_chart.py +0 -0
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: newsworthycharts
3
- Version: 1.71.3
3
+ Version: 1.71.5
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.71.3.tar.gz
6
+ Download-URL: https://github.com/jplusplus/newsworthycharts/archive/1.71.5.tar.gz
7
7
  Author: Jens Finnäs and Leo Wallentin, J++ Stockholm
8
8
  Author-email: stockholm@jplusplus.org
9
9
  License: MIT
@@ -179,6 +179,7 @@ _ Inherits from SerialChart _
179
179
 
180
180
  _ Inherits from SerialChart _
181
181
 
182
+ - label_placement = "right" # [left|right|both|outside|legend]
182
183
  - highlight = None # The label value to of a line to highlight
183
184
  - line_marker = "o-" # Matplotlib line marker type.
184
185
  - line_marker_size = 5 # Matplotlib line marker size
@@ -270,6 +271,16 @@ Roadmap
270
271
  Changelog
271
272
  ---------
272
273
 
274
+ - 1.71.5
275
+
276
+ - zorder fixes in BumpChart
277
+ - Add `label_placement` = [left|right|both|outside|legend] to BumpChart. Default is 'right'
278
+ - Use alternating shades of gray in BumpChart
279
+
280
+ - 1.71.4
281
+
282
+ - BumpChart: Use dual colors in line markers when rank is shared
283
+
273
284
  - 1.71.3
274
285
 
275
286
  - Revert 1.71.2 changes to rendering, to make file sizes predictable again
@@ -153,6 +153,7 @@ _ Inherits from SerialChart _
153
153
 
154
154
  _ Inherits from SerialChart _
155
155
 
156
+ - label_placement = "right" # [left|right|both|outside|legend]
156
157
  - highlight = None # The label value to of a line to highlight
157
158
  - line_marker = "o-" # Matplotlib line marker type.
158
159
  - line_marker_size = 5 # Matplotlib line marker size
@@ -244,6 +245,16 @@ Roadmap
244
245
  Changelog
245
246
  ---------
246
247
 
248
+ - 1.71.5
249
+
250
+ - zorder fixes in BumpChart
251
+ - Add `label_placement` = [left|right|both|outside|legend] to BumpChart. Default is 'right'
252
+ - Use alternating shades of gray in BumpChart
253
+
254
+ - 1.71.4
255
+
256
+ - BumpChart: Use dual colors in line markers when rank is shared
257
+
247
258
  - 1.71.3
248
259
 
249
260
  - Revert 1.71.2 changes to rendering, to make file sizes predictable again
@@ -1,4 +1,4 @@
1
- __version__ = "1.71.3"
1
+ __version__ = "1.71.5"
2
2
 
3
3
  from .chart import Chart
4
4
  from .choroplethmap import ChoroplethMap
@@ -0,0 +1,232 @@
1
+ """
2
+ A chart showing ranking over time (like ”most popular baby names”)
3
+ """
4
+ from .serialchart import SerialChart
5
+ from .lib.utils import to_date
6
+ import numpy as np
7
+
8
+
9
+ class BumpChart(SerialChart):
10
+ """Plot a rank chart
11
+
12
+ Data should be a list of iterables of (rank, date string) tuples, eg:
13
+ `[ [("2010-01-01", 2), ("2011-01-01", 3)] ]`, combined with a list of
14
+ labels in the same order
15
+ """
16
+
17
+ def __init__(self, *args, **kwargs):
18
+ label_placement = kwargs.get("label_placement", None)
19
+ if label_placement not in ["legend", "outside"]:
20
+ self.label_placement = "none"
21
+
22
+ super(BumpChart, self).__init__(*args, **kwargs)
23
+
24
+ if self.line_width is None:
25
+ self.line_width = 0.9
26
+ if self.line_marker_size is None:
27
+ self.line_marker_size = 6
28
+ if not label_placement:
29
+ self.label_placement = 'right'
30
+ self.type = "line"
31
+ self.decimals = 0
32
+ self.revert_value_axis = True
33
+ self.ymin = 1
34
+ self.allow_broken_y_axis = False
35
+ self.grid = False
36
+ self.accentuate_baseline = False
37
+
38
+ self.line_marker = "o-"
39
+
40
+ def _get_line_colors(self, i, *args):
41
+ if not self.data:
42
+ # Don't waste time
43
+ return None
44
+ if self.highlight and self.highlight in self.labels and i == self.labels.index(self.highlight):
45
+ return self._nwc_style["strong_color"]
46
+ elif self.colors and i < len(self.colors):
47
+ return self.colors[i]
48
+ # alternate between dark gray and light gray
49
+ if i % 2 == 0:
50
+ return "darkgray"
51
+ else:
52
+ return "lightgray"
53
+
54
+ """
55
+ def _get_marker_fill(self, i):
56
+ pass
57
+ """
58
+
59
+ def _after_add_data(self):
60
+ # Print out every rank
61
+ if self.data.max_val < 30:
62
+ _range = list(range(1, int(self.data.max_val) + 1))
63
+ self.ax.yaxis.set_ticks(_range, _range)
64
+
65
+ # Recolor markers with more than one line passing through
66
+ # (MPL does not allow access to individual markers, so we'll overwrite them)
67
+ for date in self.data.x_points:
68
+ value_colors = {}
69
+ for i, serie in enumerate(self.data):
70
+ values = np.array(self.serie_values[i], dtype=np.float64)
71
+ dates = [x[0] for x in serie]
72
+ color = self._get_line_colors(i)
73
+ if date not in dates:
74
+ continue
75
+ idx = dates.index(date)
76
+ if np.isnan(values[idx]):
77
+ continue
78
+ val = int(values[idx])
79
+ if val not in value_colors:
80
+ value_colors[val] = []
81
+ value_colors[val].append(color)
82
+ for val, colors in value_colors.items():
83
+ if len(colors) < 2:
84
+ continue
85
+ elif len(colors) == 2:
86
+ self.ax.plot(
87
+ to_date(date),
88
+ val,
89
+ self.line_marker,
90
+ markersize=self.line_marker_size,
91
+ color="None",
92
+ fillstyle="left",
93
+ markeredgewidth=0,
94
+ markerfacecolor=colors[0],
95
+ markerfacecoloralt=colors[1],
96
+ zorder=100,
97
+ )
98
+ else:
99
+ self.ax.plot(
100
+ to_date(date),
101
+ val,
102
+ self.line_marker,
103
+ markersize=self.line_marker_size,
104
+ color=self._nwc_style["neutral_color"],
105
+ markeredgewidth=0,
106
+ zorder=100,
107
+ )
108
+ # Add labels
109
+ slots_occupied_right = {
110
+ to_date(k): [] for k in self.data.x_points
111
+ }
112
+ slots_occupied_left = {
113
+ to_date(k): [] for k in self.data.x_points
114
+ }
115
+ # distance between rank ticks
116
+ # y1 = self.ax.transData.transform((0, 1))
117
+ # y2 = self.ax.transData.transform((0, 2))
118
+ # dist = abs(y1[1] - y2[1])
119
+ for i, serie in enumerate(self.data):
120
+ values = np.array(self.serie_values[i], dtype=np.float64)
121
+ dates = [to_date(x[0]) for x in serie]
122
+ color = self._get_line_colors(i)
123
+
124
+ endpoints = [
125
+ (d, values[idx])
126
+ for (idx, d) in enumerate(dates) if idx == len(dates) - 1 or np.isnan(values[idx + 1])
127
+ ]
128
+
129
+ startpoints = []
130
+ if self.label_placement == "both":
131
+ startpoints = [
132
+ (d, values[idx])
133
+ for (idx, d) in enumerate(dates)
134
+ if (idx == 0 or np.isnan(values[idx - 1]) # only if 2 consecutive values come after
135
+ and (idx < len(dates) - 2)
136
+ and not np.isnan(values[idx + 1])
137
+ and not np.isnan(values[idx + 2]))
138
+ ]
139
+ elif self.label_placement == "left":
140
+ startpoints = [
141
+ (d, values[idx])
142
+ for (idx, d) in enumerate(dates)
143
+ if idx == 0 or np.isnan(values[idx - 1])
144
+ ]
145
+
146
+ if self.label_placement in ["left", "both"]:
147
+ # We need to move y spine to the left to make room for labels
148
+ # To save time we'll only measure the with of the longest text string
149
+ # There will be edge cases where shorter strings taker up more space
150
+ longest_sp_label = max([len(str(x[1])) for x in startpoints])
151
+ dummy_text = self.ax.text(0, 0, longest_sp_label, fontsize=self._nwc_style["annotation.fontsize"])
152
+ _bbox = dummy_text.get_window_extent(renderer=self._fig.canvas.get_renderer())
153
+ self.ax.spines['left'].set_position(('outward', _bbox.width * 1.15 + 15)) # Add a bit extra space
154
+ dummy_text.remove()
155
+
156
+ if self.label_placement in ["right", "both"]:
157
+ for ep in endpoints:
158
+ position = ep[1]
159
+ while position in slots_occupied_right[ep[0]]:
160
+ position += 1
161
+ # pos_diff = position - ep[1]
162
+ slots_occupied_right[ep[0]].append(position)
163
+ self._annotate_point(
164
+ self.labels[i],
165
+ # (ep[0], ep[1]),
166
+ (ep[0], position),
167
+ "right",
168
+ offset=15,
169
+ color=color,
170
+ va="center",
171
+ # xytext=(15, -abs(y1[1] - y2[1]) * pos_diff),
172
+ # arrowprops=dict(arrowstyle="->", color=color) if pos_diff > 1 else None,
173
+ zorder=99,
174
+ )
175
+ if self.label_placement in ["left", "both"]:
176
+ for sp in startpoints:
177
+ position = sp[1]
178
+ while position in slots_occupied_left[sp[0]]:
179
+ position += 1
180
+ # pos_diff = position - sp[1]
181
+ slots_occupied_left[sp[0]].append(position)
182
+ self._annotate_point(
183
+ self.labels[i],
184
+ (sp[0], position),
185
+ "left",
186
+ offset=15,
187
+ color=color,
188
+ va="center",
189
+ zorder=99,
190
+ )
191
+ # Add space for labels on the left
192
+
193
+ """
194
+ labels = []
195
+ for i, serie in enumerate(self.data):
196
+ values = np.array(self.serie_values[i], dtype=np.float64)
197
+ dates = [to_date(x[0]) for x in serie]
198
+ color = self._get_line_colors(i)
199
+
200
+ endpoints = [
201
+ (d, values[idx])
202
+ for (idx, d) in enumerate(dates) if idx == len(dates) - 1 or np.isnan(values[idx + 1])
203
+ ]
204
+ for ep in endpoints:
205
+ lbl = self._annotate_point(
206
+ self.labels[i],
207
+ (ep[0], ep[1]),
208
+ "right",
209
+ offset=15,
210
+ color=color,
211
+ va="center",
212
+ # arrowprops=dict(arrowstyle="->", color=color),
213
+ )
214
+ loops = 0
215
+ overlap = True if len(labels) > 0 else False
216
+ while overlap:
217
+ for i, bb in enumerate(labels):
218
+ if i == len(labels) - 1:
219
+ overlap = False
220
+ break
221
+ bbox1 = lbl.get_window_extent()
222
+ bbox2 = labels[i].get_window_extent()
223
+ print(bbox1, bbox2)
224
+ if bbox1.y1 < bbox2.y0 + 10 and bbox1.x1 > bbox2.x0 + 5: # allow for some overlap
225
+ xy1 = lbl.xyann
226
+ lbl.xyann = (xy1[0], xy1[1] + 1)
227
+ break
228
+ loops += 1
229
+ if loops > 500:
230
+ break
231
+ labels.append(lbl)
232
+ """
@@ -52,7 +52,9 @@ class SerialChart(Chart):
52
52
  self.colors = None
53
53
 
54
54
  # Optional: where to place series label
55
- self.label_placement = "legend" # legend|inline|outside|line
55
+ # Could be set already by subclass
56
+ if not hasattr(self, "label_placement"):
57
+ self.label_placement = "legend" # legend|inline|outside|line
56
58
 
57
59
  # Optional: annotate each point with a value label
58
60
  self.value_labels = False
@@ -254,6 +256,9 @@ class SerialChart(Chart):
254
256
  color = self._nwc_style["strong_color"]
255
257
  else:
256
258
  color = self._nwc_style["neutral_color"]
259
+ marker_fill = None
260
+ if hasattr(self, "_get_marker_fill"):
261
+ marker_fill = self._get_marker_fill(i)
257
262
 
258
263
  line, = self.ax.plot(
259
264
  dates,
@@ -261,6 +266,8 @@ class SerialChart(Chart):
261
266
  self.line_marker,
262
267
  markersize=self.line_marker_size,
263
268
  color=color,
269
+ markerfacecolor=marker_fill,
270
+ markeredgewidth=0,
264
271
  zorder=zo,
265
272
  lw=lw,
266
273
  )
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: newsworthycharts
3
- Version: 1.71.3
3
+ Version: 1.71.5
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.71.3.tar.gz
6
+ Download-URL: https://github.com/jplusplus/newsworthycharts/archive/1.71.5.tar.gz
7
7
  Author: Jens Finnäs and Leo Wallentin, J++ Stockholm
8
8
  Author-email: stockholm@jplusplus.org
9
9
  License: MIT
@@ -179,6 +179,7 @@ _ Inherits from SerialChart _
179
179
 
180
180
  _ Inherits from SerialChart _
181
181
 
182
+ - label_placement = "right" # [left|right|both|outside|legend]
182
183
  - highlight = None # The label value to of a line to highlight
183
184
  - line_marker = "o-" # Matplotlib line marker type.
184
185
  - line_marker_size = 5 # Matplotlib line marker size
@@ -270,6 +271,16 @@ Roadmap
270
271
  Changelog
271
272
  ---------
272
273
 
274
+ - 1.71.5
275
+
276
+ - zorder fixes in BumpChart
277
+ - Add `label_placement` = [left|right|both|outside|legend] to BumpChart. Default is 'right'
278
+ - Use alternating shades of gray in BumpChart
279
+
280
+ - 1.71.4
281
+
282
+ - BumpChart: Use dual colors in line markers when rank is shared
283
+
273
284
  - 1.71.3
274
285
 
275
286
  - Revert 1.71.2 changes to rendering, to make file sizes predictable again
@@ -1,115 +0,0 @@
1
- """
2
- A chart showing ranking over time (like ”most popular baby names”)
3
- """
4
- from .serialchart import SerialChart
5
- from .lib.utils import to_date
6
- import numpy as np
7
-
8
-
9
- class BumpChart(SerialChart):
10
- """Plot a rank chart
11
-
12
- Data should be a list of iterables of (rank, date string) tuples, eg:
13
- `[ [("2010-01-01", 2), ("2011-01-01", 3)] ]`, combined with a list of
14
- labels in the same order
15
- """
16
-
17
- def __init__(self, *args, **kwargs):
18
- super(BumpChart, self).__init__(*args, **kwargs)
19
-
20
- if self.line_width is None:
21
- self.line_width = 0.9
22
- self.label_placement = 'none'
23
- self.type = "line"
24
- self.decimals = 0
25
- self.revert_value_axis = True
26
- self.ymin = 1
27
- self.allow_broken_y_axis = False
28
- self.grid = False
29
- self.accentuate_baseline = False
30
-
31
- self.line_marker = "o-"
32
- self.line_marker_size = 5
33
-
34
- def _get_line_colors(self, i, *args):
35
- if not self.data:
36
- # Don't waste time
37
- return None
38
- if self.highlight and self.highlight in self.labels and i == self.labels.index(self.highlight):
39
- return self._nwc_style["strong_color"]
40
- elif self.colors and i < len(self.colors):
41
- return self.colors[i]
42
- return self._nwc_style["neutral_color"]
43
-
44
- def _after_add_data(self):
45
- # Print out every rank
46
- if self.data.max_val < 30:
47
- _range = list(range(1, int(self.data.max_val) + 1))
48
- self.ax.yaxis.set_ticks(_range, _range)
49
- # Add labels
50
- slots_occupied = {
51
- to_date(k): [] for k in self.data.x_points
52
- }
53
- for i, serie in enumerate(self.data):
54
- values = np.array(self.serie_values[i], dtype=np.float64)
55
- dates = [to_date(x[0]) for x in serie]
56
- color = self._get_line_colors(i)
57
-
58
- endpoints = [
59
- (d, values[idx])
60
- for (idx, d) in enumerate(dates) if idx == len(dates) - 1 or np.isnan(values[idx + 1])
61
- ]
62
- for ep in endpoints:
63
- position = ep[1]
64
- while position in slots_occupied[ep[0]]:
65
- position += 1
66
- slots_occupied[ep[0]].append(position)
67
- self._annotate_point(
68
- self.labels[i],
69
- (ep[0], position),
70
- "right",
71
- offset=15,
72
- color=color,
73
- va="center",
74
- # arrowprops=dict(arrowstyle="->", color=color),
75
- )
76
- """
77
- labels = []
78
- for i, serie in enumerate(self.data):
79
- values = np.array(self.serie_values[i], dtype=np.float64)
80
- dates = [to_date(x[0]) for x in serie]
81
- color = self._get_line_colors(i)
82
-
83
- endpoints = [
84
- (d, values[idx])
85
- for (idx, d) in enumerate(dates) if idx == len(dates) - 1 or np.isnan(values[idx + 1])
86
- ]
87
- for ep in endpoints:
88
- lbl = self._annotate_point(
89
- self.labels[i],
90
- (ep[0], ep[1]),
91
- "right",
92
- offset=15,
93
- color=color,
94
- va="center",
95
- # arrowprops=dict(arrowstyle="->", color=color),
96
- )
97
- loops = 0
98
- overlap = True if len(labels) > 0 else False
99
- while overlap:
100
- for i, bb in enumerate(labels):
101
- if i == len(labels) - 1:
102
- overlap = False
103
- break
104
- bbox1 = lbl.get_window_extent()
105
- bbox2 = labels[i].get_window_extent()
106
- print(bbox1, bbox2)
107
- if bbox1.y1 < bbox2.y0 + 10 and bbox1.x1 > bbox2.x0 + 5: # allow for some overlap
108
- xy1 = lbl.xyann
109
- lbl.xyann = (xy1[0], xy1[1] + 1)
110
- break
111
- loops += 1
112
- if loops > 500:
113
- break
114
- labels.append(lbl)
115
- """