¿Cómo cambio la proyección de subtrama de matplotlib de un eje existente?

4 minutos de lectura

Avatar de usuario de Denis Sergeev
denis sergeev

Estoy tratando de construir una función simple que tome una instancia de subtrama (matplotlib.axes._subplots.AxesSubplot) y transforma su proyección a otra proyección, por ejemplo, a una de las cartopy.crs.CRS proyecciones.

La idea se parece a esto

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)

Por supuesto, puedo usar fig.add_subplot() función:

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

pero me preguntaba si hay una adecuada matplotlib método para cambiar la proyección de un eje de subtrama después fue definido. Desafortunadamente, leer la API de matplotlib no ayudó.

No puede cambiar la proyección de un eje existente, el motivo se indica a continuación. Sin embargo, la solución a su problema subyacente es simplemente usar el subplot_kw argumento a plt.subplots() descrito en la documentación de matplotlib aquí. Por ejemplo, si quisiera que todas sus subparcelas tuvieran el cartopy.crs.PlateCarree proyección que podrías hacer

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

Con respecto a la pregunta real, especificar una proyección cuando crea un conjunto de ejes determina la clase de ejes que obtiene, que es diferente para cada tipo de proyección. Por ejemplo

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

Este código imprimirá lo siguiente

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

Observe cómo cada eje es en realidad una instancia de una clase diferente.

  • ¡Gracias! Y solo para confirmar, el projection La palabra clave determina la clase para todas las subparcelas a la vez, por lo que no hay forma de pasar varias proyecciones en subplot_kw? P.ej projection='polar' para la primera columna y projection=ccrs.PlateCarree() para la segunda columna de un conjunto de subtramas creado por plt.subplots(ncols=2)?

    – Denis Serguéiev

    6 de enero de 2016 a las 9:19


  • Las palabras clave en subplot_kw se pasan a cada eje, por lo que no creo que puedas hacer lo que describes. los subplots La función es un contenedor de conveniencia para atender el caso de uso básico, si necesita algo más, puede escribir su propia función de contenedor usando add_subplot o similar.

    – ajdawson

    7 de enero de 2016 a las 9:42

  • ¿Hay alguna manera de hacer esto con ImageGrid? Sería bueno poder tener el control sobre el espaciado del mapa y la ubicación de la barra de colores que permite ImageGrid, pero no veo una forma de establecer la proyección de las subparcelas en la cuadrícula.

    –Daniel Watkins

    14 de noviembre de 2017 a las 0:33

  • Sí, es posible usando axes_class palabra clave en ImageGrid (o AxesGrid). Hay un ejemplo en la galería de cartopy. También hubo un PR para cartopy (aunque no aceptado) que se puede usar para crear un personalizado GeoAxesGrid clase.

    – Denis Serguéiev

    15 de noviembre de 2017 a las 21:08


avatar de usuario de dominecf
dominar

Suponiendo que se utilizan varios ejes para el trazado 2D, como…

fig = matplotlib.pyplot.Figure()
axs = fig.subplots(3, 4) # prepare for multiple subplots
# (some plotting here)
axs[0,0].plot([1,2,3])

… uno puede simplemente destruir uno de ellos y reemplazarlo por uno nuevo que tenga la proyección 3D:

axs[2,3].remove()
ax = fig.add_subplot(3, 4, 12, projection='3d')
ax.plot_surface(...)

Solo tenga en cuenta que, a diferencia del resto de Python, el add_subplot utiliza la indexación fila-columna comenzando de 1 (no desde 0).

EDITAR: Cambié mi error tipográfico sobre la indexación.

avatar de usuario de user2660966
usuario2660966

siguiendo la respuesta a esta pregunta:

En Python, ¿cómo puedo heredar y anular un método en una instancia de clase, asignando esta nueva versión al mismo nombre que la anterior?

Encontré un truco para cambiar la proyección de un hacha después de crearlo que parece funcionar al menos en el ejemplo simple a continuación, pero no tengo idea si esta solución es la mejor manera

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

  • no funciona….

    – Alí

    5 oct a las 17:28

¿Ha sido útil esta solución?