|
49 | 49 | '2014-10-26', '2014-10-18', '2014-08-26'] |
50 | 50 |
|
51 | 51 | dates = [datetime.strptime(d, "%Y-%m-%d") for d in dates] # Convert strs to dates. |
| 52 | +releases = [tuple(release.split('.')) for release in releases] # Split by component. |
52 | 53 | dates, releases = zip(*sorted(zip(dates, releases))) # Sort by increasing date. |
53 | 54 |
|
54 | 55 | # %% |
|
61 | 62 | # |
62 | 63 | # Note that Matplotlib will automatically plot datetime inputs. |
63 | 64 |
|
64 | | -# Choose some nice levels: alternate minor releases between top and bottom, and |
65 | | -# progressievly shorten the stems for bugfix releases. |
| 65 | +# Choose some nice levels: alternate meso releases between top and bottom, and |
| 66 | +# progressively shorten the stems for micro releases. |
66 | 67 | levels = [] |
67 | | -major_minor_releases = sorted({release[:3] for release in releases}) |
| 68 | +macro_meso_releases = sorted({release[:2] for release in releases}) |
68 | 69 | 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 |
| 70 | + macro_meso = release[:2] |
| 71 | + micro = int(release[2]) |
| 72 | + h = 1 + 0.8 * (5 - micro) |
| 73 | + level = h if macro_meso_releases.index(macro_meso) % 2 == 0 else -h |
73 | 74 | levels.append(level) |
74 | 75 |
|
| 76 | + |
| 77 | +def is_feature(release): |
| 78 | + """Return whether a version (split into components) is a feature release.""" |
| 79 | + return release[-1] == '0' |
| 80 | + |
| 81 | + |
75 | 82 | # The figure and the axes. |
76 | 83 | fig, ax = plt.subplots(figsize=(8.8, 4), layout="constrained") |
77 | 84 | ax.set(title="Matplotlib release dates") |
78 | 85 |
|
79 | 86 | # The vertical stems. |
80 | 87 | ax.vlines(dates, 0, levels, |
81 | | - color=[("tab:red", 1 if release.endswith(".0") else .5) |
82 | | - for release in releases]) |
| 88 | + color=[("tab:red", 1 if is_feature(release) else .5) for release in releases]) |
83 | 89 | # The baseline. |
84 | 90 | ax.axhline(0, c="black") |
85 | 91 | # 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") |
| 92 | +meso_dates = [date for date, release in zip(dates, releases) if is_feature(release)] |
| 93 | +micro_dates = [date for date, release in zip(dates, releases) |
| 94 | + if not is_feature(release)] |
| 95 | +ax.plot(micro_dates, np.zeros_like(micro_dates), "ko", mfc="white") |
| 96 | +ax.plot(meso_dates, np.zeros_like(meso_dates), "ko", mfc="tab:red") |
90 | 97 |
|
91 | 98 | # Annotate the lines. |
92 | 99 | for date, level, release in zip(dates, levels, releases): |
93 | | - ax.annotate(release, xy=(date, level), |
| 100 | + version_str = '.'.join(release) |
| 101 | + ax.annotate(version_str, xy=(date, level), |
94 | 102 | xytext=(-3, np.sign(level)*3), textcoords="offset points", |
95 | 103 | verticalalignment="bottom" if level > 0 else "top", |
96 | | - weight="bold" if release.endswith(".0") else "normal", |
| 104 | + weight="bold" if is_feature(release) else "normal", |
97 | 105 | bbox=dict(boxstyle='square', pad=0, lw=0, fc=(1, 1, 1, 0.7))) |
98 | 106 |
|
99 | | -ax.yaxis.set(major_locator=mdates.YearLocator(), |
| 107 | +ax.xaxis.set(major_locator=mdates.YearLocator(), |
100 | 108 | major_formatter=mdates.DateFormatter("%Y")) |
101 | 109 |
|
102 | 110 | # Remove the y-axis and some spines. |
|
0 commit comments