Skip to content

Commit 394b80d

Browse files
authored
Merge pull request matplotlib#28014 from anntzer/tl
Improve timeline example.
2 parents 16d90d8 + 0aa101e commit 394b80d

File tree

1 file changed

+44
-34
lines changed

1 file changed

+44
-34
lines changed

galleries/examples/lines_bars_and_markers/timeline.py

Lines changed: 44 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -28,31 +28,28 @@
2828
data = json.loads(urllib.request.urlopen(url, timeout=1).read().decode())
2929

3030
dates = []
31-
names = []
31+
releases = []
3232
for item in data:
3333
if 'rc' not in item['tag_name'] and 'b' not in item['tag_name']:
3434
dates.append(item['published_at'].split("T")[0])
35-
names.append(item['tag_name'])
36-
# Convert date strings (e.g. 2014-10-18) to datetime
37-
dates = [datetime.strptime(d, "%Y-%m-%d") for d in dates]
35+
releases.append(item['tag_name'].lstrip("v"))
3836

3937
except Exception:
4038
# In case the above fails, e.g. because of missing internet connection
4139
# use the following lists as fallback.
42-
names = ['v2.2.4', 'v3.0.3', 'v3.0.2', 'v3.0.1', 'v3.0.0', 'v2.2.3',
43-
'v2.2.2', 'v2.2.1', 'v2.2.0', 'v2.1.2', 'v2.1.1', 'v2.1.0',
44-
'v2.0.2', 'v2.0.1', 'v2.0.0', 'v1.5.3', 'v1.5.2', 'v1.5.1',
45-
'v1.5.0', 'v1.4.3', 'v1.4.2', 'v1.4.1', 'v1.4.0']
46-
40+
releases = ['2.2.4', '3.0.3', '3.0.2', '3.0.1', '3.0.0', '2.2.3',
41+
'2.2.2', '2.2.1', '2.2.0', '2.1.2', '2.1.1', '2.1.0',
42+
'2.0.2', '2.0.1', '2.0.0', '1.5.3', '1.5.2', '1.5.1',
43+
'1.5.0', '1.4.3', '1.4.2', '1.4.1', '1.4.0']
4744
dates = ['2019-02-26', '2019-02-26', '2018-11-10', '2018-11-10',
4845
'2018-09-18', '2018-08-10', '2018-03-17', '2018-03-16',
4946
'2018-03-06', '2018-01-18', '2017-12-10', '2017-10-07',
5047
'2017-05-10', '2017-05-02', '2017-01-17', '2016-09-09',
5148
'2016-07-03', '2016-01-10', '2015-10-29', '2015-02-16',
5249
'2014-10-26', '2014-10-18', '2014-08-26']
5350

54-
# Convert date strings (e.g. 2014-10-18) to datetime
55-
dates = [datetime.strptime(d, "%Y-%m-%d") for d in dates]
51+
dates = [datetime.strptime(d, "%Y-%m-%d") for d in dates] # Convert strs to dates.
52+
dates, releases = zip(*sorted(zip(dates, releases))) # Sort by increasing date.
5653

5754
# %%
5855
# Next, we'll create a stem plot with some variation in levels as to
@@ -64,32 +61,45 @@
6461
#
6562
# Note that Matplotlib will automatically plot datetime inputs.
6663

67-
68-
# Choose some nice levels
69-
levels = np.tile([-5, 5, -3, 3, -1, 1],
70-
int(np.ceil(len(dates)/6)))[:len(dates)]
71-
72-
# Create figure and plot a stem plot with the date
64+
# Choose some nice levels: alternate minor releases between top and bottom, and
65+
# progressievly shorten the stems for bugfix releases.
66+
levels = []
67+
major_minor_releases = sorted({release[:3] for release in releases})
68+
for release in releases:
69+
major_minor = release[:3]
70+
bugfix = int(release[4])
71+
h = 1 + 0.8 * (5 - bugfix)
72+
level = h if major_minor_releases.index(major_minor) % 2 == 0 else -h
73+
levels.append(level)
74+
75+
# The figure and the axes.
7376
fig, ax = plt.subplots(figsize=(8.8, 4), layout="constrained")
7477
ax.set(title="Matplotlib release dates")
7578

76-
ax.vlines(dates, 0, levels, color="tab:red") # The vertical stems.
77-
ax.plot(dates, np.zeros_like(dates), "-o",
78-
color="k", markerfacecolor="w") # Baseline and markers on it.
79-
80-
# annotate lines
81-
for d, l, r in zip(dates, levels, names):
82-
ax.annotate(r, xy=(d, l),
83-
xytext=(-3, np.sign(l)*3), textcoords="offset points",
84-
horizontalalignment="right",
85-
verticalalignment="bottom" if l > 0 else "top")
86-
87-
# format x-axis with 4-month intervals
88-
ax.xaxis.set_major_locator(mdates.MonthLocator(interval=4))
89-
ax.xaxis.set_major_formatter(mdates.DateFormatter("%b %Y"))
90-
plt.setp(ax.get_xticklabels(), rotation=30, ha="right")
91-
92-
# remove y-axis and spines
79+
# The vertical stems.
80+
ax.vlines(dates, 0, levels,
81+
color=[("tab:red", 1 if release.endswith(".0") else .5)
82+
for release in releases])
83+
# The baseline.
84+
ax.axhline(0, c="black")
85+
# The markers on the baseline.
86+
minor_dates = [date for date, release in zip(dates, releases) if release[-1] == '0']
87+
bugfix_dates = [date for date, release in zip(dates, releases) if release[-1] != '0']
88+
ax.plot(bugfix_dates, np.zeros_like(bugfix_dates), "ko", mfc="white")
89+
ax.plot(minor_dates, np.zeros_like(minor_dates), "ko", mfc="tab:red")
90+
91+
# Annotate the lines.
92+
for date, level, release in zip(dates, levels, releases):
93+
ax.annotate(release, xy=(date, level),
94+
xytext=(-3, np.sign(level)*3), textcoords="offset points",
95+
verticalalignment="bottom" if level > 0 else "top",
96+
weight="bold" if release.endswith(".0") else "normal",
97+
bbox=dict(boxstyle='square', pad=0, lw=0, fc=(1, 1, 1, 0.7)))
98+
99+
ax.yaxis.set(major_locator=mdates.YearLocator(),
100+
major_formatter=mdates.DateFormatter("%Y"))
101+
102+
# Remove the y-axis and some spines.
93103
ax.yaxis.set_visible(False)
94104
ax.spines[["left", "top", "right"]].set_visible(False)
95105

0 commit comments

Comments
 (0)