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

How to plot spheres in 3d with plotly (or another library)?

我正在努力策划一些我认为应该非常简单的事情。我有一个 dataframe/table df,其中包含球体的坐标 x、y、z。此外,在一个单独的列中,它包含这些球体的半径。如何使用正确的半径绘制 space 中球体的 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 提供绝对大小图中的球体。我怎样才能让这个情节与 plotly 一起工作(或者最坏的情况与另一个图书馆一起工作)?谢谢!

当您使用标记时,通常以像素(面积或直径)为单位指定大小。文档状态 precisely that.

我从未使用过 plotly,但我很确定将使用 matplotlib 的脚本转换为使用 plotly 会很容易(请参阅 here。)

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 参数(并将 cstriderstride 参数检查为 plot_surface)。

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