Drawing lines between cartopy axes

隐身守侯 提交于 2021-02-18 03:36:57

问题


I have drawn two sets of axes which overlap, one being a zoomed version of the other. I want to draw lines between the corners of the zoomed axes and the corners of the rectangle it represents on the larger axes. However, the lines I'm drawing are slightly off position. I've tried to condense this into a simple example:

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

With the following output: enter image description here

I think this is because I am defining the shape/aspect of the axes explicitly when calling plt.axes(), and this shape does not match the shape of the cartopy axes as they are drawn with an aspect ratio designed to make the map look correct. I can tweak the shape of the axes in my call to plt.axes() so that the aspect ratio matches that of the map and the line is drawn where I expect, but this is not easy to do! Is there a way I can account for this in the coordinate transform?


回答1:


Not easily AFAIK, as you essentially want to define one point in one CS and the other in another (BlendedGenericTransform allows you to define your xs in one CS and ys in another, but not individual points).

As a result, the only solution I know of is to construct a transform which expects a certain number of points to transform. I've implemented a 2 point transformation class which transforms the first point given the first transform, and the second point with the other transform:

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

With this I can then add a line expressed in the coordinates I care about:

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

Note: I believe there to be an issue with the matplotlib caching of lines with non-affine transforms such as this. This problem manifests itself when we resize the figure. As a result, the simplest solution to this is to also add the line:

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

Which will re-compute the line each time the figure is resized.

This should do the trick for you.

HTH



来源:https://stackoverflow.com/questions/22543847/drawing-lines-between-cartopy-axes

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!