【问题标题】:Is there a convenient way to add a scale indicator to a plot in matplotlib?有没有一种方便的方法可以在 matplotlib 的图中添加比例指示器?
【发布时间】:2017-09-01 16:31:02
【问题描述】:

我想在下面的(否则)空图中标记为“10kpc”的图中添加比例指示器。所以基本上,轴使用一个测量单位,我想用不同的单位表示图中的长度。它必须具有与以下相同的样式,即 |----|上面有文字的栏。

matplotlib 中是否有一种方便的方法可以做到这一点,还是我必须画三条线(两条小的垂直线,一条水平线)并添加文本?一个理想的解决方案甚至不需要我在数据维度中设置坐标,即我只是沿着horizontalalignment='left', verticalalignment='bottom', transform=ax.transAxes 的行说一些东西,并且只指定数据坐标中的宽度。

我与annotate()arrow() 以及他们的文档争吵了一会儿,直到我得出结论,它们并不完全有用,但我可能错了。

编辑:

下面的代码是最接近的,我到目前为止。我仍然不喜欢在数据坐标系中指定 x 坐标。我唯一想在数据中指定的是条形的宽度。其余部分应放置在绘图系统中,理想情况下,条形应相对于文本放置(上方几个像素)。

import matplotlib.pyplot as plt 
import matplotlib.transforms as tfrms
plt.imshow(somedata)
plt.colorbar()
ax = plt.gca()
trans = tfrms.blended_transform_factory( ax.transData, ax.transAxes )
plt.errorbar( 5, 0.06, xerr=10*arcsecperkpc/2, color='k', capsize=5, transform=trans )
plt.text( 5, 0.05, '10kpc',  horizontalalignment='center', verticalalignment='top', transform=trans )

【问题讨论】:

  • 会的,但我必须匹配上图的风格。所以它看起来就像那样
  • 您是否考虑过使用水平的errorbarannotate
  • @con-f-use 我很高兴经过一个小时的搜索找到了你的帖子,它真的很有帮助。 @mommermi 您能否提供一些带有errorbarannotate 的示例代码,这将对未来的读者有所帮助!

标签: matplotlib annotations


【解决方案1】:

这是一个向绘图添加水平比例尺(或比例指示器或比例尺)的代码。条的宽度以数据单位给出,而边缘的高度以轴单位的分数表示。

解决方案基于AnchoredOffsetbox,其中包含VPackerVPacker 的下排有一个标签,AuxTransformBox 的上排有一个标签。
这里的关键是AnchoredOffsetbox 相对于轴定位,使用类似于图例定位的loc 参数(例如loc=4 表示右下角)。但是,AuxTransformBox 包含一组元素,这些元素使用转换定位在框内。作为变换,我们可以选择混合变换,根据坐标轴的数据变换变换 x 坐标,根据坐标轴变换变换 y 坐标。执行此操作的转换实际上是轴本身的 xaxis_transform。将此转换提供给AuxTransformBox 允许我们以有用的方式指定其中的艺术家(在本例中为Line2Ds),例如条形线将是Line2D([0,size],[0,0])

所有这些都可以打包到一个类中,继承AnchoredOffsetbox,以便在现有代码中轻松使用。

import matplotlib.pyplot as plt
import matplotlib.offsetbox
from matplotlib.lines import Line2D
import numpy as np; np.random.seed(42)

x = np.linspace(-6,6, num=100)
y = np.linspace(-10,10, num=100)
X,Y = np.meshgrid(x,y)
Z = np.sin(X)/X+np.sin(Y)/Y

fig, ax = plt.subplots()
ax.contourf(X,Y,Z, alpha=.1)
ax.contour(X,Y,Z, alpha=.4)

class AnchoredHScaleBar(matplotlib.offsetbox.AnchoredOffsetbox):
    """ size: length of bar in data units
        extent : height of bar ends in axes units """
    def __init__(self, size=1, extent = 0.03, label="", loc=2, ax=None,
                 pad=0.4, borderpad=0.5, ppad = 0, sep=2, prop=None, 
                 frameon=True, linekw={}, **kwargs):
        if not ax:
            ax = plt.gca()
        trans = ax.get_xaxis_transform()
        size_bar = matplotlib.offsetbox.AuxTransformBox(trans)
        line = Line2D([0,size],[0,0], **linekw)
        vline1 = Line2D([0,0],[-extent/2.,extent/2.], **linekw)
        vline2 = Line2D([size,size],[-extent/2.,extent/2.], **linekw)
        size_bar.add_artist(line)
        size_bar.add_artist(vline1)
        size_bar.add_artist(vline2)
        txt = matplotlib.offsetbox.TextArea(label, minimumdescent=False)
        self.vpac = matplotlib.offsetbox.VPacker(children=[size_bar,txt],  
                                 align="center", pad=ppad, sep=sep) 
        matplotlib.offsetbox.AnchoredOffsetbox.__init__(self, loc, pad=pad, 
                 borderpad=borderpad, child=self.vpac, prop=prop, frameon=frameon,
                 **kwargs)

ob = AnchoredHScaleBar(size=3, label="3 units", loc=4, frameon=True,
                       pad=0.6,sep=4, linekw=dict(color="crimson"),) 
ax.add_artist(ob)
plt.show()

为了达到问题中想要的结果,您可以关闭框架并调整线宽。当然从你要显示的单位(kpc)到数据单位(km?)的转换需要你自己来完成。

ikpc = lambda x: x*3.085e16 #x in kpc, return in km
ob = AnchoredHScaleBar(size=ikpc(10), label="10kpc", loc=4, frameon=False,
                       pad=0.6,sep=4, linekw=dict(color="k", linewidth=0.8))

【讨论】:

  • 很好的答案,谢谢。知道如何控制比例尺的位置吗?我想把它放在一些 (x,y) 坐标上。我尝试使用bbox_to_anchor,但我对bbox坐标系感到困惑。
  • @normanius 对。我更新了答案代码。所以现在可以将bbox_to_anchor=(0.1,.1), bbox_transform=ax.transAxes 之类的东西作为关键字参数传递。
  • 啊,感谢您的更新。我错过了 bbox_transform 参数。 :)
  • 还有一件事:填充参数以哪些单位测量?我想不通。
  • 应该是字体大小的单位。 IE。如果字体大小是 10 pt,pad 是 0.5,那么它应该是 5pt padding。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-04-27
  • 1970-01-01
相关资源
最近更新 更多