本文介绍了左右对齐 matplotlib 散点标记的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 matplotlib 散点图函数在垂直线上创建手柄的外观,以描绘图形的某些部分.但是,为了使它们看起来正确,我需要能够将散点图标记对齐到左侧(对于左侧线/轮廓线)和/或右侧(对于右侧线/轮廓线).

I am using the matplotlib scatterplot function to create the appearance of handles on vertical lines to delineate certain parts of a graph. However, in order to make them look correct, I need to be able to align the scatter plot marker to the left (for the left line / delineator) and / or right (for the right line / delineator).

这是一个例子:

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

上面的代码给了我几乎我想要的图形,就像这样:

The code above gives me almost the graph I'm looking for, like this:

但是,我希望最左边的标记(>")被向左对齐"(即稍微向右移动),以便该行继续到标记的后面.同样,我希望最右端的标记(<")将被右对齐"(即稍微向左移动).像这样:

However, I'd like the leftmost marker (">") to be "aligned left" (i.e. shifted slightly to the right) so that the line is continued to the back of the marker Likewise, I'd like the rightmost marker ("<") to be "aligned right" (i.e. slightly shifted to the left). Like this:

有关如何以灵活的方式完成此任务的任何指导或建议?

Any guidance or suggestions on how to accomplish this in a flexible manner?

注意:实际上,我的 DataFrame 索引是 pandas.Datetime ,而不是我为这个简单示例提供的整数.

NOTE: In practice, my DataFrame index is pandas.Datetime not integers as I've provided for this simple example.

推荐答案

我喜欢这个问题,但对我的第一个答案并不满意.特别是,创建图形特定对象 (mark_align_*) 以对齐标记似乎不必要地繁琐.我最终发现的是通过 verts 指定标记的功能(一个 2 元素浮点数列表,或一个 Nx2 数组,它指定相对于 处的目标绘图点的标记顶点(0,0)).为了将这个功能用于这个目的,我编写了这个函数,

I liked this question and was not satisfied with my first answer. In particular, it seemed unnecessarily cumbersome to create figure specific objects (mark_align_*) in order to align markers. What I eventually found was the functionality to specify a marker by verts (a list of 2-element floats, or an Nx2 array, that specifies the marker vertices relative to the target plot-point at (0, 0)). To utilize this functionality for this purpose I wrote this function,

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, e.g.::

        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)

使用此功能,可以绘制所需的标记,

Using this function, the desired markers can be plotted as,

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() 以便标记的垂直位置在轴坐标中(1 是轴),这与标记 alignment 无关.

In both of these examples I have specified transform=ax.get_xaxis_transform() so that the vertical position of the markers is in axes coordinates (1 is the top of the axes), this has nothing to do with the marker alignment.

与我之前的解决方案相比,此解决方案的明显优势在于它不需要了解 markersize绘图功能 (ax.plotcode> vs. ax.scatter) 或 axes(用于转换).相反,只需指定一个标记及其对齐方式即可!

The obvious advantage of this solution compared to my previous one is that it does not require knowledge of the markersize, plotting function (ax.plot vs. ax.scatter), or axes (for the transform). Instead, one simply specifes a marker and its alignment!

干杯!

这篇关于左右对齐 matplotlib 散点标记的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-20 01:16