Relación de aspecto en subplots con varios ejes y

Me gustaría que el siguiente código produzca 4 subplots del mismo tamaño con una relación de aspecto común entre el tamaño del eje x y el eje y establecido por mí. Refiriéndose al ejemplo de abajo, me gustaría que todas las subplots se vean exactamente como la primera (arriba a la izquierda). Lo que está mal ahora es que el tamaño del eje y está correlacionado con su valor más grande. Ese es el comportamiento que quiero evitar.

import matplotlib.pyplot as plt import numpy as np def main(): fig = plt.figure(1, [5.5, 3]) for i in range(1,5): fig.add_subplot(221+i-1, adjustable='box', aspect=1) plt.plot(np.arange(0,(i)*4,i)) plt.show() if __name__ == "__main__": main() 

Sorprendentemente, matplotlib produce lo correcto de manera predeterminada (imagen de abajo):

  import matplotlib.pyplot as plt import numpy as np def main(): fig = plt.figure(1, [5.5, 3]) for i in range(1,5): fig.add_subplot(221+i-1) plt.plot(np.arange(0,(i)*4,i)) plt.show() 

Solo quiero agregar a esto una capacidad para controlar la relación de aspecto entre las longitudes de los ejes x y y.

Esto es lo que estoy buscando:

No puedo decir lo que quieres de tu pregunta.

¿Desea que todos los gráficos tengan los mismos límites de datos?

Si es así, use ejes compartidos (aquí estoy usando subplots , pero puede evitarlo si desea mantener el código de estilo matlab):

 import matplotlib.pyplot as plt import numpy as np fig, axes = plt.subplots(nrows=2, ncols=2, sharey=True, sharex=True) for i, ax in enumerate(axes.flat, start=1): ax.set(aspect=1) ax.plot(np.arange(0, i * 4, i)) plt.show() 

introduzca la descripción de la imagen aquí

Si desea que todos compartan sus límites de ejes, pero que tengan adjustable='box' (es decir, límites de ejes no cuadrados), use adjustable='box-forced' :

 import matplotlib.pyplot as plt import numpy as np fig, axes = plt.subplots(nrows=2, ncols=2, sharey=True, sharex=True) for i, ax in enumerate(axes.flat, start=1): ax.set(aspect=1, adjustable='box-forced', xticks=range(i)) ax.plot(np.arange(0, i * 4, i)) plt.show() 

introduzca la descripción de la imagen aquí


Edit: Lo siento, todavía estoy un poco confundido. ¿Quieres algo como esto?

 import matplotlib.pyplot as plt import numpy as np fig, axes = plt.subplots(nrows=2, ncols=2) for i, ax in enumerate(axes.flat, start=1): ax.set(adjustable='datalim', aspect=1) ax.plot(np.arange(0, i * 4, i)) plt.show() 

introduzca la descripción de la imagen aquí


Está bien, creo que finalmente entiendo tu pregunta. Ambos queríamos decir cosas completamente diferentes por “relación de aspecto”.

En matplotlib, la relación de aspecto de la gráfica se refiere a las escalas relativas de los límites de datos. En otras palabras, si la relación de aspecto de la gráfica es 1, una línea con una pendiente de uno aparecerá a 45 grados. Estabas suponiendo que la relación de aspecto se aplicaba al contorno de los ejes y no a los datos representados en los ejes.

Solo quieres que el contorno de las subplots sea cuadrado. (En cuyo caso, todos tienen diferentes relaciones de aspecto, según lo define matplotlib).

En ese caso, necesitas una figura cuadrada. (Hay otras formas, pero hacer una figura cuadrada es mucho más simple. Los ejes de Matplotlib llenan un espacio que es proporcional al tamaño de la figura en la que están).

 import matplotlib.pyplot as plt import numpy as np # The key here is the figsize (it needs to be square). The position and size of # axes in matplotlib are defined relative to the size of the figure. fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(8,8)) for i, ax in enumerate(axes.flat, start=1): ax.plot(np.arange(0, i * 4, i)) # By default, subplots leave a bit of room for tick labels on the left. # We'll remove it so that the axes are perfectly square. fig.subplots_adjust(left=0.1) plt.show() 

introduzca la descripción de la imagen aquí

¿Combinando la respuesta de Joe Kington con el nuevo estilo python para las plots cuadradas de ejes compartidos en matplotlib? y otra publicación que me temo que no puedo encontrar de nuevo, hice un código para establecer con precisión la proporción de la caja a un valor dado.

Deje que desired_box_ratioN indique la proporción deseada entre los lados y y x de la caja. temp_inverse_axis_ratioN es la relación entre los lados x e y de la gráfica actual; ya que ‘aspecto’ es la relación entre la escala y y la escala x (y no los ejes), debemos establecer el aspecto en el cuadro_caja_descado * temp_inverse_axis_ratioN.

 import matplotlib.pyplot as plt import numpy as np fig, axes = plt.subplots(nrows=2, ncols=2) desired_box_ratioN = 1 for i, ax in enumerate(axes.flat, start=1): ax.plot(np.arange(0, i * 4, i)) temp_inverse_axis_ratioN = abs( (ax.get_xlim()[1] - ax.get_xlim()[0])/(ax.get_ylim()[1] - ax.get_ylim()[0]) ) ax.set(aspect = desired_box_ratioN * temp_inverse_axis_ratioN, adjustable='box-forced') plt.show() 

La teoría

Existen diferentes sistemas de coordenadas en matplotlib. Las diferencias entre los diferentes sistemas de coordenadas pueden realmente confundir a mucha gente. Lo que el OP desea es la relación de aspecto en la coordenada de visualización, pero ax.set_aspect() está configurando la relación de aspecto en la coordenada de datos. Su relación puede ser formulada como:

 aspect = 1.0/dataRatio*dispRatio 

donde, aspect es el argumento a utilizar en el método set_aspect , dataRatio es relación de aspecto en coordenadas de datos y dispRatio es la relación de aspecto deseada en coordenadas de visualización.

La práctica

Existe un método get_data_ratio que podemos usar para hacer nuestro código más conciso. A continuación se muestra un fragmento de código de trabajo:

 import matplotlib.pyplot as plt import numpy as np fig, axes = plt.subplots(nrows=2, ncols=2) dispRatio = 0.5 for i, ax in enumerate(axes.flat, start=1): ax.plot(np.arange(0, i * 4, i)) ax.set(aspect=1.0/ax.get_data_ratio()*dispRatio, adjustable='box-forced') plt.show() 

También he escrito un post detallado sobre todo esto aquí .