Reputation: 269
How to plot density map on the surface of a sphere if I have array of values corresponding to given (theta,phi) points in spherical coordinates? I have found how to construct a sphere e.g. Bloch sphere or plotting on a sphere. The first example is really nice looking - axes are needed and heatmap.
Upvotes: 3
Views: 3839
Reputation: 10650
If you subclass the Bloch
class of QuTip
, and alter the way it draws the sphere, you can draw density plots and keep all the other framework it creates.
Taking the matplotlib surface_plot
examples, and altering the Bloch
class' plotting functions works. Putting it in your own subclass prevents you from hacking away at the libraries.
from qutip import Bloch
from math import sqrt, sin, cos, pi
from colorsys import hsv_to_rgb
from numpy import linspace, outer, ones, sin, cos, arccos, arctan2, size, empty
class BlochDensity(Bloch):
def plot_back(self):
# back half of sphere
u = linspace(0, pi, 25)
v = linspace(0, pi, 25)
x = outer(cos(u), sin(v))
y = outer(sin(u), sin(v))
z = outer(ones(size(u)), cos(v))
colours = empty(x.shape, dtype=object)
for i in range(len(x)):
for j in range(len(y)):
theta = arctan2(y[i,j], x[i,j])
phi = arccos(z[i,j])
colours[i,j] = self.density(theta, phi)
self.axes.plot_surface(x, y, z, rstride=1, cstride=1,
facecolors=colours,
alpha=self.sphere_alpha,
linewidth=0, antialiased=True)
# wireframe
self.axes.plot_wireframe(x, y, z, rstride=5, cstride=5,
color=self.frame_color,
alpha=self.frame_alpha)
# equator
self.axes.plot(1.0 * cos(u), 1.0 * sin(u), zs=0, zdir='z',
lw=self.frame_width, color=self.frame_color)
self.axes.plot(1.0 * cos(u), 1.0 * sin(u), zs=0, zdir='x',
lw=self.frame_width, color=self.frame_color)
def plot_front(self):
# front half of sphere
u = linspace(-pi, 0, 25)
v = linspace(0, pi, 25)
x = outer(cos(u), sin(v))
y = outer(sin(u), sin(v))
z = outer(ones(size(u)), cos(v))
colours = empty(x.shape, dtype=object)
for i in range(len(x)):
for j in range(len(y)):
theta = arctan2(y[i,j], x[i,j])
phi = arccos(z[i,j])
colours[i,j] = self.density(theta, phi)
self.axes.plot_surface(x, y, z, rstride=1, cstride=1,
facecolors=colours,
alpha=self.sphere_alpha,
linewidth=0, antialiased=True)
# wireframe
self.axes.plot_wireframe(x, y, z, rstride=5, cstride=5,
color=self.frame_color,
alpha=self.frame_alpha)
# equator
self.axes.plot(1.0 * cos(u), 1.0 * sin(u),
zs=0, zdir='z', lw=self.frame_width,
color=self.frame_color)
self.axes.plot(1.0 * cos(u), 1.0 * sin(u),
zs=0, zdir='x', lw=self.frame_width,
color=self.frame_color)
What i've done here is make the plotting part call the function of BlochDensity
: self.density(theta, phi)
- which i haven't defined.
After you create the BlochDensity
object, you need to create that function, which is the mapping of theta, phi
onto your density. I would advise using SciPy's 2D interpolation to create the function, something like this:
from scipy.interpolate import interp2d
from numpy.random import rand
b = BlochDensity()
b.sphere_alpha=0.5
thetas, phis = linspace(-pi,pi,10), linspace(0,pi,10)
density = rand(len(thetas), len(phis))
#scale density to a maximum of 1
density /= density.max()
interpolated_density = interp2d(thetas, phis, density)
def f(theta, phi):
return hsv_to_rgb(interpolated_density(theta,phi), 1, 1)
b.density = f
b.show()
b.density = f
b.show()
If you want to increase the resolution, then just change the numbers in the linspace inside the plot_*
functions of BlochDensity
.
Upvotes: 9