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

8
  • 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(). Commented Jun 4, 2020 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) Commented Jun 4, 2020 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. Commented Jun 4, 2020 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. Commented Jun 4, 2020 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? Commented Jun 4, 2020 at 13:28

2 Answers 2

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

Sign up to request clarification or add additional context in comments.

Comments

-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

1 Comment

omg, thank you so much for the detailed answer! It worked out.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.