如何使用plotly(或其他库)在3d中绘制球体?

问题描述 投票:0回答:4

我正在努力绘制一些我认为应该非常简单的东西。我有一个数据框/表

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!

python matplotlib plot 3d plotly
4个回答
3
投票

根据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 互动人物:


1
投票

使用标记时,尺寸通常以像素为单位(面积或直径)指定。文档指出正是如此

我从未使用过

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
)。


1
投票

我个人使用 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")


0
投票

球体图可以使用 S3Dlib 中的 SphericalSurface 类直接构造。例如:

spheres

从脚本生成:

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 颜色

使用球面对象创建图形的另一个示例如下所示:

NaCl

对于这种情况,球体的位置、大小和颜色是明确定义的。 S3Dlib 文档中提供了代码

© www.soinside.com 2019 - 2024. All rights reserved.