我正在努力绘制一些我认为应该非常简单的东西。我有一个数据框/表
df
,其中包含球体的坐标 x、y、z。此外,在单独的列中,它包含这些球体的半径。如何使用正确的半径绘制空间中球体的 3D 图?
我最接近使这个情节成为现实的是这段代码:
import plotly.express as px
import plotly.graph_objects as go
x =y=z = np.arange(1,4)
fig = go.Figure()
fig.add_trace(go.Scatter3d(
mode='markers',
x=x,
y=y,
z=z,
marker=dict(color=px.colors.qualitative.D3,size=[50, 5, 25],sizemode='diameter'
)
)
)
这几乎产生了我想要的(见下文),但请注意球体的大小不正确 - 球体大小之间的比率是正确的,但我希望
size
提供图中球体的绝对大小。我怎样才能让这个情节与情节一起工作(或者最坏的情况与另一个库一起工作)? Tnx!
根据azelcer的回答,我设法生成了以下代码,用
plotly
绘制球体:
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
def ms(x, y, z, radius, resolution=20):
"""Return the coordinates for plotting a sphere centered at (x,y,z)"""
u, v = np.mgrid[0:2*np.pi:resolution*2j, 0:np.pi:resolution*1j]
X = radius * np.cos(u)*np.sin(v) + x
Y = radius * np.sin(u)*np.sin(v) + y
Z = radius * np.cos(v) + z
return (X, Y, Z)
df = pd.read_csv('xyzr_sphere_coordinates.txt')
data = []
for index, row in df.iterrows():
(x_pns_surface, y_pns_surface, z_pns_suraface) = ms(row.x, row.y, row.z, row.r)
data.append(go.Surface(x=x_pns_surface, y=y_pns_surface, z=z_pns_suraface, opacity=0.5))
fig = go.Figure(data=data)
fig.show()
它引出了这个 3D 互动人物:
使用标记时,尺寸通常以像素为单位(面积或直径)指定。文档指出正是如此。
我从未使用过
plotly
,但我很确定使用 matplotlib
将此脚本转换为使用 plotly
(请参阅此处。)
import numpy as np
import matplotlib.pyplot as plt
from itertools import repeat # just for the example
def makesphere(x, y, z, radius, resolution=10):
"""Return the coordinates for plotting a sphere centered at (x,y,z)"""
u, v = np.mgrid[0:2*np.pi:resolution*2j, 0:np.pi:resolution*1j]
X = radius * np.cos(u)*np.sin(v) + x
Y = radius * np.sin(u)*np.sin(v) + y
Z = radius * np.cos(v) + z
return (X, Y, Z)
fig = plt.figure("Spheres")
ax = fig.add_subplot(projection='3d')
for x, y, z, radius, in zip(*repeat(np.arange(1,4),3), [.1, .5, .75]):
X, Y, Z = makesphere(x, y, z, radius)
ax.plot_surface(X, Y, Z, color="r")
结果:
如果您想要更平滑的球体,请增加
resolution
参数(并将 cstride
和 rstride
参数检查为 plot_surface
)。
我个人使用 PyVista 将球体的网格作为等值面,并使用
go.Mesh3d
用 plotly 来绘制它。
import numpy as np
import pyvista as pv
import plotly.graph_objects as go
import plotly.io as pio # to save the graphics as html
# center
x0 = 0
y0 = 0
z0 = 0
# radius
r = 2
# radius + 2% to be sure of the bounds
R = r * 1.02
def f(x, y, z):
return (
(x-x0)**2 + (y-y0)**2 + (z-z0)**2
)
# generate data grid for computing the values
X, Y, Z = np.mgrid[(-R+x0):(R+x0):250j, (-R+y0):(R+y0):250j, (-R+z0):(R+z0):250j]
# create a structured grid
grid = pv.StructuredGrid(X, Y, Z)
# compute and assign the values
values = f(X, Y, Z)
grid.point_data["values"] = values.ravel(order = "F")
# compute the isosurface f(x, y, z) = r²
isosurf = grid.contour(isosurfaces = [r**2])
mesh = isosurf.extract_geometry()
# extract vertices and triangles
vertices = mesh.points
triangles = mesh.faces.reshape(-1, 4)
# plot
fig = go.Figure(data=[
go.Mesh3d(
x=vertices[:, 0],
y=vertices[:, 1],
z=vertices[:, 2],
colorscale = [[0, 'gold'],
[0.5, 'mediumturquoise'],
[1, 'magenta']],
# Intensity of each vertex, which will be interpolated and color-coded
intensity = np.linspace(0, 1, len(vertices)),
# i, j and k give the vertices of the triangles
i = triangles[:, 1],
j = triangles[:, 2],
k = triangles[:, 3],
showscale = False
)
])
fig.show()
# save
pio.write_html(fig, "plotlySphere.html")
球体图可以使用 S3Dlib 中的 SphericalSurface 类直接构造。例如:
从脚本生成:
import csv
import numpy as np
import matplotlib.pyplot as plt
import s3dlib.surface as s3d
csv_data = []
with open('testdata.csv') as csv_file:
csv_reader = csv.reader(csv_file, delimiter=',')
for row in csv_reader: csv_data.append(row)
# note: first row contains the column labels
geom = np.array([ c[0:4] for c in csv_data ][1:]).astype(float) # xyz & radii
colors = [ c[4] for c in csv_data ][1:]
rez=3
for i,sph in enumerate(geom) :
s = s3d.SphericalSurface(rez,color=colors[i]).domain(sph[3])
s.transform(translate=sph[0:3])
spheres = s if i==0 else spheres+s
fig = plt.figure(figsize=plt.figaspect(1))
ax = plt.axes(projection='3d')
s3d.auto_scale(ax,spheres, rscale=True )
ax.add_collection3d(spheres.shade())
fig.tight_layout()
plt.show()
csv 数据文件是使用 Excel 生成的,随机 xyz 坐标为 [-25,25]。半径采用正态分布,平均值为 10,标准差为 5。随机颜色取自 Matplotlib,名为 CSS 颜色。
使用球面对象创建图形的另一个示例如下所示:
对于这种情况,球体的位置、大小和颜色是明确定义的。 S3Dlib 文档中提供了代码。