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

查看:242
本文介绍了有没有一种方便的方法可以向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中是否有一种方便的方法可以做到这一点?还是我必须画三行(两行小垂直,一行水平)并添加文本?理想的解决方案甚至不需要我在数据维度中设置坐标,即我只是沿horizontalalignment='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天全站免登陆