0

I would like to create 3d scatter plot with colormap range from min(u), u =64 to max(u), u=100. u is a 1d array

The code works as expected, u is increasing from the center (x,y,z)=(0,0,0) but the colors is incorrect, the color gradient should range according to u, from min(u) to max(u) instead of depending on x,y,z coordinate. Also colorbar is not correct (should be from 0 to 100)

fig = plt.figure(figsize = (8,6))
ax = fig.add_subplot(111, projection='3d')
ax.set_title('normal distribution')

#add the line/data in our plot
x = 18 * np.random.normal(size =500)
y = 18 * np.random.normal(size =500)
z = 18 * np.random.normal(size =500)

u = np.linspace(64, 100, 500)

norma = mpl.colors.Normalize(min(u), max(u))
color = np.linalg.norm([x,y,z], axis=0)
track = ax.scatter(x,y,z, s=35, c = color, alpha = 1, cmap='inferno', norm = norma)

plt.colorbar(track, label='color map', shrink=0.6)
fig = plt.figure(figsize = (8,6))
ax = fig.add_subplot(111, projection='3d')
ax.set_title('normal distribution')

the above code figure

When the color map Normalise to vmin=min(u) and vmax=max(u), the color gradient is lost and colormap gradient values are spread randomly along the x,y,z axis instead of being in ordered array. Does someone know how to fix the color gradient along the axis, while the center of u is at (0,0,0) with the correct color bar (0-100) please?

fig = plt.figure(figsize = (8,6))
ax = fig.add_subplot(111, projection='3d')
ax.set_title('normal distribution')

#add the line/data in our plot
x = 18 * np.random.normal(size =500)
y = 18 * np.random.normal(size =500)
z = 18 * np.random.normal(size =500)

u = np.linspace(100, 64, 500)

norma = mpl.colors.Normalize(vmin=0, vmax = 100)
color = np.linalg.norm([u], axis=0)
track = ax.scatter(x,y,z, s=35, c = color, alpha = 1, cmap='inferno', norm = norma)

plt.colorbar(track, label='color map', shrink=0.6)

The result of the second example

heather_by
  • 13
  • 4
  • Do I understand correctly that you want to use `x`, `y`, and `z` as coordinates and `u` as the color? Then your first example is correct. If you want to normalize the color, just use `min(u)` and `max(u)` as the arguments for `Normalize()`. – Not_a_programmer Jun 04 '20 at 10:37
  • Thank you for your answer, I have tried what you suggesting but still get colors in random location instead of as a gradient from min(u) to max(u) `norma = mpl.colors.Normalize(vmin=min(u), vmax = max(u)` – heather_by Jun 04 '20 at 10:46
  • Ah, I think I understand your question now. You expect `u` to increase from the center. In this case, warped's answer should work just fine. You just assigned your linearly increasing `u` to your random coordinates. That's why you had randomly distributed color. – Not_a_programmer Jun 04 '20 at 11:01
  • ok, I was explaining the problem better after edited the question. Indeed I expect u to increase from the (0,0,0) coordinates, but I value u= 64 in the center instead of 0. am I explaning myself better? The main thing I can not manage is to make the scatter of normal distribution plotted from on (x,y,z) = (0,0,0) together with color map that the center is min(u) (u=64), and the max(u) , u=100. – heather_by Jun 04 '20 at 12:05
  • @heather-by So you want to create a sphere with radius 18 centered at 0. The sphere is made out of 500 points. The points are normally distributed with the highest density at the center. Correct? Now the color of the points should be dependent on the distance from the center. At the center the value is 64 (black). On the surface of the sphere the value is 100 (yellow). Is this correct? – Not_a_programmer Jun 04 '20 at 13:28
  • I think it would help if you added a 2d sketch with some program like paint. I have a hard time understanding what you want. – warped Jun 04 '20 at 13:48
  • @Not_a_programmer Yes for all the parameters except the color at the min value (64) , preferably would be orange and define a color bar range from 0 to 100 as I did at the first code, if that is possible with keeping the color gradient along the axis. I need it for a graphcal demonstration of light extinction. Thanks for your help. – heather_by Jun 04 '20 at 13:53
  • I did, you can open the link and take a look of the plots I made. because Im new here I can not add them as pictures, first example plot: https://i.stack.imgur.com/e0ZUa.png , second example plot: https://i.stack.imgur.com/tGYfh.png – heather_by Jun 04 '20 at 14:10

2 Answers2

0
x = 18 * np.random.normal(size =500)
y = 18 * np.random.normal(size =500)
z = 18 * np.random.normal(size =500)

# collect all data in array
data = np.array([x,y,z])

# center in a given dimension is the mean of all datapoints:
# reshape to allow easy subtraction
center = np.mean(data, axis=1).reshape(3,-1)
# for each datapoint, calculate distance to center and use as color value
color = np.linalg.norm(data - center, axis=0)

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

track = ax.scatter(x,y,z, s=35, c = color, alpha = 1, cmap='inferno')
plt.colorbar(track, label='color map', shrink=0.6)

enter image description here

warped
  • 8,947
  • 3
  • 22
  • 49
-1

I found this question which seems to answer your question about the coordinates. The answers also show how to evenly distribute coordinates if you prefer to do that.

After getting the coordinates, you can then get the distance from the center as the color value (like warped did in his answer). I adjusted the distance to reflect your specifications. This is the resulting code:

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

number_of_particles = 500
sphere_radius = 18

# create the particles
radius = sphere_radius * np.random.uniform(0.0, 1.0, number_of_particles)
theta = np.random.uniform(0., 1., number_of_particles) * 2 * np.pi
phi = np.random.uniform(0., 1., number_of_particles) * 2 * np.pi
x = radius * np.sin(theta) * np.cos(phi)
y = radius * np.sin(theta) * np.sin(phi)
z = radius * np.cos(theta)

# collect all data in array
data = np.array([x, y, z])

# for each datapoint, calculate distance to center and use as color value
color = radius
color /= sphere_radius
color = color * 36 + 64

# initialize a figure with a plot
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

# add the points and the colorbar
track = ax.scatter(x, y, z, s=35, c=color, alpha=1, cmap='inferno',
                   norm=Normalize(0, 100))
plt.colorbar(track, label='color map', shrink=0.6)

plt.show()

My result looks like this:

Output image