如何使用 matplotlib 在两个环之间填充

Dan*_*Dan 2 python plot numpy matplotlib

我沿着从任意 3D 方向旋转的两个同心圆有 x 和 y 值的 numpy 数组,并投影到绘图的 xy 平面中xs1, ys1, xs2, ys2

我想用 matplotlib 绘制它们,填充它们之间的空间。我在 fill_between 时遇到了麻烦,因为我要填充的曲线是多值的。我在想一种蛮力方法是拆分成单值段,沿着相同的一组 x 值插入曲线并使用 fill_between,但想知道是否可能有更优雅的解决方案。代码:

import numpy as np
import matplotlib.pyplot as plt
phi = 0.5
theta = 1.2
Rphi = np.array([[np.cos(phi), -np.sin(phi), 0.], [np.sin(phi), np.cos(phi), 0.], [0.,0.,1.]])
Rtheta = np.array([[1.,0.,0.], [0., np.cos(theta), -np.sin(theta)], [0., np.sin(theta), np.cos(theta)]])
R = np.dot(Rphi, Rtheta) 
Router = 0.06
Rinner = 0.04
rs = np.array([[np.cos(phi), np.sin(phi), 0.] for phi in np.linspace(0., 2*np.pi, 100)])
rs = np.dot(rs, R.T)
plt.plot(Rinner*rs[:,0], Rinner*rs[:,1], Router*rs[:,0], Router*rs[:,1])
plt.plot([0], [0], 'oy', ms=100)
Run Code Online (Sandbox Code Playgroud)

我想填充两个环之间的空间(是的,我正在尝试绘制土星!)

奖励:是否有一种简单的方法可以使深度正确?即,土星出现在背面的前面,如下图,但在正面的环后面?

土星

And*_*eak 5

您使用了错误的函数:plt.fill()是您可能需要的:

plt.fill(Router*rs[:,0], Router*rs[:,1],'blue')
plt.fill(Rinner*rs[:,0], Rinner*rs[:,1],'white')
plt.plot([0], [0], 'oy', ms=100)
Run Code Online (Sandbox Code Playgroud)

结果:

结果

使中间圆圈隐藏背景位应该是非常手动的:即使使用 matplotlib 的 3d 绘图在 z 顺序方面也有严重的困难(每个对象要么完全在另一个对象之前,要么完全在另一个对象之后)。您可能必须将椭圆分成两部分,并按照背景 -> 行星 -> 前景的顺序绘制它们。

此外,正如您所看到的,由于对matplotlib.rc. 我建议也使用基于数据的维度正确绘制行星:

Rsaturn = 0.018
rs0 = np.array([[np.cos(phi), np.sin(phi), 0.] for phi in np.linspace(0., 2*np.pi, 100)])
plt.fill(Rsaturn*rs0[:,0], Rsaturn*rs0[:,1],'yellow')
plt.axis('equal')
Run Code Online (Sandbox Code Playgroud)

新结果:

较新的输出


奖金问题让我正确地做到了这一点。为了能够用环的前部隐藏土星,您必须正确填充环,而不是在彼此之间绘制两个完整的椭圆。这是我的解决方案:

import numpy as np
import matplotlib.pyplot as plt
phi = 0.5
theta = 1.2
Rphi = np.array([[np.cos(phi), -np.sin(phi), 0.], [np.sin(phi), np.cos(phi), 0.], [0.,0.,1.]])
Rtheta = np.array([[1.,0.,0.], [0., np.cos(theta), -np.sin(theta)], [0., np.sin(theta), np.cos(theta)]])
R = np.dot(Rphi, Rtheta) 
Router = 0.06
Rinner = 0.04
Rsaturn = 0.018

#rs0 = np.array([[np.cos(phi), np.sin(phi), 0.] for phi in np.linspace(0., 2*np.pi, 100)])
phivec1 = np.linspace(0., np.pi, 50)
phivec2 = np.linspace(np.pi,2*np.pi, 50)
rs1 = np.array([np.cos(phivec1), np.sin(phivec1), np.zeros_like(phivec1)]).T  # first half arc
rs2 = np.array([np.cos(phivec2), np.sin(phivec2), np.zeros_like(phivec2)]).T  # second half arc
rs0 = np.concatenate((rs1,rs2),axis=0)  # full arc for Saturn
rs1 = np.dot(rs1, R.T)  # rotate
rs2 = np.dot(rs2, R.T)  # rotate

# draw foreground
semiring1 = np.concatenate((Router*rs1[:,:2],Rinner*rs1[::-1,:2]),axis=0)
plt.fill(semiring1[:,0], semiring1[:,1],'blue',edgecolor='none')
# draw Saturn
plt.fill(Rsaturn*rs0[:,0], Rsaturn*rs0[:,1],'yellow')
# draw foreground
semiring2 = np.concatenate((Router*rs2[:,:2],Rinner*rs2[::-1,:2]),axis=0)
plt.fill(semiring2[:,0], semiring2[:,1],'blue',edgecolor='none')
plt.axis('equal')
Run Code Online (Sandbox Code Playgroud)

一个变化是我通过将角度范围分成两部分来使用两个半椭圆,并且我将两个同心半椭圆fill一次一个连接到环部分。我们必须关闭 中的边缘颜色fill,否则数据的跳跃会表现为黑色线条弄乱图形。如果您需要边缘线,请使用 手动绘制它们plot

这是上面的结果:

最终解决方案