matplotlib - How to replicate the following density plot in Python? - Stack Overflow

Given the following setup,N_r = 21; N_theta = 18; N_phi= 36;r_index = N_r-1;[phi,theta,r_sphere] = np

Given the following setup,

N_r = 21; N_theta = 18; N_phi= 36;
r_index = N_r-1;

[phi,theta,r_sphere] = np.meshgrid(np.linspace(0,2*np.pi,N_phi),np.linspace(0,np.pi,N_theta),np.linspace(a,b,N_r));

X = r_sphere[:,:,r_index] * np.sin(theta[:,:,r_index]) * np.cos(phi[:,:,r_index]);
Y = r_sphere[:,:,r_index] * np.sin(theta[:,:,r_index]) * np.sin(phi[:,:,r_index]);
Z = r_sphere[:,:,r_index] * np.cos(theta[:,:,r_index]);

rho = 1/r_sphere**2*np.sin(theta)*np.cos(theta)*np.sin(phi)

I have set up my 2D X, Y, and Z coordinates converted from spherical coordinates, and a density variable in spherical coordinates that I want to plot a spherical shell (at r_index) of. In Matlab, with the same variables and setup, I was able to use the surf() function

surf(X,Y,Z,rho(:,:,r_index),"EdgeAlpha",0.2); (plus a couple other things like axis labels and colorbar), I was able to create the following 3D (or I guess 4D?) plot at r=r_index:

Trying to use Matplotlib's plot_surface() either doesn't work, or I'm not quite getting my inputs correct:

fig1 = plt.figure(figsize=(16,9),dpi=80)
ax = fig1.add_subplot(projection = "3d")
surf = ax.plot_surface(X,Y,Z,rho[:,:,r_index])

Can I get this to work using plot_surface(), or is there another plotting function tailor made for what it is that I'm trying to do?

EDIT: scatter() appears to give me something close

fig1 = plt.figure(figsize=(16,9),dpi=80)
ax = fig1.add_subplot(projection = "3d")
surf = ax.scatter(X,Y,Z,c=rho[:,:,r_index],cmap = mpl.colormaps['bwr'])
plt.colorbar(surf,ax = ax,shrink = 0.5,aspect = 5)
plt.show()

It cleverly sets up the surface shape by taking in X, Y, and Z, and then I can set c to color each dot in accordance to the range of values passed in. If I could just do something similar to that for a function like plot_surface(). It can probably be done, I just don't know what the exact input arguments would be.

Given the following setup,

N_r = 21; N_theta = 18; N_phi= 36;
r_index = N_r-1;

[phi,theta,r_sphere] = np.meshgrid(np.linspace(0,2*np.pi,N_phi),np.linspace(0,np.pi,N_theta),np.linspace(a,b,N_r));

X = r_sphere[:,:,r_index] * np.sin(theta[:,:,r_index]) * np.cos(phi[:,:,r_index]);
Y = r_sphere[:,:,r_index] * np.sin(theta[:,:,r_index]) * np.sin(phi[:,:,r_index]);
Z = r_sphere[:,:,r_index] * np.cos(theta[:,:,r_index]);

rho = 1/r_sphere**2*np.sin(theta)*np.cos(theta)*np.sin(phi)

I have set up my 2D X, Y, and Z coordinates converted from spherical coordinates, and a density variable in spherical coordinates that I want to plot a spherical shell (at r_index) of. In Matlab, with the same variables and setup, I was able to use the surf() function

surf(X,Y,Z,rho(:,:,r_index),"EdgeAlpha",0.2); (plus a couple other things like axis labels and colorbar), I was able to create the following 3D (or I guess 4D?) plot at r=r_index:

Trying to use Matplotlib's plot_surface() either doesn't work, or I'm not quite getting my inputs correct:

fig1 = plt.figure(figsize=(16,9),dpi=80)
ax = fig1.add_subplot(projection = "3d")
surf = ax.plot_surface(X,Y,Z,rho[:,:,r_index])

Can I get this to work using plot_surface(), or is there another plotting function tailor made for what it is that I'm trying to do?

EDIT: scatter() appears to give me something close

fig1 = plt.figure(figsize=(16,9),dpi=80)
ax = fig1.add_subplot(projection = "3d")
surf = ax.scatter(X,Y,Z,c=rho[:,:,r_index],cmap = mpl.colormaps['bwr'])
plt.colorbar(surf,ax = ax,shrink = 0.5,aspect = 5)
plt.show()

It cleverly sets up the surface shape by taking in X, Y, and Z, and then I can set c to color each dot in accordance to the range of values passed in. If I could just do something similar to that for a function like plot_surface(). It can probably be done, I just don't know what the exact input arguments would be.

Share Improve this question edited Mar 22 at 8:35 Researcher R asked Mar 22 at 3:58 Researcher RResearcher R 1475 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 3

Try this:

a, b = 0, 100 # use desired values
rho[np.isnan(rho)] = 0 # impute NaN values
density = rho[...,r_index] # set appropriate density
# normalize to have values in [0,1]
density = (density - density.min()) / (density.max() - density.min()) 
m = plt.cm.ScalarMappable( \
        norm=mpl.colors.Normalize(density.min(), density.max()),  \
        cmap='jet')

fig1 = plt.figure(figsize=(16,9),dpi=80)
ax = fig1.add_subplot(projection = "3d")
surf = ax.plot_surface(X,Y,Z, facecolors=m.to_rgba(density))
fig1.colorbar(m, ax=ax) # colorbar
plt.show()

complete code:

import numpy as np

import matplotlib.pyplot as plt
import matplotlib as mpl

N_r = 21
N_theta = 18
N_phi= 36
r_index = N_r-1
a, b = 0, 100 # use desired values

[phi,theta,r_sphere] = np.meshgrid(np.linspace(0,2*np.pi,N_phi),np.linspace(0,np.pi,N_theta),np.linspace(a,b,N_r))

X = r_sphere[:,:,r_index] * np.sin(theta[:,:,r_index]) * np.cos(phi[:,:,r_index])
Y = r_sphere[:,:,r_index] * np.sin(theta[:,:,r_index]) * np.sin(phi[:,:,r_index])
Z = r_sphere[:,:,r_index] * np.cos(theta[:,:,r_index])

rho = 1/r_sphere**2*np.sin(theta)*np.cos(theta)*np.sin(phi)

#a, b = 0, 100 # use desired values
rho[np.isnan(rho)] = 0 # impute NaN values
density = rho[...,r_index] # set appropriate density
# normalize to have values in [0,1]
density = (density - density.min()) / (density.max() - density.min()) 
m = plt.cm.ScalarMappable( \
        norm=mpl.colors.Normalize(density.min(), density.max()),  \
        cmap='jet')

fig1 = plt.figure(figsize=(16,9),dpi=80)
ax = fig1.add_subplot(projection = "3d")
surf = ax.plot_surface(X,Y,Z, facecolors=m.to_rgba(density))
fig1.colorbar(m, ax=ax) # colorbar
plt.show()

Ah, so it's the same as with using scatter where we create a colormap out of the data and applying it. The only issue now is that the colorbar's min and max values aren't reflective of the of the data, as it's locked to 0 to 1. I'm guessing that's what the Normalize function does. Tried fiddling around with the inputs adding vmin and vmax and applying clim, but it looks like it's stuck. Is there a way around this?

Not sure I am getting the comment to the accepted answer right , but copying from:

color coding using scalar mappable in matplotlib

I tried:

import numpy as np

import matplotlib.pyplot as plt
import matplotlib as mpl

N_r = 21
N_theta = 18
N_phi= 36
r_index = N_r-1
a, b = 0, 100 # use desired values

[phi,theta,r_sphere] = np.meshgrid(np.linspace(0,2*np.pi,N_phi),np.linspace(0,np.pi,N_theta),np.linspace(a,b,N_r))

X = r_sphere[:,:,r_index] * np.sin(theta[:,:,r_index]) * np.cos(phi[:,:,r_index])
Y = r_sphere[:,:,r_index] * np.sin(theta[:,:,r_index]) * np.sin(phi[:,:,r_index])
Z = r_sphere[:,:,r_index] * np.cos(theta[:,:,r_index])

rho = 1/r_sphere**2*np.sin(theta)*np.cos(theta)*np.sin(phi)

#print('\nrho :\n', rho)

#a, b = 0, 100 # use desired values
rho[np.isnan(rho)] = 0 # impute NaN values
density = rho[...,r_index] # set appropriate density
# normalize to have values in [0,1]
#density = (density - density.min()) / (density.max() - density.min()) 
#m = plt.cm.ScalarMappable( \
      # norm=mpl.colors.Normalize(density.min(), density.max()),  \
      # cmap='jet')
  
cmap= plt.cm.jet
# create normalization instance
norm = mpl.colors.Normalize(vmin=density.min(), vmax=density.max()) 
# create a scalarmappable from the colormap
m = mpl.cm.ScalarMappable(cmap=cmap, norm=norm)    

fig1 = plt.figure(figsize=(16,9),dpi=80)
ax = fig1.add_subplot(projection = "3d")
surf = ax.plot_surface(X,Y,Z, facecolors=m.to_rgba(density))
fig1.colorbar(m, ax=ax) # colorbar
plt.show()

output:

given that:

print('\ndensity.max() : ', density.max())

print('\ndensity.min() : ', density.min())

results in:

density.max() :  4.973657691184833e-05

density.min() :  -4.973657691184834e-05

I am using Online Matplotlib Compiler that is Matplotlib Version : 3.8.4

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744325408a4568626.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信