繁体   English   中英

在 matplotlib 注释中添加一行

[英]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")

这是电流与所需 output 的比较: 当前与期望

您可以使用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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM