con*_*use 3 annotations matplotlib
我想在下面的(否则)空图中标记为“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 )
Run Code Online (Sandbox Code Playgroud)
这是向绘图添加水平比例尺(或比例指示器或比例尺)的代码。条的宽度以数据单位给出,而边的高度以轴单位的分数表示。
解决方案基于AnchoredOffsetbox,其中包含VPacker。的VPacker下排有一个标签,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()
Run Code Online (Sandbox Code Playgroud)
为了获得问题中所需的结果,您可以关闭框架并调整线宽。当然,从你想显示的单位(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))
Run Code Online (Sandbox Code Playgroud)