我不想用单词或数字作为 x 轴的刻度标签,而是想绘制一个简单的绘图(由直线和圆圈组成)作为每个 x 刻度的标签。这可能吗?如果是这样,在 matplotlib 中最好的方法是什么?
我会删除刻度标签并将文本替换为补丁。以下是执行此任务的简短示例:
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
将不会显示。补丁的坐标和大小(半径、宽度、高度等)将取决于轴在图中的位置。例如,如果您正在考虑对子图执行此操作,则需要对补丁的位置保持敏感,以免与任何其他轴重叠。也许值得您花时间研究变换,并定义其他单元(轴、图形或显示)中的位置和大小。
如果您有要用于符号的特定图像文件,您可以使用
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
另一个答案有一些缺点,因为它使用静态坐标。因此,当更改图形大小或缩放和平移绘图时,它将不起作用。
更好的选择是直接定义所选坐标系中的位置。对于 x 轴,使用 x 位置的数据坐标和 y 位置的轴坐标是有意义的。
使用
matplotlib.offsetbox
es 使这变得相当简单。下面将分别将一个带有圆圈的框和一个带有图像的框分别定位在坐标 (-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 符号的形式存在,因此可以简单地使用这些符号设置刻度标签。对于这样的解决方案,请参阅如何在 matplotlib 或 seaborn 中使用彩色形状作为 yticks?