Skip to content

Commit ce7c539

Browse files
authored
Merge pull request #13760 from meeseeksmachine/auto-backport-of-pr-13719-on-v3.1.x
Backport PR #13719 on branch v3.1.x (Doc: Update timeline example)
2 parents a3526d4 + 4c91d7d commit ce7c539

File tree

2 files changed

+94
-45
lines changed

2 files changed

+94
-45
lines changed

.flake8

+1
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ per-file-ignores =
145145
examples/lines_bars_and_markers/span_regions.py: E402
146146
examples/lines_bars_and_markers/stem_plot.py: E402
147147
examples/lines_bars_and_markers/step_demo.py: E402
148+
examples/lines_bars_and_markers/timeline.py: E402
148149
examples/misc/agg_buffer.py: E402
149150
examples/misc/anchored_artists.py: E501
150151
examples/misc/contour_manual.py: E501

examples/lines_bars_and_markers/timeline.py

+93-45
Original file line numberDiff line numberDiff line change
@@ -15,57 +15,105 @@
1515
import matplotlib.dates as mdates
1616
from datetime import datetime
1717

18-
# A list of Matplotlib releases and their dates
19-
# Taken from https://api.github.com/repos/matplotlib/matplotlib/releases
20-
names = ['v2.2.2', 'v2.2.1', 'v2.2.0', 'v2.1.2', 'v2.1.1', 'v2.1.0', 'v2.0.2',
21-
'v2.0.1', 'v2.0.0', 'v1.5.3', 'v1.5.2', 'v1.5.1', 'v1.5.0', 'v1.4.3',
22-
'v1.4.2', 'v1.4.1', 'v1.4.0']
23-
24-
dates = ['2018-03-17T03:00:07Z', '2018-03-16T22:06:39Z',
25-
'2018-03-06T12:53:32Z', '2018-01-18T04:56:47Z',
26-
'2017-12-10T04:47:38Z', '2017-10-07T22:35:12Z',
27-
'2017-05-10T02:11:15Z', '2017-05-02T01:59:49Z',
28-
'2017-01-17T02:59:36Z', '2016-09-09T03:00:52Z',
29-
'2016-07-03T15:52:01Z', '2016-01-10T22:38:50Z',
30-
'2015-10-29T21:40:23Z', '2015-02-16T04:22:54Z',
31-
'2014-10-26T03:24:13Z', '2014-10-18T18:56:23Z',
32-
'2014-08-26T21:06:04Z']
33-
dates = [datetime.strptime(ii, "%Y-%m-%dT%H:%M:%SZ") for ii in dates]
18+
try:
19+
# Try to fetch a list of Matplotlib releases and their dates
20+
# from https://api.github.com/repos/matplotlib/matplotlib/releases
21+
import urllib.request
22+
import json
23+
24+
url = 'https://api.github.com/repos/matplotlib/matplotlib/releases'
25+
url += '?per_page=100'
26+
data = json.loads(urllib.request.urlopen(url, timeout=.4).read().decode())
27+
28+
dates = []
29+
names = []
30+
for item in data:
31+
if 'rc' not in item['tag_name'] and 'b' not in item['tag_name']:
32+
dates.append(item['published_at'].split("T")[0])
33+
names.append(item['tag_name'])
34+
# Convert date strings (e.g. 2014-10-18) to datetime
35+
dates = [datetime.strptime(d, "%Y-%m-%d") for d in dates]
36+
37+
except Exception:
38+
# In case the above fails, e.g. because of missing internet connection
39+
# use the following lists as fallback.
40+
names = ['v2.2.4', 'v3.0.3', 'v3.0.2', 'v3.0.1', 'v3.0.0', 'v2.2.3',
41+
'v2.2.2', 'v2.2.1', 'v2.2.0', 'v2.1.2', 'v2.1.1', 'v2.1.0',
42+
'v2.0.2', 'v2.0.1', 'v2.0.0', 'v1.5.3', 'v1.5.2', 'v1.5.1',
43+
'v1.5.0', 'v1.4.3', 'v1.4.2', 'v1.4.1', 'v1.4.0']
44+
45+
dates = ['2019-02-26', '2019-02-26', '2018-11-10', '2018-11-10',
46+
'2018-09-18', '2018-08-10', '2018-03-17', '2018-03-16',
47+
'2018-03-06', '2018-01-18', '2017-12-10', '2017-10-07',
48+
'2017-05-10', '2017-05-02', '2017-01-17', '2016-09-09',
49+
'2016-07-03', '2016-01-10', '2015-10-29', '2015-02-16',
50+
'2014-10-26', '2014-10-18', '2014-08-26']
51+
52+
# Convert date strings (e.g. 2014-10-18) to datetime
53+
dates = [datetime.strptime(d, "%Y-%m-%d") for d in dates]
3454

3555
##############################################################################
36-
# Next, we'll iterate through each date and plot it on a horizontal line.
37-
# We'll add some styling to the text so that overlaps aren't as strong.
56+
# Next, we'll create a `~.Axes.stem` plot with some variation in levels as to
57+
# distinguish even close-by events. In contrast to a usual stem plot, we will
58+
# shift the markers to the baseline for visual emphasis on the one-dimensional
59+
# nature of the time line.
60+
# For each event, we add a text label via `~.Axes.annotate`, which is offset
61+
# in units of points from the tip of the event line.
3862
#
3963
# Note that Matplotlib will automatically plot datetime inputs.
4064

41-
levels = np.array([-5, 5, -3, 3, -1, 1])
42-
fig, ax = plt.subplots(figsize=(8, 5))
43-
44-
# Create the base line
45-
start = min(dates)
46-
stop = max(dates)
47-
ax.plot((start, stop), (0, 0), 'k', alpha=.5)
48-
49-
# Iterate through releases annotating each one
50-
for ii, (iname, idate) in enumerate(zip(names, dates)):
51-
level = levels[ii % 6]
52-
vert = 'top' if level < 0 else 'bottom'
53-
54-
ax.scatter(idate, 0, s=100, facecolor='w', edgecolor='k', zorder=9999)
55-
# Plot a line up to the text
56-
ax.plot((idate, idate), (0, level), c='r', alpha=.7)
57-
# Give the text a faint background and align it properly
58-
ax.text(idate, level, iname,
59-
horizontalalignment='right', verticalalignment=vert, fontsize=14,
60-
backgroundcolor=(1., 1., 1., .3))
65+
66+
# Choose some nice levels
67+
levels = np.tile([-5, 5, -3, 3, -1, 1],
68+
int(np.ceil(len(dates)/6)))[:len(dates)]
69+
70+
# Create figure and plot a stem plot with the date
71+
fig, ax = plt.subplots(figsize=(8.8, 4), constrained_layout=True)
6172
ax.set(title="Matplotlib release dates")
62-
# Set the xticks formatting
63-
# format xaxis with 3 month intervals
64-
ax.get_xaxis().set_major_locator(mdates.MonthLocator(interval=3))
73+
74+
markerline, stemline, baseline = ax.stem(dates, levels,
75+
linefmt="C3-", basefmt="k-",
76+
use_line_collection=True)
77+
78+
plt.setp(markerline, mec="k", mfc="w", zorder=3)
79+
80+
# Shift the markers to the baseline by replacing the y-data by zeros.
81+
markerline.set_ydata(np.zeros(len(dates)))
82+
83+
# annotate lines
84+
vert = np.array(['top', 'bottom'])[(levels > 0).astype(int)]
85+
for d, l, r, va in zip(dates, levels, names, vert):
86+
ax.annotate(r, xy=(d, l), xytext=(-3, np.sign(l)*3),
87+
textcoords="offset points", va=va, ha="right")
88+
89+
# format xaxis with 4 month intervals
90+
ax.get_xaxis().set_major_locator(mdates.MonthLocator(interval=4))
6591
ax.get_xaxis().set_major_formatter(mdates.DateFormatter("%b %Y"))
66-
fig.autofmt_xdate()
92+
plt.setp(ax.get_xticklabels(), rotation=30, ha="right")
93+
94+
# remove y axis and spines
95+
ax.get_yaxis().set_visible(False)
96+
for spine in ["left", "top", "right"]:
97+
ax.spines[spine].set_visible(False)
6798

68-
# Remove components for a cleaner look
69-
plt.setp((ax.get_yticklabels() + ax.get_yticklines() +
70-
list(ax.spines.values())), visible=False)
99+
ax.margins(y=0.1)
71100
plt.show()
101+
102+
103+
#############################################################################
104+
#
105+
# ------------
106+
#
107+
# References
108+
# """"""""""
109+
#
110+
# The use of the following functions, methods and classes is shown
111+
# in this example:
112+
113+
import matplotlib
114+
matplotlib.axes.Axes.stem
115+
matplotlib.axes.Axes.annotate
116+
matplotlib.axis.Axis.set_major_locator
117+
matplotlib.axis.Axis.set_major_formatter
118+
matplotlib.dates.MonthLocator
119+
matplotlib.dates.DateFormatter

0 commit comments

Comments
 (0)