在Cartopy轴之间绘制连线

3
我画了两组重叠的坐标轴,其中一组是另一组的缩小版。我想在缩小的坐标轴的角落和它在较大坐标轴上所表示的矩形的角落之间画线。然而,我画出来的线有些偏移。我尝试将其简化为一个简单的例子:
import cartopy.crs as ccrs
import matplotlib.pyplot as plt


# Create a large figure:
fig = plt.figure(figsize=(10, 10))

# Add an axes set and draw coastlines:
ax1 = plt.axes([0.01, 0.49, 0.8, 0.5], projection=ccrs.PlateCarree())
ax1.set_global()
ax1.coastlines()

# Add a second axes set (overlaps first) and draw coastlines:
ax2 = plt.axes([0.45, 0.35, 0.4, 0.3], projection=ccrs.PlateCarree())
ax2.set_extent([-44, 45, -15, 45], crs=ccrs.PlateCarree())
ax2.coastlines()

# Draw the rectangular extent of the second plot on the first:
x = [-44, 45, 45, -44, -44]
y = [-15, -15, 45, 45, -15]
ax1.fill(x, y, transform=ccrs.PlateCarree(), color='#0323E4', alpha=0.5)
ax1.plot(x, y, transform=ccrs.PlateCarree(), marker='o')

# Now try and draw a line from the bottom left corner of the second axes set
# to the bottom left corner of the extent rectangle in the first plot:
transFigure = fig.transFigure.inverted()
coord1 = transFigure.transform(ax2.transAxes.transform([0, 0]))
coord2 = transFigure.transform(ax1.transData.transform([-45, -15]))
line = plt.Line2D((coord1[0], coord2[0]), (coord1[1], coord2[1]), transform=fig.transFigure)
fig.lines.append(line)

plt.show()

以下是输出结果: enter image description here 我认为这是因为在调用plt.axes()时,我明确定义了轴的形状/纵横比,而这种形状与cartopy轴的绘制形状不匹配,因为后者的纵横比被设计成能够使地图看起来正确。我可以调整我对plt.axes()的调用中轴的形状,使其纵横比与地图相匹配,并且线条会被画在我期望的位置上,但这不容易做到!有没有一种方法可以通过坐标变换解决这个问题?
1个回答

3

据我所知,这并不容易,因为您实际上想在一个坐标系中定义一个点,在另一个坐标系中定义另一个点(BlendedGenericTransform允许您在一个坐标系中定义您的x值,在另一个坐标系中定义您的y值,但不能定义单个点)。

因此,我所知道的唯一解决方案是构建一个期望转换某些点的转换。我已经实现了一个2点变换类,它使用第一个变换来变换第一个点,并使用另一个变换来变换第二个点:

import matplotlib.transform as mtrans

class TwoPointTransformer(mtrans.Transform):
    is_affine = False
    has_inverse = False

    def __init__(self, first_point_transform, second_point_transform):
        self.first_point_transform = first_point_transform
        self.second_point_transform = second_point_transform
        return mtrans.Transform.__init__(self)

    def transform_non_affine(self, values):
        if values.shape != (2, 2):
            raise ValueError('The TwoPointTransformer can only handle '
                             'vectors of 2 points.')
        result = self.first_point_transform.transform_affine(values)
        second_values = self.second_point_transform.transform_affine(values)
        result[1, :] = second_values[1, :]
        return result

有了这个,我就可以添加一行代码,使用我关心的坐标表达:

line = plt.Line2D(xdata=(-45, 0), ydata=(-15, 0),
                  transform=TwoPointTransformer(ax1.transData, ax2.transAxes))

注意:我认为matplotlib对于具有非仿射变换的线条的缓存存在问题。当我们调整图形大小时,这个问题会显现出来。因此,解决这个问题最简单的方法是添加以下行:

fig.canvas.mpl_connect('resize_event', lambda v: line.recache())

这将在每次调整图形大小时重新计算行。这应该可以解决你的问题。希望能对你有所帮助。

好的,这正是我所需要的,谢谢!我很好奇为什么我的通过中间图形空间的方法没有得到相同的结果?当然,关于matplotlib转换,有很多我不知道的东西! - ajdawson
我在猜测,但我怀疑轴的角落直到绘制时才被计算出来,因此将等比例轴的角落固定在哪里会导致这种奇怪的情况。 - pelson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接