13

I have a collection of Nx3 matrices in scipy/numpy and I'd like to make a 3 dimensional scatter of it, where the X and Y axes are determined by the values of first and second columns of the matrix, the height of each bar is the third column in the matrix, and the number of bars is determined by N.

Each matrix represents a different data group and I want each to be plotted with a different color, and then set a legend for the entire figure.

I have the following code:

fig = pylab.figure()
s = plt.subplot(1, 1, 1)
colors = ['k', "#B3C95A", 'b', '#63B8FF', 'g', "#FF3300",
          'r', 'k']
ax = Axes3D(fig)
plots = []
index = 0

for data, curr_color in zip(datasets, colors):
    p = ax.scatter(log2(data[:, 0]), log2(data[:, 1]),
                   log2(data[:, 2]), c=curr_color, label=my_labels[index])

    s.legend()
    index += 1

    plots.append(p)

    ax.set_zlim3d([-1, 9])
    ax.set_ylim3d([-1, 9])
    ax.set_xlim3d([-1, 9])

The issue is that ax.scatter plots things with a transparency and I'd like that remove. Also, I'd like to set the xticks and yticks and zticks -- how can I do that?

Finally, the legend call does not appear, even though I am calling label="" for each scatter call. How can I get the legend to appear?

thanks very much for your help.

3 Answers3

15

Try replacing 'ax.scatter' with ax.plot', possibly with the 'o' parameter to get similar circles. This fixes the transparency and the legend.

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

mpl.rcParams['legend.fontsize'] = 10

fig = plt.figure(1)
fig.clf()
ax = Axes3D(fig)
datasets = random((8,100,3))*512
my_labels = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']

colors = ['k', "#B3C95A", 'b', '#63B8FF', 'g', "#FF3300",
          'r', 'k']
index = 0
for data, curr_color in zip(datasets, colors):
    ax.plot(np.log2(data[:, 0]), np.log2(data[:, 1]), 
                   np.log2(data[:, 2]), 'o', c=curr_color, label=my_labels[index])
    index += 1

ax.set_zlim3d([-1, 9])
ax.set_ylim3d([-1, 9])
ax.set_xlim3d([-1, 9])

ax.set_xticks(range(0,11))
ax.set_yticks([1,2,8])
ax.set_zticks(np.arange(0,9,.5))

ax.legend(loc = 'upper left')
    
plt.draw()

plt.show()

I added a few lines and tweaks to get some sample data and get the rest of your demo working. I assume you'll be able to get it to work.

Setting the ticks requires the August 2010 update to mplot3d as described here. I got the latest mplot3d from Sourceforge. I'm not quite sure if Matplotlib 1.0.1 contains this latest update as I'm still running Python 2.6 with Matplotlib 1.0.0.

Edit

A quick and dirty dummy plot for the legends while keeping the 3d transparency effect you get from scatter:

index = 0
for data, curr_color in zip(datasets, colors):
    ax.scatter(np.log2(data[:, 0]), np.log2(data[:, 1]), 
                   np.log2(data[:, 2]), 'o', c=curr_color, label=my_labels[index])
    ax.plot([], [], 'o', c = curr_color, label=my_labels[index])                    
    index += 1
Community
  • 1
  • 1
Daan
  • 2,049
  • 14
  • 21
  • plot seems to preform a lot better than scatter here. you can also disable lines connecting your datapoints by explicitly passing ax.plot(...., ls='None') – mkocubinski Apr 05 '11 at 15:03
  • This is nearly perfect, thanks! One quick thing: the transparency i realize is required for the 3d effect. how can I do exactly what you did above but WITH the transparency that scatter3D gives? I.e. make it transparent with plot() –  Apr 06 '11 at 01:40
  • I don't think you can. The transparency you get with scatter is dependent on the orientation of the axis, so as you rotate the transparency changes. It seems you don't get this with plot as it is simply a 2d plot with a little tweak; scatter gives you an actual collection of 3d patches. If you need the transparency with the fancy 3d effect, then use scatter and get the legend through some dummy plots. Or, fix the scatter code so it works with legends ;-) – Daan Apr 06 '11 at 09:54
  • See the edit to my answer for a dummy plot together with scatter for the 3d transparency effect. – Daan Apr 06 '11 at 09:57
4

AFAIK, legends for 3d scatter artists are not directly supported. See here: http://matplotlib.sourceforge.net/users/legend_guide.html#plotting-guide-legend

However, you can use a hack/work-around with a 'proxy artist', using something like:

p = Rectangle((0, 0), 1, 1, fc="r")
axis.legend([p], ["Red Rectangle"])

So the proxy artist won't be added to the axis, but you can use it to create a legend.

mkocubinski
  • 455
  • 5
  • 17
0

Setting the kwarg depthshade=False fixed it for me:

ax.scatter(np.log2(data[:, 0]), np.log2(data[:, 1]), 
               np.log2(data[:, 2]), 'o', c=curr_color,  label=my_labels[index], depthshade=False)
mivkov
  • 471
  • 5
  • 19