【问题标题】:Instead of grid lines on a plot, can matplotlib print grid crosses?matplotlib 可以打印网格交叉而不是绘图上的网格线吗?
【发布时间】:2012-04-25 11:45:18
【问题描述】:

我想在绘图上有一些网格线,但实际上全长线太多/分散注意力,甚至是浅灰色虚线。我去手动对 SVG 输出进行了一些编辑,以获得我想要的效果。这可以用 matplotlib 完成吗?我查看了网格的 pyplot api,唯一能看到的可能是 xdata 和 ydata Line2D kwargs。

【问题讨论】:

    标签: python matplotlib


    【解决方案1】:

    这无法通过基本 API 完成,因为网格线仅使用两个点创建。网格线需要在每个刻度线处都有一个“数据”点,以便绘制一个标记。这显示在以下示例中:

    import matplotlib.pyplot as plt
    
    ax = plt.subplot(111)
    ax.grid(clip_on=False, marker='o', markersize=10)
    plt.savefig('crosses.png')
    plt.show()
    

    这会导致:

    请注意'o' 标记仅位于 Axes 边缘的开头和结尾,因为网格线仅涉及两个点。

    您可以编写一个方法来模拟您想要的,使用一系列Artists 创建十字标记,但仅利用基本绘图功能来绘制十字图案会更快。

    这就是我在以下示例中所做的:

    import matplotlib.pyplot as plt
    import numpy as np
    
    NPOINTS=100
    
    def set_grid_cross(ax, in_back=True):
        xticks = ax.get_xticks()
        yticks = ax.get_yticks()
        xgrid, ygrid = np.meshgrid(xticks, yticks)
        kywds = dict() 
        if in_back:
            kywds['zorder'] = 0
        grid_lines = ax.plot(xgrid, ygrid, 'k+', **kywds)
    
    xvals = np.arange(NPOINTS)
    yvals = np.random.random(NPOINTS) * NPOINTS
    
    ax1 = plt.subplot(121)
    ax2 = plt.subplot(122)
    
    ax1.plot(xvals, yvals, linewidth=4)
    ax1.plot(xvals, xvals, linewidth=7)
    set_grid_cross(ax1)
    ax2.plot(xvals, yvals, linewidth=4)
    ax2.plot(xvals, xvals, linewidth=7)
    set_grid_cross(ax2, in_back=False)
    
    plt.savefig('gridpoints.png')
    plt.show()
    

    结果如下图:

    如您所见,我使用 x 和 y 中的刻度线来定义一系列我想要网格标记 ('+') 的点。我使用meshgrid 获取两个 1D 数组并制作 2 个 2D 数组,这些数组对应于每个网格点上的双循环。我用标记样式将其绘制为'+',我已经完成了......几乎。这会在顶部绘制十字,我添加了一个额外的关键字来重新排序与绘图相关的线条列表。如果要在所有内容后面绘制网格标记,我会调整zorder。*****

    该示例显示了默认情况下网格放置在后面的左侧子图,而右侧子图禁用了此选项。如果您遵循每个图中的绿线,您会注意到差异。

    如果您对边界上的网格交叉感到困扰,您可以在set_grid_cross 中定义网格之前删除 x 和 y 的第一个和最后一个刻度线,如下所示:

    xticks = ax.get_xticks()[1:-1] #< notice the slicing
    yticks = ax.get_yticks()[1:-1] #< notice the slicing
    xgrid, ygrid = np.meshgrid(xticks, yticks)
    

    我在以下示例中这样做,使用更大的不同标记来说明我的观点:

    ***** 感谢@fraxel 的回答指出了这一点。

    【讨论】:

    • 信息丰富且具有创新性!并且 kwargs 可用于更详细地设置颜色和大小。
    • 还有一个问题是它在轴上绘制标记。如果我可以对 xgrid、ygrid 数组进行切片
    【解决方案2】:

    您可以在刻度点的每个交点处绘制线段。它很容易做到,只需抓住两个轴的刻度位置get_ticklocs(),然后循环遍历所有组合,使用axhlineaxvline 绘制短线段,从而在每个交叉点创建一个十字准线。我设置了zorder=0,所以首先绘制十字准线,以便它们位于绘图数据的后面。它易于控制颜色/alpha 和十字线大小。几个轻微的“陷阱”......在你得到刻度位置之前做图......而且xminxmax参数似乎需要规范化。

    import matplotlib.pyplot as plt
    
    fig = plt.figure()
    ax = fig.add_subplot(1,1,1)    
    ax.plot((0,2,3,5,5,5,6,7,8,6,6,4,3,32,7,99), 'r-',linewidth=4)
    
    x_ticks = ax.xaxis.get_ticklocs()
    y_ticks = ax.yaxis.get_ticklocs()    
    for yy in y_ticks[1:-1]:
        for xx in x_ticks[1:-1]:
            plt.axhline(y=yy, xmin=xx / max(x_ticks) - 0.02, 
                    xmax=xx / max(x_ticks) + 0.02, color='gray', alpha=0.5, zorder=0)
            plt.axvline(x=xx, ymin=yy / max(y_ticks) - 0.02, 
                    ymax=yy / max(y_ticks) + 0.02, color='gray', alpha=0.5, zorder=0)
    plt.show()
    

    【讨论】:

    • 太棒了!有很大的灵活性来微调十字架的大小/长度。您对标准化位是正确的,必须努力使比率正确,尤其是对于非方形图形尺寸。我看到刻度线所在的轴上也有多余的线,所以会尝试去掉它们。
    • @a different ben - 嘿,没有注意到 x 轴和 y 轴上的交叉点!我已经更新以用切片摆脱它们。是的,取决于绘图大小而不是轴值的最小值和最大值是一个非常奇怪的值!
    猜你喜欢
    • 1970-01-01
    • 2013-12-20
    • 1970-01-01
    • 2011-12-19
    • 2020-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多