【问题标题】:How can I make the xtick labels of a plot be simple drawings using matplotlib?如何使用 matplotlib 使绘图的 xtick 标签成为简单的绘图?
【发布时间】:2012-05-19 07:21:34
【问题描述】:

我想绘制一个简单的图形(由线和圆组成)作为每个 x 刻度的标签,而不是单词或数字作为 x 轴的刻度标签。这可能吗?如果是这样,在 matplotlib 中最好的方法是什么?

【问题讨论】:

    标签: python drawing plot matplotlib labels


    【解决方案1】:

    另一个答案有一些缺点,因为它使用静态坐标。因此,在更改图形大小或缩放和平移绘图时它将不起作用。

    更好的选择是直接定义所选坐标系中的位置。对于 xaxis,使用数据坐标作为 x 位置和轴坐标作为 y 位置是有意义的。

    使用matplotlib.offsetboxes 使这变得相当简单。下面将分别在坐标 (-5,0) 和 (5,0) 处放置一个带有圆圈的框和一个带有图像的框,并将它们稍微偏移到较低的位置,这样它们看起来就像是刻度标签。

    import matplotlib.pyplot as plt
    import matplotlib.patches as mpatches
    from matplotlib.offsetbox import (DrawingArea, OffsetImage,AnnotationBbox)
    
    fig, ax = plt.subplots()
    ax.plot([-10,10], [1,3])
    
    # Annotate the 1st position with a circle patch
    da = DrawingArea(20, 20, 10, 10)
    p = mpatches.Circle((0, 0), 10)
    da.add_artist(p)
    
    ab = AnnotationBbox(da, (-5,0),
                        xybox=(0, -7),
                        xycoords=("data", "axes fraction"),
                        box_alignment=(.5, 1),
                        boxcoords="offset points",
                        bboxprops={"edgecolor" : "none"})
    
    ax.add_artist(ab)
    
    # Annotate the 2nd position with an image
    arr_img = plt.imread("https://i.stack.imgur.com/FmX9n.png", format='png')
    
    imagebox = OffsetImage(arr_img, zoom=0.2)
    imagebox.image.axes = ax
    
    ab = AnnotationBbox(imagebox, (5,0),
                        xybox=(0, -7),
                        xycoords=("data", "axes fraction"),
                        boxcoords="offset points",
                        box_alignment=(.5, 1),
                        bboxprops={"edgecolor" : "none"})
    
    ax.add_artist(ab)
    
    plt.show()
    


    请注意,许多形状以 unicode 符号形式存在,因此可以简单地使用这些符号设置刻度标签。对于这样的解决方案,请参阅How to use a colored shape as yticks in matplotlib or seaborn?

    【讨论】:

    • 这个答案比当时接受的更容易修改,使我能够更直观地控制图像标签的位置
    【解决方案2】:

    我会删除刻度标签并将文本替换为patches。以下是执行此任务的简短示例:

    import matplotlib.pyplot as plt
    import matplotlib.patches as patches
    
    
    # define where to put symbols vertically
    TICKYPOS = -.6
    
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.plot(range(10))
    
    # set ticks where your images will be
    ax.get_xaxis().set_ticks([2,4,6,8])
    # remove tick labels
    ax.get_xaxis().set_ticklabels([])
    
    
    # add a series of patches to serve as tick labels
    ax.add_patch(patches.Circle((2,TICKYPOS),radius=.2,
                                fill=True,clip_on=False))
    ax.add_patch(patches.Circle((4,TICKYPOS),radius=.2,
                                fill=False,clip_on=False))
    ax.add_patch(patches.Rectangle((6-.1,TICKYPOS-.05),.2,.2,
                                   fill=True,clip_on=False))
    ax.add_patch(patches.Rectangle((8-.1,TICKYPOS-.05),.2,.2,
                                   fill=False,clip_on=False))
    

    结果如下图:

    clip_on设置为False很关键,否则坐标轴外的patches将不显示。补丁的坐标和大小(半径、宽度、高度等)将取决于轴在图中的位置。例如,如果您正在考虑对子图执行此操作,则需要对补丁的位置敏感,以免与任何其他轴重叠。您可能值得花时间研究Transformations,并在其他单位(轴、图形或显示)中定义位置和大小。

    如果您有要用于符号的特定图像文件,您可以使用BboxImage 类来创建要添加到轴而不是补丁的艺术家。例如,我使用以下脚本制作了一个简单的图标:

    import matplotlib.pyplot as plt
    
    fig = plt.figure(figsize=(1,1),dpi=400)
    ax = fig.add_axes([0,0,1,1],frameon=False)
    ax.set_axis_off()
    
    ax.plot(range(10),linewidth=32)
    ax.plot(range(9,-1,-1),linewidth=32)
    
    fig.savefig('thumb.png')
    

    制作这张图片:

    然后我在我想要刻度标签的位置和我想要的大小创建了一个 BboxImage:

    lowerCorner = ax.transData.transform((.8,TICKYPOS-.2))
    upperCorner = ax.transData.transform((1.2,TICKYPOS+.2))
    
    bbox_image = BboxImage(Bbox([lowerCorner[0],
                                 lowerCorner[1],
                                 upperCorner[0],
                                 upperCorner[1],
                                 ]),
                           norm = None,
                           origin=None,
                           clip_on=False,
                           )
    

    注意到我如何使用transData 转换将数据单位转换为显示单位,这是Bbox 的定义所必需的。

    现在我使用imread 例程读取图像,并将其结果(一个numpy 数组)设置为bbox_image 的数据并将艺术家添加到轴:

    bbox_image.set_data(imread('thumb.png'))
    ax.add_artist(bbox_image)
    

    这会导致更新的数字:

    如果你直接使用图片,请确保导入所需的类和方法:

    from matplotlib.image import BboxImage,imread
    from matplotlib.transforms import Bbox
    

    【讨论】:

      猜你喜欢
      • 2016-02-29
      • 2018-01-20
      • 1970-01-01
      • 2023-03-23
      • 1970-01-01
      • 2022-11-24
      • 2020-09-26
      • 2017-09-11
      相关资源
      最近更新 更多