Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Normalizing Colormap Used by Facecolors in Matplotlib

First off, I'm trying to plot spherical harmonics in matplotlib as they are seen here in mayavi: http://docs.enthought.com/mayavi/mayavi/auto/example_spherical_harmonics.html

Here is where I'm at:

import matplotlib.pyplot as plt
from matplotlib import cm, colors
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
from scipy import special

# Create a sphere
r = 3
pi = np.pi
cos = np.cos
sin = np.sin
phi, theta = np.mgrid[0:pi:50j, 0:2*pi:50j]


x = r * sin(phi) * cos(theta)
y = r * sin(phi) * sin(theta)
z = r * cos(phi)

colorfunction=special.sph_harm(3,4,theta,phi).real

norm=colors.Normalize(vmin = np.min(colorfunction), vmax = np.max(colorfunction), clip = False)
print colorfunction



fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.scatter(x, y, z)
ax.plot_surface(
    x, y, z,  rstride=1, cstride=1, norm=norm, cmap=cm.jet, facecolors=cm.jet(colorfunction))
plt.show()

The idea is to use colorfunction to colour the surface of the sphere according to the spherical harmonic. However, the output of this function is an array with negative numbers. What I need to do is 'normalize' this array so it behaves nicely with matplotlib's colormap. However, unlike the answer here, Color matplotlib plot_surface command with surface gradient , where the answer simply preforms a sloppy normalize by dividing by the largest element, I have negative elements so that just won't work. I'd ideally like to use matplotlib.colors.Normalize but it just isn't working on facecolors.

I know that the norm is applying to the cmap=cm.jet, because if I remove facecolors argument entirely I get a new colormap that behaves according to my norm function.

This is the crux of my issue, I cannot get my normalized colormap to apply to my facecolors. Any ideas?

This is the figure the above code currently generates. As you can see the negative values are cut-off entirely and the information is lost because the colormaps range is much larger than the actual values (so everything just looks blue).

like image 583
Jesse Avatar asked Jul 29 '14 19:07

Jesse


1 Answers

Maybe this is too trivial, but:

ax.plot_surface(x, y, z,  rstride=1, cstride=1, facecolors=cm.jet(norm(colorfunction)))

This normalizes colorfunction. Also, it is sufficient to define the normalization function by:

norm = colors.Normalize()

This will automatically scale the input between 0..1.

The result:

enter image description here

It seems that cmap and norm keywords apply to the case where one uses Z data to color the surface, so they are not useful here.

like image 194
DrV Avatar answered Nov 14 '22 23:11

DrV