有没有一种方便的方法可以在 matplotlib 的图中添加比例指示器? [英] Is there a convenient way to add a scale indicator to a plot in matplotlib?

查看:15
本文介绍了有没有一种方便的方法可以在 matplotlib 的图中添加比例指示器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I want to add a scale indicator to a plot like the one labelled '10kpc' in the (otherwise) empty plot below. So basically, the axis use one unit of measure and I want to indicate a length in the plot in a different unit. It has to have the same style as below, i.e. a |----| bar with text above.

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

Is there a convenient way in matplotlib to do that or do I have to draw three lines (two small vertical, one horizontal) and add the text? An ideal solution would not even require me to set coordinates in the data dimensions, i.e. I just say something along the line of horizontalalignment='left', verticalalignment='bottom', transform=ax.transAxes and specify only the width in data coordinates.

我与 annotate()arrow() 以及他们的文档进行了斗争,直到我得出结论,它们并不完全有用,但我可能错了.

I fought with annotate() and arrow() and their documentations for quiet a bit until I concluded, they were not exactly useful, but I might be wrong.

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

The code below is the closest, I have come so far. I still don't like having to specify the x-coordinates in the data coordinate system. The only thing I want to specify in data is the width of the bar. The rest should be placed in the plot system and ideally the bar should be placed relative to the text (a few pixels above).

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 )

推荐答案

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

Here is a code that adds a horizontal scale bar (or scale indicator or scalebar) to a plot. The bar's width is given in data units, while the height of the edges is in fraction of axes units.

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

The solution is based on an AnchoredOffsetbox, which contains a VPacker. The VPacker has a label in its lower row, and an AuxTransformBox in its upper row.
The key here is that the AnchoredOffsetbox is positioned relative to the axes, using the loc argument similar to the legend positioning (e.g. loc=4 denotes the lower right corner). However, the AuxTransformBox contains a set of elements, which are positioned inside the box using a transformation. As transformation we can choose a blended transform which transforms x coordinates according to the data transform of the axes and y coordinates according to the axes transform. A tranformation which does this is actually the xaxis_transform of the axes itself. Supplying this transform to the AuxTransformBox allows us to specify the artists within (which are Line2Ds in this case) in a useful way, e.g. the line of the bar will be Line2D([0,size],[0,0]).

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

All of this can be packed into a class, subclassing the AnchoredOffsetbox, such that it is easy to be used in an existing code.

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?)的转换需要你自己来完成.

In order to achieve a result as desired in the question, you can set the frame off and adjust the linewidth. Of course the transformation from the units you want to show (kpc) into data units (km?) needs to be done by yourself.

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))

这篇关于有没有一种方便的方法可以在 matplotlib 的图中添加比例指示器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆