Как визуализировать скалярные 2D-данные с помощью Matplotlib?
Итак, у меня есть meshgrid (матрицы X и Y) вместе со скалярными данными (матрица Z), и мне нужно визуализировать это. Предпочтительно некоторое двумерное изображение с цветами в точках, показывающих значение Z.
Я провел некоторое исследование, но не нашел ничего, что делает именно то, что я хочу.
pyplot.imshow(Z) имеет хороший внешний вид, но он не принимает мои X и Y-матрицы, поэтому оси неправильны и не могут обрабатывать нелиноразмерные точки, заданные X и Y.
pyplot.pcolor(X, Y, Z) создает цветные квадраты с цветами, соответствующими данным в одном из его углов, поэтому он искажает данные (он должен показывать данные в своем центре или что-то еще). Кроме того, он игнорирует два ребра из матрицы данных.
Я уверен, что в Matplotlib должен быть какой-то лучший способ, но документация затрудняет получение обзора. Поэтому я спрашиваю, знает ли кто-то другой лучший способ. Бонус, если он позволяет мне обновить матрицу Z, чтобы сделать анимацию.
Ответы
Ответ 1
Это выглядит хорошо, но неэффективно:
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()
Это был я, я бы повторно интерполировал (используя scipy.interpolate) данные в обычную сетку и использовал imshow(), установив экстенты для фиксации осей.
![fine contour]()
Изменить (за комментарий):
Анимация контурного сюжета может быть выполнена подобным образом, но, как я уже сказал, вышеизложенное является неэффективным, просто злоупотреблением функцией контурного графика. Самый эффективный способ сделать то, что вы хотите, - это использовать SciPy. У вас установлено это?
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()
Ответ 2
Если ваш meshgrid имеет равномерный интервал, вы можете продолжать использовать pcolor
, а просто сдвигать X и Y для центрирования данных по конкретным значениям, а не по углам.
Вы также можете использовать график рассеяния, чтобы явно разместить точки определенного размера в точках X и Y, а затем установить цвет в 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')
или
pcolor(X+0.5,Y+0.5,Z)
axis('equal')
или, как предложил Павел, используя одну из контурных функций
Ответ 3
В случае, если кто-то попадает в эту статью в поисках того, что я искал, я взял приведенный выше пример и изменил его, чтобы использовать imshow с входным стеком фреймов вместо того, чтобы генерировать и использовать контуры на лету. Начиная с 3D-массива изображений формы (nBins, nBins, nBins), называется 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)
Я также нашел гораздо более простой способ обойти весь этот процесс, хотя и менее надежный:
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
Обратите внимание, что обе эти функции работают только с ipython --pylab=tk
, a.k.a. backend = TkAgg
Спасибо за помощь во всем.
Ответ 4
Следующая функция создает поля с половиной размера на границе (как показано на прилагаемом рисунке).
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]()