3D Scatter Plot with Colorbar
Asked Answered
V

2

41

Borrowing from the example on the Matplotlib documentation page and slightly modifying the code,

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)
    cs = randrange(n, 0, 100)
    ax.scatter(xs, ys, zs, c=cs, marker=m)
ax.set_xlabel('X Label')
ax.set_ylabel('Y Label')
ax.set_zlabel('Z Label')

plt.show()

Will give a 3D scatter plot with different colors for each point (random colors in this example). What's the correct way to add a colorbar to the figure, since adding in plt.colorbar() or ax.colorbar() doesn't seem to work.

Vola answered 31/3, 2011 at 4:50 Comment(1)
what is cs in your example?Phyllida
R
51

This produces a colorbar (though possibly not the one you need):

Replace this line:

ax.scatter(xs, ys, zs, c=cs, marker=m)

with

p = ax.scatter(xs, ys, zs, c=cs, marker=m)

then use

fig.colorbar(p)

near the end

Root answered 31/3, 2011 at 6:9 Comment(0)
U
11

Using the above answer did not solve my problem. The colorbar colormap was not linked to the axes (note also the incorrect colorbar limits):

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

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

data = np.random.rand(3, 100)
x, y, z = data  # for show
c = np.arange(len(x)) / len(x)  # create some colours

p = ax.scatter(x, y, z, c=plt.cm.magma(0.5*c))
ax.set_xlabel('$\psi_1$')
ax.set_ylabel('$\Phi$')
ax.set_zlabel('$\psi_2$')

ax.set_box_aspect([np.ptp(i) for i in data])  # equal aspect ratio

fig.colorbar(p, ax=ax)

bad example

The solution (see here also) is to use cmap in ax.scatter:

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

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

data = np.random.rand(3, 100)
x, y, z = data  # for show
c = np.arange(len(x)) / len(x)  # create some colours

p = ax.scatter(x, y, z, c=0.5*c, cmap=plt.cm.magma)
ax.set_xlabel('$\psi_1$')
ax.set_ylabel('$\Phi$')
ax.set_zlabel('$\psi_2$')

ax.set_box_aspect([np.ptp(i) for i in data])  # equal aspect ratio

fig.colorbar(p, ax=ax)

enter image description here

Ur answered 3/2, 2021 at 11:44 Comment(3)
You passed the values c (which ranges from 0. to 1.) through the cm.magma function, which altered all the values, and gave the impression of an incorrect range. I would not say that my answer was incorrect, but that your first attempt to change the colormap was incorrect. Your second answer correctly sets the colormap with the cmap argument.Root
why is 0.5*c needed?Pfeifer
It is not needed, but c is bounded [0..1] and 0.5 was added as a scaling factor to show that the scale bar displays appropriate units in the second plot, which is not the case in the first plot.Ur

© 2022 - 2024 — McMap. All rights reserved.