10

I want to realize the function like surf(x,y,z,c) in matlab, here x,y and z are the coordinates, and c is a variable value, I can use c to define the color. I don't know how to realize it with matplotlib.

Dan
  • 45,079
  • 17
  • 88
  • 157
bowang
  • 121
  • 1
  • 1
  • 3
  • 1
    You could have a look at this tutorial http://matplotlib.org/mpl_toolkits/mplot3d/tutorial.html – marsei Mar 04 '14 at 15:14
  • 1
    I didn't find a function like surf(x,y,z,c) in the matplotlib tutorial – bowang Mar 04 '14 at 15:19
  • 1
    This really doesn't fully match the SO standards; include what you've tried and why it hasn't worked/etc. and then we can go from there in helping you. Even if you say I read the docs and just couldn't understand them you are making it better and not coming across as just asking everyone else to do your homework. – Nick Dickinson-Wilde Mar 04 '14 at 15:29
  • 1
    Here is the [specific function](http://matplotlib.org/mpl_toolkits/mplot3d/tutorial.html#mpl_toolkits.mplot3d.Axes3D.plot_surface) in the mplot3d tutorial. – wflynny Mar 04 '14 at 15:30

3 Answers3

6

I've done it using code something like this (see Edgelines vanish in mplot3d surf when facecolors are specified):

from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import matplotlib.pyplot as plt
import matplotlib
from pylab import *
import numpy as np

fig = plt.figure()
ax = fig.gca(projection='3d')


#Create X and Y data
x = np.arange(xmin, xmax, xstep)
y = np.arange(ymin, ymax, ystep)
X, Y = np.meshgrid(x, y)


surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, facecolors=C, antialiased=True)

#Show the plot
plt.show()
Community
  • 1
  • 1
Dan
  • 45,079
  • 17
  • 88
  • 157
4

You need to create a scalar map which will convert the values stored in your array 'C' into color values:

from matplotlib.colors import Normalize
from matplotlib import cm

import matplotlib.pyplot as plt

# assuming X, Y, Z, C are given in correct format
# Z and C have same dimensions

min = C.min()
max = C.max()

# choose any colormap e.g. cm.jet, cm.coolwarm, etc.
color_map = cm.RdYlGn # reverse the colormap: cm.RdYlGn_r
scalarMap = cm.ScalarMappable(norm=Normalize(vmin=min, vmax=max), cmap=color_map)

# outputs an array where each C value is replaced with a corresponding color value
C_colored = scalarMap.to_rgba(C)

surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, facecolors=C_colored, antialiased=True)
David
  • 51
  • 3
4

Here's a convenience function combining the other two answers (https://stackoverflow.com/a/22176126/171761 and https://stackoverflow.com/a/23799389/171761 ), which allows you to pass in a single argument (a raster Z, like imshow) and a colormap, and computes X, Y, and C (or which allows you to pass in Z, the colormap, and some of X, Y, and C):

def surf(Z, colormap, X=None, Y=None, C=None, shade=None):
    if X is None and Y is None:
        X, Y = meshgrid_of(Z)
    elif X is None:
        X, _ = meshgrid_of(Z)
    elif Y is None:
        _, Y = meshgrid_of(Z)

    if C is None:
        C = Z

    scalarMap = cm.ScalarMappable(norm=Normalize(vmin=C.min(), vmax=C.max()), cmap=colormap)

    # outputs an array where each C value is replaced with a corresponding color value
    C_colored = scalarMap.to_rgba(C)

    ax = gca(projection='3d')

    surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, facecolors=C_colored, shade=shade)

    return surf


def meshgrid_of(A):
    xx, yy = meshgrid(range(shape(A)[1]), range(shape(A)[0]))
    return xx, yy
Community
  • 1
  • 1
bshanks
  • 1,238
  • 2
  • 12
  • 24