Выровнять маркер разметки matplotlib слева и справа
Я использую функцию matplotlib
чтобы создать внешний вид ручек на вертикальных линиях, чтобы очертить определенные части графика. Однако, чтобы заставить их выглядеть правильно, мне нужно уметь выравнивать маркер диаграммы рассеяния слева (для левой линии / ограничителя) и / или вправо (для правой линии / ограничителя).
Вот пример:
#create the figure fig = plt.figure(facecolor = '#f3f3f3', figsize = (11.5, 6)) ax = plt. ax = plt.subplot2grid((1, 1), (0,0)) #make some random data index = pandas.DatetimeIndex(start = '01/01/2000', freq = 'b', periods = 100) rand_levels = pandas.DataFrame( numpy.random.randn(100, 4)/252., index = index, columns = ['a', 'b', 'c', 'd']) rand_levels = 100*numpy.exp(rand_levels.cumsum(axis = 0)) ax.stackplot(rand_levels.index, rand_levels.transpose()) #create the place holder for the vertical lines d1, d2 = index[25], index[50] #draw the lines ymin, ymax = ax.get_ylim() ax.vlines([index[25], index[50]], ymin = ymin, ymax = ymax, color = '#353535', lw = 2) #draw the markers ax.scatter(d1, ymax, clip_on = False, color = '#353535', marker = '>', s = 200, zorder = 3) ax.scatter(d2, ymax, clip_on = False, color = '#353535', marker = '<', s = 200, zorder = 3) #reset the limits ax.set_ylim(ymin, ymax) ax.set_xlim(rand_levels.index[0], rand_levels.index[-1]) plt.show()
Приведенный выше код дает мне почти график, который я ищу, например:
Тем не менее, я бы хотел, чтобы крайний левый маркер («>») был «выровнен влево» (т.е. слегка сдвинут вправо), чтобы линия продолжалась до конца маркера. Аналогично, мне нужен самый правый маркер ( «<») «выравниваться вправо» (т.е. слегка сдвигается влево). Как это:
Какие-либо рекомендации или предложения о том, как это сделать гибким образом?
ПРИМЕЧАНИЕ. На практике мой индекс DataFrame
представляет собой pandas.Datetime
не целые числа, как я представил для этого простого примера.
- Pylab: наложение меток на цвета
- Как построить график рассеяния с использованием вывода гистограммы в matplotlib?
- Получить данные из графика с помощью matplotlib
- Matplotlib: график рассеяния – размер символа на основе расстояния между пикселями
- Удаление точки на участке рассеяния с помощью matplotlib
Мне понравился этот вопрос и я не был доволен своим первым ответом. В частности, для выравнивания маркеров казалось излишне громоздким создавать конкретные объекты ( mark_align_*
). В конечном итоге я нашел функциональность для указания маркера по verts (список 2-элементных поплавков или массив Nx2, который указывает вершины маркера относительно целевой точки в точке (0, 0)
). Чтобы использовать эту функциональность для этой цели, я написал эту функцию,
from matplotlib import markers from matplotlib.path import Path def align_marker(marker, halign='center', valign='middle',): """ create markers with specified alignment. Parameters ---------- marker : a valid marker specification. See mpl.markers halign : string, float {'left', 'center', 'right'} Specifies the horizontal alignment of the marker. *float* values specify the alignment in units of the markersize/2 (0 is 'center', -1 is 'right', 1 is 'left'). valign : string, float {'top', 'middle', 'bottom'} Specifies the vertical alignment of the marker. *float* values specify the alignment in units of the markersize/2 (0 is 'middle', -1 is 'top', 1 is 'bottom'). Returns ------- marker_array : numpy.ndarray A Nx2 array that specifies the marker path relative to the plot target point at (0, 0). Notes ----- The mark_array can be passed directly to ax.plot and ax.scatter, eg:: ax.plot(1, 1, marker=align_marker('>', 'left')) """ if isinstance(halign, (str, unicode)): halign = {'right': -1., 'middle': 0., 'center': 0., 'left': 1., }[halign] if isinstance(valign, (str, unicode)): valign = {'top': -1., 'middle': 0., 'center': 0., 'bottom': 1., }[valign] # Define the base marker bm = markers.MarkerStyle(marker) # Get the marker path and apply the marker transform to get the # actual marker vertices (they should all be in a unit-square # centered at (0, 0)) m_arr = bm.get_path().transformed(bm.get_transform()).vertices # Shift the marker vertices for the specified alignment. m_arr[:, 0] += halign / 2 m_arr[:, 1] += valign / 2 return Path(m_arr, bm.get_path().codes)
Используя эту функцию, желаемые маркеры можно изобразить как,
ax.plot(d1, 1, marker=align_marker('>', halign='left'), ms=20, clip_on=False, color='k', transform=ax.get_xaxis_transform()) ax.plot(d2, 1, marker=align_marker('<', halign='right'), ms=20, clip_on=False, color='k', transform=ax.get_xaxis_transform())
или используя ax.scatter
,
ax.scatter(d1, 1, 200, marker=align_marker('>', halign='left'), clip_on=False, color='k', transform=ax.get_xaxis_transform()) ax.scatter(d2, 1, 200, marker=align_marker('<', halign='right'), clip_on=False, color='k', transform=ax.get_xaxis_transform())
В обоих этих примерах я указал transform=ax.get_xaxis_transform()
чтобы вертикальное положение маркеров transform=ax.get_xaxis_transform()
в координатах осей ( 1
– верхняя часть осей), это не имеет никакого отношения к выравниванию маркера.
Очевидным преимуществом этого решения по сравнению с моим предыдущим является то, что он не требует знания маркеров , функции построения ( ax.plot
против ax.scatter
) или осей (для преобразования). Вместо этого просто указывается маркер и его выравнивание!
Ура!
Одним из решений было бы использовать mpl.transforms и входной параметр transform
в ax.scatter
или ax.plot
. В частности, я бы начал с добавления,
from matplotlib import transforms as tf
В этом подходе я использую tf.offset_copy
для создания маркеров, смещенных на половину их размера. Но каков размер маркеров? Оказывается, что ax.scatter
и ax.plot
определяют размеры маркеров по-разному. См. Этот вопрос для получения дополнительной информации.
-
Параметр
s=
input дляax.scatter
указывает размеры маркеров в точках ^ 2 (т.ax.scatter
Это площадь квадрата, в который помещаются маркеры). -
Входной параметр
ax.plot
вax.plot
указывает ширину и высоту маркеров в точках (т.ax.plot
Ширину и высоту квадрата, в который помещаются маркеры).
Использование ax.scatter
Итак, если вы хотите ax.scatter
свои маркеры с помощью ax.scatter
вы можете сделать,
ms_scatter = 200 # define markersize mark_align_left_scatter = tf.offset_copy(ax.get_xaxis_transform(), fig, ms_scatter ** 0.5 / 2, units='points') mark_align_right_scatter = tf.offset_copy(ax.get_xaxis_transform(), fig, -ms_scatter ** 0.5 / 2, units='points')
Здесь я использовал ax.get_xaxis_transform
, который представляет собой преобразование, которое помещает точки в координаты данных вдоль оси x, но в координатах осей (от 0 до 1) по оси y. Таким образом, вместо использования ymax
, я могу разместить точку в верхней части графика с помощью 1
. Кроме того, если я панорамирую или увеличиваю цифру, маркеры все равно будут наверху! Как только я определил новые преобразования, я назначаю их свойству transform
когда я вызываю ax.scatter
,
ax.scatter(d1, 1, s=ms_scatter, marker='>', transform=mark_align_left_scatter, clip_on=False, color='k') ax.scatter(d2, 1, s=ms_scatter, marker='<', transform=mark_align_right_scatter, clip_on=False, color='k')
Использование ax.plot
Поскольку это несколько проще, я бы, вероятно, использовал ax.plot
. В таком случае я бы сделал,
ms = 20 mark_align_left = tf.offset_copy(ax.get_xaxis_transform(), fig, ms / 2, units='points') mark_align_right = tf.offset_copy(ax.get_xaxis_transform(), fig, -ms / 2, units='points') ax.plot(d1, 1, marker='>', ms=ms, transform=mark_align_left, clip_on=False, color='k') ax.plot(d2, 1, marker='<', ms=ms, transform=mark_align_right, clip_on=False, color='k')
Последние комментарии
Вы можете создать оболочку, чтобы сделать преобразование mark_align_*
проще, но я оставлю это для вас, если вы захотите.
Если вы используете ax.scatter
или ax.plot
ваш выходной график будет выглядеть примерно так:
Не самое изящное решение, но если я правильно понимаю ваш вопрос, вычитание и добавление одного из / в d1
и d2
соответственно должно сделать это:
ax.scatter(d1-1, ymax, clip_on = False, color = '#353535', marker = '>', s = 200, zorder = 3) ax.scatter(d2+1, ymax, clip_on = False, color = '#353535', marker = '<', s = 200, zorder = 3)
- Как проверить макет звонков с помощью подстановочных знаков?
- Python – как обрабатывать HTTPS-запрос с помощью (Urllib2 + SSL), хотя HTTP-прокси
- График разметки matplotlib с разными маркерами и цветами
- Есть ли функция для создания матриц рассеяния в matplotlib?
- Правильная калибровка маркеров в области рассеяния на радиус R в Matplotlib
- Недопустимый rgba arg "#" в matplotlib
- matplotlib 3D-диаграмма рассеяния с цветом маркера, соответствующим значениям RGB
- Выбор размера маркера в Matplotlib
- matplotlib Медленное вращение 3D-рассеяния