2011-02-26 15 views
10

Entonces tengo una malla de malla (matrices X e Y) junto con datos escalares (matriz Z), y necesito visualizar esto. Preferentemente, una imagen 2D con colores en los puntos que muestran el valor de Z allí. He hecho algunas investigaciones pero no he encontrado nada que haga exactamente lo que quiero.¿Cómo visualizar datos 2D escalares con Matplotlib?

pyplot.imshow (Z) tiene un buen aspecto, pero no toma mis matrices X e Y, por lo que los ejes son incorrectos y no es capaz de manejar los puntos espaciados no linealmente dados por X e Y.

pyplot.pcolor (X, Y, Z) hace cuadrados de colores con los colores correspondientes a los datos en una de sus esquinas, por lo que tergiversa los datos (debe mostrar los datos en su centro o algo así). Además, ignora dos de los bordes de la matriz de datos.

Estoy bastante seguro de que debe existir una forma mejor en algún lugar en Matplotlib, pero la documentación hace que sea difícil obtener una visión general. Entonces, estoy preguntando si alguien más sabe de una mejor manera. Bonificación si me permite actualizar la matriz Z para hacer una animación.

Respuesta

9

Esto se ve bien, pero es ineficiente:

from pylab import * 
origin = 'lower' 

delta = 0.025 

x = y = arange(-3.0, 3.01, delta) 
X, Y = meshgrid(x, y) 
Z1 = bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0) 
Z2 = bivariate_normal(X, Y, 1.5, 0.5, 1, 1) 
Z = 10 * (Z1 - Z2) 

nr, nc = Z.shape 

CS = contourf(
    X, Y, Z, 
    levels = linspace(Z.min(), Z.max(), len(x)), 
    ls = '-', 
    cmap=cm.bone, 
    origin=origin) 

CS1 = contour(
    CS, 
    levels = linspace(Z.min(), Z.max(), len(x)), 
    ls = '-', 
    cmap=cm.bone, 
    origin=origin) 

show() 

Si fuera yo, volvería a interpolar (usando scipy.interpolate) los datos a una grilla normal y usar imshow(), estableciendo las extensiones para fijar los ejes.

fine contour

Edit (por comentario):

Animación de un gráfico de contorno se puede realizar como este, pero, como dije, lo anterior es ineficiente abuso simplemente de la función de gráfico de contorno. La forma más eficiente de hacer lo que desea es emplear SciPy. ¿Lo tienes instalado?

import matplotlib 
matplotlib.use('TkAgg') # do this before importing pylab 
import time 
import matplotlib.pyplot as plt 

fig = plt.figure() 
ax = fig.add_subplot(111) 

def animate(): 
    origin = 'lower' 
    delta = 0.025 

    x = y = arange(-3.0, 3.01, delta) 
    X, Y = meshgrid(x, y) 
    Z1 = bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0) 
    Z2 = bivariate_normal(X, Y, 1.5, 0.5, 1, 1) 
    Z = 10 * (Z1 - Z2) 

    CS1 = ax.contourf(
     X, Y, Z, 
     levels = linspace(Z.min(), Z.max(), 10), 
     cmap=cm.bone, 
     origin=origin) 

    for i in range(10): 
     tempCS1 = contourf(
      X, Y, Z, 
      levels = linspace(Z.min(), Z.max(), 10), 
      cmap=cm.bone, 
      origin=origin) 
     del tempCS1 
     fig.canvas.draw() 
     time.sleep(0.1) 
     Z += x/10 

win = fig.canvas.manager.window 
fig.canvas.manager.window.after(100, animate) 
plt.show() 
+0

Gracias. ¿Es posible actualizar los datos en este objeto CS para que pueda hacer algún tipo de animación en un bucle? – Eskil

+0

@Eskil: mira mi actualización. – Paul

+0

Sí, tengo Scipy. Pero pensé que Scipy usó Matplotlib para todos los planes. ¿Tiene su propia funcionalidad de trazado independiente también? – Eskil

2

Si su malla de malla tiene un espaciado uniforme, puede continuar utilizando pcolor, pero simplemente cambie X e Y a los efectos de centrar los datos en los valores particulares en lugar de en las esquinas.

También es posible usar un diagrama de dispersión para colocar de forma explícita puntos de cierto tamaño en la X exacta y los puntos de Y a continuación, establecer el color a la Z:

x = numpy.arange(10) 
y = numpy.arange(10) 
X,Y = numpy.meshgrid(x,y) 
Z = numpy.arange(100).reshape((10,10)) 
scatter(X,Y,c=Z,marker='s',s=1500) 
#I picked a marker size that basically overlapped the symbols at the edges 
axis('equal') 

o:

pcolor(X+0.5,Y+0.5,Z) 
axis('equal') 

o como sugirió Paul, usando una de las funciones de contorno

1

En caso de que alguien viene a través de este artículo en busca de lo que estaba buscando, tomé el ejemplo anterior y lo modificó para utilizar imshow con una pila de entrada de marcos, en lugar de generar y utilizar contornos sobre la marcha. Comenzando con una matriz 3D de imágenes de forma (nBins, nBins, nBins), llamada frames.

def animate_frames(frames): 
    nBins = frames.shape[0] 
    frame = frames[0] 
    tempCS1 = plt.imshow(frame, cmap=plt.cm.gray) 
    for k in range(nBins): 
     frame = frames[k] 
     tempCS1 = plt.imshow(frame, cmap=plt.cm.gray) 
     del tempCS1 
     fig.canvas.draw() 
     #time.sleep(1e-2) #unnecessary, but useful 
     fig.clf() 

fig = plt.figure() 
ax = fig.add_subplot(111) 

win = fig.canvas.manager.window 
fig.canvas.manager.window.after(100, animate_frames, frames) 

También he encontrado una manera mucho más sencilla de ir sobre todo este proceso, aunque menos robusta:

fig = plt.figure() 

for k in range(nBins): 
    plt.clf() 
    plt.imshow(frames[k],cmap=plt.cm.gray) 
    fig.canvas.draw() 
    time.sleep(1e-6) #unnecessary, but useful 

Tenga en cuenta que ambos éstos sólo parecen trabajar con ipython --pylab=tk, también denominadobackend = TkAgg

Gracias por la ayuda con todo.

0

La siguiente función crea cuadros de la mitad del tamaño en el límite (como se muestra en la imagen adjunta).

import matplotlib.pyplot as plt 
import numpy as np 
from scipy.ndimage.filters import convolve 

def pcolor_all(X, Y, C, **kwargs): 
    X = np.concatenate([X[0:1,:], X], axis=0) 
    X = np.concatenate([X[:,0:1], X], axis=1) 

    Y = np.concatenate([Y[0:1,:], Y], axis=0) 
    Y = np.concatenate([Y[:,0:1], Y], axis=1) 

    X = convolve(X, [[1,1],[1,1]])/4 
    Y = convolve(Y, [[1,1],[1,1]])/4 

    plt.pcolor(X, Y, C, **kwargs) 

X, Y = np.meshgrid(
    [-1,-0.5,0,0.5,1], 
    [-2,-1,0,1,2]) 

C = X**2-Y**2 

plt.figure(figsize=(4,4)) 

pcolor_all(X, Y, C, cmap='gray') 

plt.savefig('plot.png') 

plot.png

Cuestiones relacionadas