[英]Add a line to matplotlib annotations
我有一个 matplotlib plot ,其中某些点得到了注释。 我已经弄清楚了如何自己做注释,包括箭头和一切。 但是,我需要在每个注释的文本旁边添加一行。 它应该与文本平行运行,与文本有一定的偏移,以点为单位。 线的长度基于每个带注释的点所具有的百分比值。 理想情况下,我想要一条长度始终相同的行(大约 15 个文本字符,这是注释中文本的最大长度),但根据提到的百分比值,可以说是红色和灰色部分。 非常感谢任何帮助或建议。
编辑:这是一些模拟数据点的最小示例:
import numpy as np
import matplotlib.pyplot as plt
x=[2, 3, 4, 6, 7, 8, 10, 11]
y=[1, 3, 4, 2, 3, 1, 5, 2]
tx=[3, 4, 5, 6, 7, 8, 9, 10]
yd=dict(zip(x, y))
plt.scatter(x, y)
plt.xlim(0, 14)
plt.ylim(0, 8)
tspace=list(np.linspace(.05, .95, len(tx)))
tsd=dict(zip(tx, tspace))
arpr = {"arrowstyle": "-",
"connectionstyle": "arc,angleA=-90,armA=20,angleB=90,armB=20,rad=10"}
for i, j in zip(x, tx):
plt.annotate("foo bar baz", (i, yd[i]), (tsd[j], .75),
textcoords="axes fraction", arrowprops=arpr,
annotation_clip=False, rotation="vertical")
您可以使用plt.Rectangle
来绘制条形图——首先是一个灰色条形,它是整个条形的高度,然后是一个红色条形,它是整个条形高度的百分比。
但是,由于矩形的宽度和长度参数以 plot 上的 x 和 y 坐标为单位,因此我们需要能够访问您所做的文本注释的坐标。
您使用textcoords="axes fraction"
设置注释坐标,这使得在 x 和 y 坐标中访问矩形的开始和结束坐标变得很困难,因此我为限制定义了一些常量x_min, x_max, y_min, y_max
plot,然后直接从tspace
列表和条形注释计算文本注释的坐标。
可以在列表中设置每个条的红色空间百分比,这样就可以推广了。
import numpy as np
import matplotlib.pyplot as plt
x=[2, 3, 4, 6, 7, 8, 10, 11]
y=[1, 3, 4, 2, 3, 1, 5, 2]
tx=[3, 4, 5, 6, 7, 8, 9, 10]
yd=dict(zip(x, y))
fig,ax = plt.subplots(1,1)
plt.scatter(x, y)
x_min, x_max = 0, 14
y_min, y_max = 0, 8
y_text_end = 0.75*(y_max-y_min)
plt.xlim(0, 14)
plt.ylim(0, 8)
tspace=list(np.linspace(.05, .95, len(tx)))
# tsd=dict(zip(tx, tspace))
# random percentage values to demonstrate the bar functionality
bar_percentages = [0.95, 0.9, 0.8, 0.6, 0.4, 0.2, 0.1, 0.05]
bar_width = 0.2
bar_height = 1.9
arpr = {"arrowstyle": "-",
"connectionstyle": "arc,angleA=-90,armA=20,angleB=90,armB=20,rad=10"}
## axes fraction is convenient but it's important to be able to access the exact coordinates for the Rectangle function
for i, x_val in enumerate(x):
plt.annotate("foo bar baz", (x_val, yd[x_val]), (tspace[i]*(x_max-x_min), y_text_end),
arrowprops=arpr, annotation_clip=False, rotation="vertical")
bar_grey = plt.Rectangle((tspace[i]*(x_max-x_min)+0.4, y_text_end-0.1), bar_width, bar_height, fc='#cccccc')
bar_red = plt.Rectangle((tspace[i]*(x_max-x_min)+0.4, y_text_end-0.1), bar_width, bar_percentages[i]*bar_height, fc='r')
plt.gca().add_patch(bar_grey)
plt.gca().add_patch(bar_red)
plt.show()
从那以后,我找到了一个解决方案,尽管它很老套,并且没有理想的“灰盒”,但这对我的目的来说很好,如果它可以帮助某人,我会在这里分享。 如果有人知道改进,请随时贡献。 感谢@DerekO 提供了有用的输入,我将其合并到我的解决方案中。
这是改编自此matplotlib 演示。 我只是将自定义框移到文本之外,并使用百分比的附加参数修改了宽度和高度。 我不得不将它拆分为两个实际的注释,因为使用自定义框的箭头不会从正确的位置开始,但是这样可以正常工作。 缩放/缩放现在表现良好并跟随文本。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.path import Path
from matplotlib.patches import BoxStyle
class MyStyle(BoxStyle._Base):
def __init__(self, pad, per=1.):
self.pad = pad
self.per = per
super().__init__()
def transmute(self, x0, y0, width, height, mutation_size):
# padding
pad = mutation_size * self.pad
# width and height with padding added.
width = width + 2.*pad
width *= self.per
height = 8.
# boundary of the padded box
x0, y0 = x0-pad, y0-pad,
x1, y1 = x0+width, y0-height
cp = [(x0, y0),
(x1, y0),
(x1, y1),
(x0, y1),
(x0, y0)]
com = [Path.MOVETO,
Path.LINETO,
Path.LINETO,
Path.LINETO,
Path.CLOSEPOLY]
path = Path(cp, com)
return path
# register the custom style
BoxStyle._style_list["percent"] = MyStyle
x=[2, 3, 4, 6, 7, 8, 10, 11]
y=[1, 3, 4, 2, 3, 1, 5, 2]
tx=[3, 4, 5, 6, 7, 8, 9, 10]
yd=dict(zip(x, y))
fig,ax = plt.subplots(1,1)
plt.scatter(x, y)
x_min, x_max = 0, 14
y_min, y_max = 0, 8
y_text_end = 0.75*(y_max-y_min)
plt.xlim(0, 14)
plt.ylim(0, 8)
tspace=list(np.linspace(.05, .95, len(tx)))
# tsd=dict(zip(tx, tspace))
# random percentage values to demonstrate the bar functionality
bar_percentages = [0.95, 0.9, 0.8, 0.6, 0.4, 0.2, 0.1, 0.05]
arpr = {"arrowstyle": "-",
"connectionstyle": "arc,angleA=-90,armA=20,angleB=90,armB=20,rad=10"}
## axes fraction is convenient but it's important to be able to access the exact coordinates for the Rectangle function
for i, x_val in enumerate(x):
plt.annotate("", (x_val, yd[x_val]), (tspace[i]*(x_max-x_min), y_text_end),
arrowprops=arpr, annotation_clip=False, rotation="vertical",)
plt.annotate("foo bar baz", (x_val, yd[x_val]), (tspace[i]*(x_max-x_min), y_text_end),
annotation_clip=False, rotation="vertical",
va="bottom", ha="right",
bbox=dict(boxstyle=f"percent,pad=.2,per={bar_percentages[i]}",
fc="red",
ec="none"))
del BoxStyle._style_list["percent"]
plt.show()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.