Как изменить подплановую матрицу matplotlib существующей оси?

Я пытаюсь построить простую функцию, которая принимает экземпляр subplot (matplotlib.axes._subplots.AxesSubplot) и преобразует его проекцию в другую проекцию, например, в одну из проекций cartopy.crs.CRS.

Идея выглядит примерно так:

import cartopy.crs as ccrs
import matplotlib.pyplot as plt

def make_ax_map(ax, projection=ccrs.PlateCarree()):
    # set ax projection to the specified projection
    ...
    # other fancy formatting
    ax2.coastlines()
    ...

# Create a grid of plots
fig, (ax1, ax2) = plt.subplots(ncols=2)
# the first subplot remains unchanged
ax1.plot(np.random.rand(10))
# the second one gets another projection
make_ax_map(ax2)

Конечно, я могу просто использовать fig.add_subplot():

fig = plt.figure(figsize=(10,5))
ax1 = fig.add_subplot(121)
ax1.plot(np.random.rand(10))

ax2 = fig.add_subplot(122,projection=ccrs.PlateCarree())
ax2.coastlines()

но мне было интересно, есть ли подходящий метод matplotlib для изменения проекции оси подзаголовка после того, как он был определен. Чтение matplotlib API не помогло, к сожалению.

Ответ 1

Вы не можете изменить проекцию существующих осей, причина приведена ниже. Однако решение вашей основной проблемой является просто использовать subplot_kw аргумент plt.subplots(), описанной в Matplotlib документации здесь. Например, если вы хотите, чтобы все ваши cartopy.crs.PlateCarree проекцию cartopy.crs.PlateCarree вы могли бы сделать

import matplotlib.pyplot as plt
import cartopy.crs as ccrs

# Create a grid of plots
fig, (ax1, ax2) = plt.subplots(ncols=2, subplot_kw={'projection': ccrs.PlateCarree()})

Что касается фактического вопроса, указание проекции при создании набора осей определяет класс осей, который вы получаете, что отличается для каждого типа проекции. Например

import matplotlib.pyplot as plt
import cartopy.crs as ccrs

ax1 = plt.subplot(311)
ax2 = plt.subplot(312, projection='polar')
ax3 = plt.subplot(313, projection=ccrs.PlateCarree())

print(type(ax1))
print(type(ax2))
print(type(ax3))

Этот код напечатает следующие

<class 'matplotlib.axes._subplots.AxesSubplot'>
<class 'matplotlib.axes._subplots.PolarAxesSubplot'>
<class 'cartopy.mpl.geoaxes.GeoAxesSubplot'>

Обратите внимание, как каждая ось является экземпляром другого класса.

Ответ 2

после ответа на этот вопрос:

В Python, как я могу наследовать и переопределять метод в экземпляре класса, назначая этой новой версии то же имя, что и старой?

Я нашел хак для изменения проекции топора после его создания, который, кажется, работает, по крайней мере, в простом примере ниже, но я понятия не имею, является ли это решение лучшим способом

from matplotlib.axes import Axes
from matplotlib.projections import register_projection

class CustomAxe(Axes):
    name = 'customaxe'

    def plotko(self, x):
        self.plot(x, 'ko')
        self.set_title('CustomAxe')

register_projection(CustomAxe)


if __name__ == '__main__':
    import matplotlib.pyplot as plt

    fig = plt.figure()

    ## use this syntax to create a customaxe directly
    # ax = fig.add_subplot(111, projection="customaxe")

    ## change the projection after creation
    ax = plt.gca()
    ax.__class__ = CustomAxe

    ax.plotko(range(10))    
    plt.show()