简体   繁体   中英

Timeline of events — setting annotation location

I'm trying to adapt the code presented here to better fit what I need. I have to display long annotations, so I'd like to show them starting from the "edge" of the stem line that is further in relation to the y axis, adding some space if the text gets on top of the vertical line. I think I can explain that by saying that instead of defining where the text starts, I'd like to set when it should end. I thought about just changing the ['top', 'bottom'] part of the code to ['bottom', 'top'], but that didn't quite work.

This is a reproducible sample code:

import matplotlib.pyplot as plt
import numpy as np
import matplotlib.dates as mdates
from datetime import datetime


names = ['v2.2.4', 'v3.0.3', 'v3.0.2', 'v3.0.1', 'v3.0.0', 'v2.2.3',
        'v2.2.2', 'v2.2.1', 'v2.2.0', 'v2.1.2', 'v2.1.1', 'v2.1.0',
        'v2.0.2', 'v2.0.1', 'v2.0.0', 'v1.5.3', 'v1.5.2', 'v1.5.1',
        'v1.5.0', 'v1.4.3', 'v1.4.2', 'v1.4.1', 'v1.4.0']

dates = ['2019-02-26', '2019-02-26', '2018-11-10', '2018-11-10',
            '2018-09-18', '2018-08-10', '2018-03-17', '2018-03-16',
            '2018-03-06', '2018-01-18', '2017-12-10', '2017-10-07',
            '2017-05-10', '2017-05-02', '2017-01-17', '2016-09-09',
            '2016-07-03', '2016-01-10', '2015-10-29', '2015-02-16',
            '2014-10-26', '2014-10-18', '2014-08-26']

names = [name+"very_very_long_long" for name in names]

# Convert date strings (e.g. 2014-10-18) to datetime
dates = [datetime.strptime(d, "%Y-%m-%d") for d in dates]


# Choose some nice levels
levels = np.tile([-5, 5, -3, 3, -1, 1],
                 int(np.ceil(len(dates)/6)))[:len(dates)]

# Create figure and plot a stem plot with the date
fig, ax = plt.subplots(figsize=(8.8, 4), constrained_layout=True)
ax.set(title="Matplotlib release dates")

markerline, stemline, baseline = ax.stem(dates, levels,
                                         linefmt="C3-", basefmt="k-",
                                         use_line_collection=True)

plt.setp(markerline, mec="k", mfc="w", zorder=3)

# Shift the markers to the baseline by replacing the y-data by zeros.
markerline.set_ydata(np.zeros(len(dates)))

# annotate lines
vert = np.array(['bottom', 'top'])[(levels > 0).astype(int)]
for d, l, r, va in zip(dates, levels, names, vert):
    ax.annotate(r, xy=(d, l), xytext=(-3, np.sign(l)*3),
                textcoords="offset points", va=va, ha="right", rotation=90)

# format xaxis with 4 month intervals
# ax.get_xaxis().set_major_locator(mdates.MonthLocator(interval=4))
# ax.get_xaxis().set_major_formatter(mdates.DateFormatter("%b %Y"))
# plt.setp(ax.get_xticklabels(), rotation=30, ha="right")

# remove y axis and spines
ax.get_yaxis().set_visible(False)
for spine in ["left", "top", "right"]:
    ax.spines[spine].set_visible(False)

# ax.margins(y=0.1)
plt.show()

在此处输入图像描述

I've been trying to use this lib , but so far it just creates a new whole mess cause I'm probably not using it properly.

I don't have much experience with this kind of graph, but I came up with two ideas: one is to place the string horizontally and position it at the top of the level. The other is to radically switch the axes and make it a vertical graph.

1)Horizontal and centered string

for d, l, r, va in zip(dates, levels, names, vert):
    ax.annotate(r, xy=(d, l), xytext=(60, np.sign(l)*15), 
                textcoords="offset points", va=va, ha="right")

在此处输入图像描述

  1. Vertical type with the XY axes swapped
fig, ax = plt.subplots(figsize=(6, 12), constrained_layout=True)
# define bounding box
boxdic={'facecolor':'0.9',
        'edgecolor':'0.6',
        'boxstyle':'round',
        'linewidth':1}

arrowprops = dict(
    arrowstyle="->",
    connectionstyle="angle,angleA=0,angleB=45,rad=10")

arrowprops1 = dict(
    arrowstyle="->",
    connectionstyle="angle,angleA=0,angleB=-45,rad=10")

ax = plt.axes(xlim=(-5,5), ylim=(datetime(2020,1,1,0,0), datetime(2014,1,1,0,0)))
ax.set(title="Matplotlib release dates")
ax.scatter([0]*len(dates), dates, marker='o', color='w', ec='k')

ax.spines['left'].set_position('zero')
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.axes.xaxis.set_visible(False)

for i, (d, n) in enumerate(zip(dates, names)):
    if i % 2 == 0:
        ax.annotate(str("{}".format(n)), xy=(0.1, d),
                    xycoords='data', xytext=(15, 25), textcoords='offset points',
                    color="k", fontsize=10, bbox=boxdic, arrowprops=arrowprops)
    else:
        ax.annotate(str("{}".format(n)), xy=(-0.1, d),
                    xycoords='data', xytext=(-15, 25), textcoords='offset points',
                    color="k", fontsize=10, bbox=boxdic, ha='right', arrowprops=arrowprops1)        

months = mdates.MonthLocator(interval = 6)
months_fmt = mdates.DateFormatter('%Y-%m')
ax.yaxis.set_major_locator(months)
ax.yaxis.set_major_formatter(months_fmt)

plt.show()

在此处输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM