如何更改pyplot中Y轴上的标签之间的距离?

时间:2020-09-04 09:47:52

标签: python matplotlib

我正在绘制“旅行时间”,其中x轴上有时间,y轴上有检查点(检查点仅是名称,一个检查点对应一个时间戳)。 自己绘制的代码是:

if checkpoints:
  plt.plot_date(timestamps,checkpoints,color = "b",linestyle='solid')
else:
  plt.plot_date(timestamps,distances,color = "b",linestyle='solid')

时间戳:小时列表:分钟, 检查点:字符串列表, 距离:整数列表

随着检查点之间的距离变化,我将需要在y轴上使用不同间距重新绘制图。我想这可以通过使用距离数组作为第二个参数来实现,但是我不知道如何重命名距离标签,以便它们与检查点相对应。

编辑:

使用的数据:

时间戳:它们由命令datetime.strptime(timestamp, "%H:%M")转换并收集在一个数组中。 输入数据如下:

4:45 4:48 4:51 4:52 4:53 4:54 4:55 4:56 5:15 5:19 5:24 5:25 5:26 5:28 5:29 5:30 5:33 5:35 5:39 5:40 5:42 5:43 5:44 5:45 5:39 5:40 5:46 5:47 5:48 5:50 5:51 5:52

检查点:字符串数组,长度与时间戳相同。它们会定期重复以匹配时间戳:

[ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H','A', 'B', 'C', 'D', 'E', 'F', 'G', 'H','A', 'B', 'C', 'D', 'E', 'F', 'G', 'H' ]

距离:类似于检查点,但它们是整数,而不是字符串。

[ 0, 9, 12, 16, 18, 21, 23, 24, 0, 9, 12, 16, 18, 21, 23, 24, 0, 9, 12, 16, 18, 21, 23, 24, 0, 9, 12, 16, 18, 21, 23, 24 ]

生成的带有检查点和时间戳的输出:

Example 1

我不喜欢检查点之间的平均距离。

我想实现这一点-输出带有距离和时间戳(Y轴上的数字是距检查点A的距离),但带有第一个示例中的标签:

Example 2

1 个答案:

答案 0 :(得分:1)

成功的关键是在检查点的 y 距离中使用, 而不是其文字标签。

您这里需要的数据是:

ts = [
    '4:45', '4:48', '4:51', '4:52', '4:53', '4:54', '4:55', '4:56',
    '5:15', '5:19', '5:24', '5:25', '5:26', '5:28', '5:29', '5:30',
    '5:33', '5:35', '5:39', '5:40', '5:42', '5:43', '5:44', '5:45',
    '5:39', '5:40', '5:46', '5:47', '5:48', '5:50', '5:51', '5:52']
chkDist = [0, 9, 12, 16, 18, 21, 23, 24]
chkLbl  = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']

检查点的距离和标签没有重复。

让我们从数据转换开始。生成具有以下内容的数据框:

    每行
  • 4列(将 ts 切成行,然后进行转换),
  • 索引为 dist
  • 并将字符串转换为 datetime

执行此操作的代码是:

timestamps = pd.DataFrame(np.array(ts).reshape((4, -1)).T,
    index=chkDist).apply(pd.to_datetime)

日期部分是从当天开始的,但实际上没关系。

还将检查点距离和标签转换为系列

chkLabels = pd.Series(chkLbl, index=chkDist)

然后生成您的图片,如下所示:

import matplotlib.pyplot as plt
import matplotlib.dates as mdates

fig, ax = plt.subplots(figsize=(6, 4), constrained_layout=True)
plt.plot_date(timestamps, timestamps.index, color='b', linestyle='solid')
ax.xaxis.set_major_locator(mdates.MinuteLocator(byminute=range(0,60,15)))
ax.xaxis.set_major_formatter(mdates.DateFormatter(fmt='%H:%M'))
plt.xticks(rotation=30)
for dist, lbl in chkLabels.iteritems():
    plt.text(xLbl, dist, lbl, ha='center', va='center')
ax.set_yticks(chkDist, minor=True)
plt.grid(which='minor', linestyle='--')
plt.grid(which='major')
plt.show()

请注意,时间戳是一个 DataFrame ,因此从每个列开始 生成了单独的行。 我使用了 MinuteLocator 每隔15分钟就有一个 x 标签, DateFormatter 对其进行格式化。

要打印检查点标签,我使用了附加循环,遍历 chkLabels 并打印每个标签。

但是请注意, plt.text 的文本坐标表示为 数据坐标,所以:

  • y 坐标取自 chkLabels 的索引,
  • x 坐标表示为最短时间-10分钟

最后一步是打印网格。对于我使用的次要行 从 chkDist 提取的 set_yticks y 。然后我叫 plt.grid , 分别针对次要行,并明确指定了线型, 以及主要行,具有默认属性。

对于您的数据,我得到了以下结果:

enter image description here

请注意,检查点标签有时彼此非常靠近(在 这种情况是 G H )。 因此,如果它们彼此重叠,则应修改代码 仅打印选定的标签通过删除一些元素 chkLabels