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.
- {newsworthycharts-1.71.3/newsworthycharts.egg-info → newsworthycharts-1.71.5}/PKG-INFO +13 -2
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/README.rst +11 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/__init__.py +1 -1
- newsworthycharts-1.71.5/newsworthycharts/rankchart.py +232 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/serialchart.py +8 -1
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5/newsworthycharts.egg-info}/PKG-INFO +13 -2
- newsworthycharts-1.71.3/newsworthycharts/rankchart.py +0 -115
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/LICENSE.txt +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/MANIFEST.in +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/bubblemap.py +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/categoricalchart.py +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/chart.py +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/choroplethmap.py +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/custom/__init__.py +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/custom/climate_cars.py +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/datawrapper.py +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/lib/__init__.py +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/lib/color_fn.py +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/lib/colors.py +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/lib/datalist.py +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/lib/formatter.py +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/lib/geography.py +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/lib/locator.py +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/lib/mimetypes.py +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/lib/utils.py +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/map.py +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/maps/se-4.gpkg +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/maps/se-7.gpkg +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/rangeplot.py +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/rc/newsworthy +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/scatterplot.py +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/seasonalchart.py +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/storage.py +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/stripechart.py +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/translations/datawrapper_regions.csv +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/translations/regions.py +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/translations/se_municipalities.csv +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts.egg-info/SOURCES.txt +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts.egg-info/dependency_links.txt +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts.egg-info/not-zip-safe +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts.egg-info/requires.txt +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts.egg-info/top_level.txt +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/setup.cfg +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/setup.py +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/test/test_categorical_chart.py +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/test/test_choropleth_maps.py +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/test/test_custom_climate_cars.py +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/test/test_data_list.py +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/test/test_datawrapper.py +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/test/test_main.py +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/test/test_rangeplot.py +0 -0
- {newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/test/test_scatterplot.py +0 -0
- {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
|
+
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.
|
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
|
@@ -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
|
-
|
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
|
+
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.
|
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
|
-
"""
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts/translations/regions.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
{newsworthycharts-1.71.3 → newsworthycharts-1.71.5}/newsworthycharts.egg-info/dependency_links.txt
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|