matplotlib: нарисуйте специальный символ, когда появится значение

Используя matplotlib я хотел бы составить список задержек, таких как:

  • по оси X у меня есть позиция задержки в списке
  • по оси Y у меня есть сама задержка

Теперь в моем списке есть специальное значение «L», которое я хочу рисовать красным крестом на оси X всякий раз, когда это происходит.

Как я могу сделать это последнее?

Существует несколько способов сделать это.

Для начала давайте сделаем ваши данные массив 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.

Вы можете обойти это, используя настраиваемое преобразование. В этом случае мы хотим, чтобы х-координаты использовали «нормальные» координаты данных ( 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 ) является лучшим вариантом для указания отсутствующих данных, чем с использованием массива объектов со смешанными строками и значениями float. В качестве примера:

 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()