Estoy escribiendo un sistema de software que visualiza cortes y proyecciones a través de un conjunto de datos 3D. Estoy usando matplotlib
y específicamente imshow
para visualizar los búferes de imágenes que obtengo de mi código de análisis.
Como me gustaría anotar las imágenes con ejes de trazado, utilizo la palabra clave de extensión que imshow
proporciona para asignar las coordenadas de píxeles del búfer de imagen a un sistema de coordenadas del espacio de datos.
Desafortunadamente, matplotlib
no sabe de unidades. Digamos (tomando un ejemplo artificial) que quiero trazar una imagen con dimensiones de 1000 m X 1 km
. En ese caso, la extensión sería algo así como [0, 1000, 0, 1]
. Aunque la matriz de imágenes es cuadrada, dado que la relación de aspecto implícita en la palabra clave de extensión es 1000, los ejes de trazado resultantes también tienen una relación de aspecto de 1000.
¿Es posible forzar la relación de aspecto del gráfico mientras se mantienen las marcas de graduación y etiquetas principales generadas automáticamente que obtengo al usar la palabra clave de extensión?
fuente
scalar
opción. Parece escalar ely-axis
por el escalar dado.Por
plt.imshow()
guía oficial, sabemos que el aspecto controla la relación de aspecto de los ejes. Bueno, en mis palabras, el aspecto es exactamente la relación entre la unidad x y la unidad y . La mayoría de las veces queremos mantenerlo como 1 ya que no queremos distorsionar las cifras sin querer. Sin embargo, hay casos en los que necesitamos especificar un aspecto con un valor distinto de 1. El interrogador proporcionó un buen ejemplo de que los ejes xey pueden tener diferentes unidades físicas. Supongamos que x está en km y y en m. Por lo tanto, para datos de 10x10, la extensión debe ser [0,10 km, 0,10 m] = [0, 10000 m, 0, 10 m]. En tal caso, si seguimos usando el aspecto predeterminado = 1, la calidad de la figura es realmente mala. Por lo tanto, podemos especificar el aspecto = 1000 para optimizar nuestra figura. Los siguientes códigos ilustran este método.%matplotlib inline import numpy as np import matplotlib.pyplot as plt rng=np.random.RandomState(0) data=rng.randn(10,10) plt.imshow(data, origin = 'lower', extent = [0, 10000, 0, 10], aspect = 1000)
Sin embargo, creo que hay una alternativa que puede satisfacer la demanda del interrogador. Podemos simplemente establecer la extensión como [0,10,0,10] y agregar etiquetas de eje xy adicionales para denotar las unidades. Códigos de la siguiente manera.
plt.imshow(data, origin = 'lower', extent = [0, 10, 0, 10]) plt.xlabel('km') plt.ylabel('m')
Para hacer una figura correcta , siempre debemos tener en cuenta eso
x_max-x_min = x_res * data.shape[1]
yy_max - y_min = y_res * data.shape[0]
dóndeextent = [x_min, x_max, y_min, y_max]
. De forma predeterminada,aspect = 1
lo que significa que la unidad de píxel es cuadrada. Este comportamiento predeterminado también funciona bien para x_res e y_res que tienen valores diferentes. Ampliando el ejemplo anterior, supongamos que x_res es 1,5 mientras que y_res es 1. Por tanto, la extensión debe ser igual a [0,15,0,10]. Usando el aspecto predeterminado, podemos tener píxeles de color rectangulares, ¡mientras que el píxel unitario sigue siendo cuadrado!plt.imshow(data, origin = 'lower', extent = [0, 15, 0, 10]) # Or we have similar x_max and y_max but different data.shape, leading to different color pixel res. data=rng.randn(10,5) plt.imshow(data, origin = 'lower', extent = [0, 5, 0, 5])
El aspecto del píxel de color es
x_res / y_res
. establecer su aspecto en el aspecto del píxel unitario (es deciraspect = x_res / y_res = ((x_max - x_min) / data.shape[1]) / ((y_max - y_min) / data.shape[0])
) siempre daría un píxel de color cuadrado. Podemos cambiar el aspecto = 1,5 para que la unidad del eje x sea 1,5 veces la unidad del eje y, lo que da como resultado un píxel de color cuadrado y una figura completa cuadrada pero una unidad de píxel rectangular. Al parecer, normalmente no se acepta.data=rng.randn(10,10) plt.imshow(data, origin = 'lower', extent = [0, 15, 0, 10], aspect = 1.5)
El caso más indeseado es el de establecer un aspecto con un valor arbitrario, como 1.2, que no dará lugar a píxeles unitarios cuadrados ni píxeles de color cuadrados.
plt.imshow(data, origin = 'lower', extent = [0, 15, 0, 10], aspect = 1.2)
En pocas palabras, siempre es suficiente establecer la extensión correcta y dejar que matplotlib haga las cosas restantes por nosotros (¡aunque x_res! = Y_res). Cambie de aspecto solo cuando sea necesario.
fuente