Jerarquía en matplotlib

Según este artículo, todo en matplotlib se organiza en una jerarquía. En la parte superior de la jerarquía se encuentra el “entorno de máquina de estado” de matplotlib que proporciona el módulo matplotlib.pyplot . En este nivel, las funciones simples se utilizan para agregar elementos de trazado (líneas, imágenes, texto, etc.) a los ejes actuales en la figura actual. El siguiente nivel en la jerarquía es el primer nivel de la interfaz orientada a objetos, en la cual pyplot se usa solo para unas pocas funciones, como la creación de figuras, y el usuario crea explícitamente y realiza un seguimiento de los objetos de figuras y ejes. En este nivel, el usuario utiliza pyplot para crear figuras y, a través de esas figuras, se pueden crear uno o más objetos de ejes. Estos objetos de ejes se utilizan para la mayoría de las acciones de trazado. También hay otros términos como Figura, Ejes, Eje, Artista (hay una buena imagen que explica todos esos, en la página mencionada). En resumen:

  1. Todo pertenece al módulo matplotlib.pyplot
  2. Figura: realiza un seguimiento de todos los Axes infantiles, un puñado de artistas “especiales” (títulos, leyendas de figuras, etc.)
  3. Los ejes – región de la imagen con el espacio de datos – pertenece a la Figura
  4. Eje: cadenas que marcan las marcas (coordenadas x, y, z, etc.) – pertenece a los ejes
  5. Artista: todo lo que puede ver en la figura (incluso los objetos Figura, Ejes y Eje) pertenece a la Figura

La forma más fácil de crear una nueva figura es con pyplot:

 fig = plt.figure() # an empty figure with no axes fig, ax_lst = plt.subplots(2, 2) # a figure with a 2x2 grid of Axes 

A menudo he visto que estos dos enfoques se usan indistintamente, y esperaba que fueran básicamente equivalentes. Pero no puedo lograr el mismo resultado usando fig, ax = plt.subplots() como obtengo usando fig = plt.figure() y ax = fig.add_subplot(111, projection='3d')

Aquí están mis experimentos, para plt.figure() :

 In [1]: from mpl_toolkits.mplot3d import Axes3D In [2]: import matplotlib.pyplot as plt In [3]: fig = plt.figure() In [4]: ax = fig.add_subplot(111, projection='3d') In [5]: fig Out[5]:  In [6]: ax Out[6]:  In [7]: 

Aquí están mis experimentos, para plt.subplots() :

 In [1]: from mpl_toolkits.mplot3d import Axes3D In [2]: import matplotlib.pyplot as plt In [3]: fig, ax = plt.subplots() In [4]: fig Out[4]:  In [5]: ax Out[5]:  In [6]: 

Como puede ver, la primera crea el objeto matplotlib.axes._subplots.Axes3DSubplot mientras que la segunda crea el objeto matplotlib.axes._subplots.AxesSubplot . He estado buscando help(plt.subplots) en la palabra clave de projection help(plt.subplots) pero no encontré nada. Así que he intentado usar los mismos argumentos para plt.subplots que para fig.add_subplot pero obtengo el siguiente error:

 In [7]: fig, ax = plt.subplots(111, projection='3d') --------------------------------------------------------------------------- TypeError Traceback (most recent call last)  in () ----> 1 fig, ax = plt.subplots(111, projection='3d') /usr/lib/python2.7/dist-packages/matplotlib/pyplot.pyc in subplots(nrows, ncols, sharex, sharey, squeeze, subplot_kw, gridspec_kw, **fig_kw) 1076 gridspec_kw = {} 1077 -> 1078 fig = figure(**fig_kw) 1079 gs = GridSpec(nrows, ncols, **gridspec_kw) 1080 /usr/lib/python2.7/dist-packages/matplotlib/pyplot.pyc in figure(num, figsize, dpi, facecolor, edgecolor, frameon, FigureClass, **kwargs) 433 frameon=frameon, 434 FigureClass=FigureClass, --> 435 **kwargs) 436 437 if figLabel: /usr/lib/python2.7/dist-packages/matplotlib/backends/backend_tkagg.pyc in new_figure_manager(num, *args, **kwargs) 78 """ 79 FigureClass = kwargs.pop('FigureClass', Figure) ---> 80 figure = FigureClass(*args, **kwargs) 81 return new_figure_manager_given_figure(num, figure) 82 TypeError: __init__() got an unexpected keyword argument 'projection' 

Pregunta:

Son fig, ax = plt.subplots() y fig = plt.figure(); ax = fig.add_subplot(111, projection='3d') fig = plt.figure(); ax = fig.add_subplot(111, projection='3d') equivalentes, si es así, ¿cómo puedo usar fig, ax = plt.subplots() en mi ejemplo?

En la página mencionada también hay el siguiente código:

 #!/bin/env python import matplotlib.pyplot as plt import numpy as np x = np.linspace(0, 2, 100) # The first call to plt.plot will automatically create the necessary figure and axes to achieve the desired plot. plt.plot(x, x, label='linear') # Subsequent calls to plt.plot re-use the current axes and each add another line. plt.plot(x, x**2, label='quadratic') plt.plot(x, x**3, label='cubic') # Setting the title, legend, and axis labels also automatically use the current axes and set the title, create the legend, and label the axis respectively. plt.xlabel('x label') plt.ylabel('y label') plt.title("Simple Plot") plt.legend() plt.show() 

Como puede ver, no hay tales funciones fig = plt.figure() ni fig, ax_lst = plt.subplots(2, 2)

Pregunta:

¿Cómo se mantiene la jerarquía en este ejemplo, se crea la Figura por defecto o qué está pasando?

Pregunta 1

Creo que has demostrado por ti mismo que los comandos no son completamente equivalentes y solo quiero un poco de seguridad de esto.

Para hacer lo que quiere hacer, puede pasar la projection a las llamadas add_subplot() que se usan ‘bajo la cubierta’ al configurar un diccionario de argumentos de subplot y pasarlos, por ejemplo,

 from mpl_toolkits.mplot3d import Axes3D import matplotlib.pyplot as plt subplot_args = {'projection':'3d'} fig, ax = plt.subplots(subplot_kw=subplot_args) 

El uso del argumento llamado subplot_kw se describe en los documentos aquí .

Pregunta 2

Los ejes de las figuras, etc., se crean todos ‘debajo de las cubiertas’ en la primera línea que comienza en plt.plot . El módulo pyplot mantiene el estado y reutiliza la misma instancia de figura y ejes hasta que llama a plt.show() .

Nota: tal como está, no tiene un controlador para estas instancias. Siempre puede obtener un identificador si lo desea, por ejemplo, llamando

 fig = plt.gcf() 

y

 ax = plt.gca() 

donde gcf() y gca() son obtener la figura actual y obtener los ejes actuales respectivamente. Esto se basa en la funcionalidad matlab en la que se basó originalmente matplotlib.

Si está realmente interesado en ver cómo se realiza la creación automática, todo es de código abierto. Puede ver que la llamada a plot() crea una instancia de Axes mediante una llamada a gca() en el código aquí . A su vez, esto llama a gcf() , que busca un FigureManager (que es lo que realmente mantiene el estado). Si existe, devuelve la figura que está administrando; de lo contrario, crea una nueva usando plt.figure() . De nuevo, este proceso hasta cierto punto se hereda de matlab, donde la llamada inicial suele figure antes de cualquier operación de trazado.


Apéndice

Creo que en lo que podría estar manejando es cómo el uso de las funciones plt.plot() como plt.plot() etc., le da acceso a la jerarquía como se describe en la documentación. La respuesta es que si quieres un control realmente fino, a veces no es así. Es por eso que la gente usa el

 fig, ax = plt.subplots() 

Patrón o similar para que tengan manijas para los objetos de la figura y los ejes directamente y puedan manipularlos a su gusto.