Matplotlib позволяет передавать листы в качестве аргумента, например. ax.plot_surface
.
Это будет означать то, что вы должны выполнить 2D интерполяции на ваш текущего массива цветов, потому что вы в настоящее время только цвета в углах прямоугольных граней (вы сделали упоминание, что у вас есть прямолинейный сетка).
Вы можете использовать scipy.interpolate.interp2d
для этого, но, как видно из документации, предлагается использовать scipy.interpolate.RectBivariateSpline
.
Чтобы дать вам простой пример:
import numpy as np
y,x = np.mgrid[1:10:10j, 1:10:10j] # returns 2D arrays
# You have 1D arrays that would make a rectangular grid if properly reshaped.
y,x = y.ravel(), x.ravel() # so let's convert to 1D arrays
z = x*(x-y)
colors = np.cos(x**2) - np.sin(y)**2
Теперь у меня есть подобный набор данных, как вы (одномерные массивы для x, y, z
и colors
). Обратите внимание, что цвета определены для каждой точки (x, y). Но когда вы хотите построить с plot_surface
, вы будете генерировать прямоугольные заплаты, из которых углы даются этими точками.
Таким образом, на интерполяции, то:
from scipy.interpolate import RectBivariateSpline
# from scipy.interpolate import interp2d # could 've used this too, but docs suggest the faster RectBivariateSpline
# Define the points at the centers of the faces:
y_coords, x_coords = np.unique(y), np.unique(x)
y_centers, x_centers = [ arr[:-1] + np.diff(arr)/2 for arr in (y_coords, x_coords)]
# Convert back to a 2D grid, required for plot_surface:
Y = y.reshape(y_coords.size, -1)
X = x.reshape(-1, x_coords.size)
Z = z.reshape(X.shape)
C = colors.reshape(X.shape)
#Normalize the colors to fit in the range 0-1, ready for using in the colormap:
C -= C.min()
C /= C.max()
interp_func = RectBivariateSpline(x_coords, y_coords, C.T, kx=1, ky=1) # the kx, ky define the order of interpolation. Keep it simple, use linear interpolation.
В этом последнем шаге вы можете также использовали interp2d
(с kind='linear'
заменой kx=1, ky=1
). Но поскольку документы предлагают использовать более быстрый RectBivariateSpline
...
Теперь вы готовы построить его:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.cm as cm
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
r = ax.plot_surface(X,Y,Z,
facecolors=cm.hot(interp_func(x_centers, y_centers).T),
rstride=1, cstride=1) # only added because of this very limited dataset
![output](https://i.stack.imgur.com/BFHOM.png)
Как вы можете видеть, цвет на лицах не имеет ничего общего больше с высотой набора данных.
Обратите внимание, что вы могли подумать, что просто пройти 2D-массив C до facecolors
будет работать, и matplotlib не пожаловался бы. Однако результат не является точным, потому что matplotlib будет использовать только подмножество C для facecolors (он, кажется, игнорирует последний столбец и последнюю строку C). Это эквивалентно использованию только цвета, определенного одной координатой (например, верхним левым) по всему патчу.
Простейшее метод был бы позволить Matplotlib сделать интерполяцию и получить facecolors, а затем передавать их на реальный сюжет:
r = ax.plot_surface(X,Y,C, cmap='hot') # first plot the 2nd dataset, i.e. the colors
fc = r.get_facecolors()
ax.clear()
ax.plot_surface(X, Y, Z, facecolors=fc)
Однако, это не будет работать в версиях < = 1,4. 1 из-за this recently submitted bug.
3D-график рассеяния кажется appriopriate, например. http://matplotlib.org/examples/mplot3d/scatter3d_demo.html. – Evert
Создает ли ваши xy-данные прямолинейную сетку или координаты x и y в значительной степени распределены случайным образом? –
Да, X, Y и Z регулярно распределяются. – muffinman