2012-03-28 20 views
5

Estoy tratando de trazar una imagen pequeña en python usando matplotlib y me gustaría que los ejes mostrados tengan la misma forma que la matriz numpy desde la que se generó, es decir, los datos no se deben volver a muestrear. En otras palabras, cada entrada en la matriz debe corresponder a un píxel (o aproximadamente) en la pantalla. Esto parece trivial, pero incluso después de buscar en la Internet para rato, me parece que no puede conseguir que funcione:matplotlib gráfico imagen pequeña sin remuestreo

import numpy as np 
import matplotlib.pyplot as plt 
import matplotlib.cm as cm 

X = np.random.rand(30,40) 

fig = plt.figure() 
fig.add_axes(aspect="equal",extent=[0, X.shape[1], 0, X.shape[0]]) 
ax = fig.gca() 
ax.autoscale_view(True, False, False) 
ax.imshow(X, cmap = cm.gray) 

plt.show() 
+2

parece que el código que proporcionó tiene el truco que desea, la forma rectangular (40x30) se conserva en la imagen graficada, y los límites del eje coinciden con la forma de la imagen. ¿Extraño algo en tu pregunta? – gcalmettes

+0

Lo siento mi fraseo es confuso. Lo que me interesa es algo así como la funcionalidad imshow en matlab, donde el número de píxeles en la pantalla coincide con el número de entradas en la matriz, es decir, los ejes no se remuestrean para que coincidan con el tamaño de la figura. – user588241

+1

¿Quiere decir que tiene una imagen sin interpolación? Si es así, simplemente cambie su código 'imshow' con' matshow', o agregue 'interpolation = 'nearest'' como parámetro para la función imshow. – carla

Respuesta

5

He tenido el mismo problema yo mismo. Si la opción interpolation='nearest' a imshow no es lo suficientemente buena, bien si su objetivo principal es ver píxeles sin procesar, sin escalar, sin interpolación ni suciedad en matplotlib, entonces no puede vencer a figimage en mi humilde opinión. Demostración:

import numpy as np 
import numpy.random 
import matplotlib.pyplot as plt 

a=256*np.random.rand(64,64) 

f0=plt.figure() 
plt.imshow(a,cmap=plt.gray()) 
plt.suptitle("imshow") 

f1=plt.figure() 
plt.figimage(a,cmap=plt.gray()) 
plt.suptitle("figimage") 

plt.show() 

Por supuesto, eso significa renunciar a los ejes (o atrayéndolos a sí mismo de alguna manera). Hay algunas opciones para figimage que le permiten mover la imagen alrededor de la figura, así que supongo que podría ser posible maniobrarlas sobre algunos ejes creados por otros medios.

+1

En caso de que alguien se lo esté preguntando, la única forma en que pude hacer que figuritara trabajar sin nada en la trama excepto la imagen en Ipython Notebook fue agregando un conjunto de ejes vacío ("apagado") antes de plt.show() , similar a esta publicación de S/O: http://stackoverflow.com/questions/9295026/matplotlib-plots-removing-axis-legends-and-white-spaces. De lo contrario, simplemente no tramaba nada. –

1

No estoy seguro de entender completamente su pregunta. ¿Significa esto que quieres el eje x entre 0 y X.shape [1] y el eje y entre 0 y X.shape [0]? En este caso, el código debe hacer el truco:

import numpy as np 
import matplotlib.pyplot as plt 
import matplotlib.cm as cm 

X = np.random.rand(30,40) 

fig = plt.figure() 

plt.xlim(0, X.shape[1]) 
plt.ylim(0, X.shape[0]) 

ax = fig.gca() 
ax.autoscale_view(True, False, False) 
ax.imshow(X, cmap = cm.gray) 

plt.show() 

creo que sirve

+0

Gracias, lo siento si mi pregunta fue confusa. Intento hacer algo como imshow en Matlab, donde los ejes dentro de la figura son del mismo tamaño que la matriz, p. cada píxel en la pantalla corresponde a una entrada en la matriz. Lo anterior reescala y remuestrea la matriz para que coincida con el tamaño de la figura. – user588241

+0

Acabo de encontrar una publicación smiliar en stackoverflow, usan el argumento de interpolación de imshow: ax.imshow (X, cmap = cm.gray, extent = (0, X.shape [1], 0, X.shape [0]), interpolación = 'más cercano') Aquí está el enlace http: // stackoverflow.com/questions/6323737/make-a-2d-pixel-plot-with-matplotlib – nay

+0

Gracias, usar la interpolación del vecino más cercano es bueno, pero también me gustaría que los ejes sean pequeños, es decir, para que refleje más fielmente el tamaño real de la matriz Actualmente, parece que los ejes aún se cambian de escala para que coincida con el tamaño de la figura. – user588241

1

Si conoce la resolución original de la imagen, se puede establecer el argumento dpi a lo que quiere en la plt.figure(dpi=value).

Puede encontrar más información sobre cómo ajustar el tamaño de la imagen en este link.

3

Puede usar el siguiente fragmento de código para convertir una matriz en una PIL (Python Imaging Library). La imagen resultante tendrá el mismo tamaño que la matriz de entrada. Se puede mostrar o guardar como una imagen.

from PIL import Image 
from numpy import linspace, array, fromfunction, sin, cos 
from matplotlib import cm 


# scale array between vmin and vmax and encode it to uint8 (256 values) 
def scale(arr, vmin, vmax): 
    return (255*(arr - vmin)/(vmax - vmin)).clip(0, 255).astype('uint8') 

# convert a matplotlib colormap into a PIL palette 
def getpalette(cmap): 
    return (255.*array(map(lambda x: cmap(x)[0:3], linspace(0., 1.,256))).ravel()).astype('int') 


# a sample array 
data = fromfunction(lambda i,j: cos((i+j)/50)*sin(i/50.), (200, 300), dtype='float') 

# convert the float array to a PIL image 
im = Image.fromarray(scale(data, 0, 1)) 
im.putpalette(getpalette(cm.jet)) 
im.save('test.png') # or im.show() 

La única cosa es que im.show() no es muy bueno, ya que requiere tener el visor de imágenes xv y se escribe una imagen temporal. Así que también puede escribir un archivo y cargarlo con su visor de imágenes favorito.

Cuestiones relacionadas