26

Currently I'm using matplotlib to plot a 3d scatter and while it gets the job done, I can't seem to find a way to rotate it to see my data better.

Here's an example:

import pylab as p
import mpl_toolkits.mplot3d.axes3d as p3

#data is an ndarray with the necessary data and colors is an ndarray with
#'b', 'g' and 'r' to paint each point according to its class

...

fig=p.figure()
ax = p3.Axes3D(fig)
ax.scatter(data[:,0], data[:,2], data[:,3], c=colors)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
fig.add_axes(ax)
p.show()

I'd like a solution that lets me do it during execution time but as long as I can rotate it and it's short/quick I'm fine with it.

Here's a comparison of the plots produced after applying a PCA to the iris dataset:
1. mayavi
alt text
2. matplotlib
alt text

Mayavi makes it easier to visualize the data, but MatPlotLib looks more professional. Matplotlib is also lighter.

pnodbnda
  • 649
  • 2
  • 8
  • 12

2 Answers2

30

Well, first you need to define what you mean by "see my data better"...

You can rotate and zoom in on the plot using the mouse, if you're wanting to work interactively.

If you're just wanting to rotate the axes programatically, then use ax.view_init(elev, azim) where elev and azim are the elevation and azimuth angles (in degrees) that you want to view your plot from.

Alternatively, you can use the ax.elev, ax.azim, and ax.dist properties to get/set the elevation, azimuth, and distance of the current view point.

Borrowing the source from this example:

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

def randrange(n, vmin, vmax):
    return (vmax-vmin)*np.random.rand(n) + vmin

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
n = 100
for c, m, zl, zh in [('r', 'o', -50, -25), ('b', '^', -30, -5)]:
    xs = randrange(n, 23, 32)
    ys = randrange(n, 0, 100)
    zs = randrange(n, zl, zh)
    ax.scatter(xs, ys, zs, c=c, marker=m)

ax.set_xlabel('X Label')
ax.set_ylabel('Y Label')
ax.set_zlabel('Z Label')

plt.show()

We get a nice scatterplot: alt text

You can rotate the axes programatically as shown:

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

def randrange(n, vmin, vmax):
    return (vmax-vmin)*np.random.rand(n) + vmin

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
n = 100
for c, m, zl, zh in [('r', 'o', -50, -25), ('b', '^', -30, -5)]:
    xs = randrange(n, 23, 32)
    ys = randrange(n, 0, 100)
    zs = randrange(n, zl, zh)
    ax.scatter(xs, ys, zs, c=c, marker=m)

ax.set_xlabel('X Label')
ax.set_ylabel('Y Label')
ax.set_zlabel('Z Label')

ax.azim = 200
ax.elev = -45

plt.show()

alt text

Hope that helps a bit!

Joe Kington
  • 275,208
  • 71
  • 604
  • 463
  • funny, i couldn't get it to rotate before but now it works. go figure. i'm using ubuntu 10.10 with python 2.6 if it makes any difference. – pnodbnda Jan 19 '11 at 20:04
  • mplot3d is very convenient and lighter-weight than mayava. But note that if you need complex 3D scenes, mplot3d recommends using MayaVi. E.g. see the answer above by unutbu. – nealmcb Nov 24 '14 at 18:46
  • mplot3d is just HORRIBLE ! it doesn't even have a function to move the center of rotation of the plot which is a critical thing in 3d plots. – Mehdi Nov 11 '15 at 15:17
  • @Mehdi - Yes, mplot3d is deliberately very minimal. It's not intended to be a "full" 3d plotting package. It's intended for quick-and-dirty pseudo-3d plots. If you need true 3D plotting, use Mayavi or something similar. – Joe Kington Nov 11 '15 at 15:23
  • 1
    how to rotate by a mouse? – Michelle Owen Jul 26 '18 at 13:57
14

Using mayavi, you can create such a plot with

import enthought.mayavi.mlab as mylab
import numpy as np
x, y, z, value = np.random.random((4, 40))
mylab.points3d(x, y, z, value)
mylab.show()

The GUI allows rotation via clicking-and-dragging, and zooming in/out via right-clicking-and-dragging.

alt text

unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
  • zoom in this one is better because the points increase in size as you zoom (matplotlib increases just the distance which makes the zoom not as helpful) and also matplotlib's draws the axis box which doesn't keep up with the zooming. though this one is a lot heavier/slower so it's probably better to use it only when you have to zoom in. – pnodbnda Jan 19 '11 at 20:15
  • 2
    This line (`import enthought.mayavi.mlab as mylab`) didn't work for me. `enthought` was apparently not a module. – Richard Nov 19 '12 at 11:04
  • @Richard: Do you have `mayavi` installed? The installation should come with instructions on how to import the mayavi module. – unutbu Nov 19 '12 at 11:10
  • Note that the [mplot3d FAQ](http://matplotlib.org/mpl_toolkits/mplot3d/faq.html) explains that mplot3d is really 2D+z, not fully 3D. E.g. "the intersection of two 3D objects (such as polygons or patches) can not be rendered properly". Thus "Until [matplotlib supports 3D at it core (OpenGL)], if you need complex 3D scenes, we recommend using MayaVi" – nealmcb Nov 24 '14 at 18:44