matplotlib:值出现时绘制特殊符号

2 投票
1 回答
1494 浏览
提问于 2025-04-17 13:47

我想用 matplotlib 来画一个延迟列表的图,具体要求是:

  • X轴 上显示延迟在列表中的位置
  • Y轴 上显示实际的延迟值

在我的列表中,有一个 特殊值 'L',我希望每次出现这个值时,在 X轴上用 红色叉 标记出来。

我该怎么做才能实现这个呢?

1 个回答

2

有很多不同的方法可以做到这一点。

首先,我们先把你的数据变成一个numpy数组,这样我们就可以使用布尔索引。这种方法可以更方便地从数据中挑选出被标记的 "L" 值。

理想情况下,你应该把数据转换成一个掩码数组,把 "L" 值掩盖起来(并且让所有值都是浮点数,而不是混合的数据类型)。不过为了简单起见,这里我们就用一个对象数组,这样你可以同时使用字符串和浮点数。

import matplotlib.pyplot as plt
import numpy as np

delays = np.array([0.5, 2.3, 'L', 0.9, 'L', 2], dtype=object)
x = np.arange(delays.size)

fig, ax = plt.subplots()
ax.plot(x[delays != 'L'], delays[delays != 'L'], 'bo')

# Expand axis limits by 0.5 in all directions for easier viewing
limits = np.array(ax.axis())
ax.axis(limits + [-0.5, 0.5, -0.5, 0.5])

flag_positions = x[delays == 'L']
ax.plot(flag_positions, np.zeros_like(flag_positions), 'rx', 
        clip_on=False, mew=2)

plt.show()

在这里输入图片描述

但是,红色的 x 标记是在固定的 y 位置上,如果我们平移或缩放图表,它们就会偏离 x 轴。

你可以通过使用自定义变换来解决这个问题。在这种情况下,我们希望 x 坐标使用“正常”的数据坐标(ax.transData),而 y 坐标使用轴坐标系统(例如,0-1,其中0是底部,1是顶部:ax.transAxes)。为此,我们将使用 BlendedGenericTransform,它使用两种不同的变换:一种用于 x 坐标,另一种用于 y 坐标。

所以,如果你希望红色的 x 标记无论如何都保持在 x 轴上,不受图表平移或缩放的影响,你可以这样做:

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.transforms import BlendedGenericTransform

delays = np.array([0.5, 2.3, 'L', 0.9, 'L', 2], dtype=object)
x = np.arange(delays.size)

fig, ax = plt.subplots()
ax.plot(x[delays != 'L'], delays[delays != 'L'], 'bo')

flags = x[delays == 'L']
ax.plot(flags, np.zeros_like(flags), 'rx', clip_on=False, mew=2,
        transform=BlendedGenericTransform(ax.transData, ax.transAxes))

# Expand axis limits by 0.5 in all directions for easier viewing
limits = np.array(ax.axis())
ax.axis(limits + [-0.5, 0.5, -0.5, 0.5])

plt.show()

在这里输入图片描述

我们可以通过使用掩码数组来让事情变得更清晰(也可以看看 pandas)。使用掩码数组(或者再次提到的 pandas)比使用混合字符串和浮点值的对象数组更好,能够更好地表示缺失数据。例如:

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.transforms import BlendedGenericTransform

delays = [0.5, 2.3, 'L', 0.9, 'L', 2]
delays = [item if item != 'L' else np.nan for item in delays]
delays = np.ma.masked_invalid(delays)

fig, ax = plt.subplots()

ax.plot(delays, 'bo')

flags = delays.mask.nonzero()
ax.plot(flags, np.zeros_like(flags), 'rx', clip_on=False, mew=2,
        transform=BlendedGenericTransform(ax.transData, ax.transAxes))

# Expand axis limits by 0.5 in all directions for easier viewing
limits = np.array(ax.axis())
ax.axis(limits + [-0.5, 0.5, -0.5, 0.5])

plt.show()

撰写回答