【问题标题】:How can I create a 4D complex surface plot? [closed]如何创建 4D 复杂曲面图? [关闭]
【发布时间】:2020-11-18 12:00:17
【问题描述】:

我有以下 Matlab 代码,我想将其转换为 Python 3 代码。

r = (0:1:15)';                           % create a matrix of complex inputs
theta = pi*(-2:0.05:2);
z = r*exp(1i*theta);
%w = z.^(1/2)  ;                          % calculate the complex outputs
w = sqrt(r)*exp(1i*theta/2);

figure('Name','Graphique complexe','units','normalized','outerposition',[ 0.08 0.1 0.8 0.55]);
subplot(121)

surf(real(z),imag(z),real(w),imag(w))    % visualize the complex function using surf
xlabel('Real(z)')
ylabel('Imag(z)')
zlabel('Real(u)')
cb = colorbar;
colormap jet;                            % gradient from blue to red
cb.Label.String = 'Imag(v)';

subplot(122)
surf(real(z),imag(z),imag(w),real(w))    % visualize the complex function using surf
xlabel('Real(z)')
ylabel('Imag(z)')
zlabel('Imag(v)')
cb = colorbar;
colormap jet;                            % gradient from blue to red
cb.Label.String = 'Real(u)';

结果和原始讨论可以在here找到。 SO page 上也有讨论。但是,我未能运行和重现这些代码。接下来我可以尝试什么?

【问题讨论】:

  • 你运气不好,因为我总是关闭这样的代码请求,但在这种特殊情况下,我无法传递移植我自己的 MATLAB 代码的乐趣> 到蟒蛇。所以,我希望你能好好利用这个结果。请务必学习 python 和 matplotlib 的基础知识。
  • @hbaromega:一些有用的反馈:问题末尾的短语 Any help? 可能对以英语为母语的人来说似乎更有资格。它似乎也将解决您的问题的责任转移给了读者。一般来说,如果您提出问题的方式表明您仍然很高兴并愿意做大部分工作,那么您可能会得到更好的接待。
  • @halfer 抱歉,过去几天我有点过分了。感谢您纠正我,我会在以后记住这个建议。
  • 不用担心,感谢您考虑:-)

标签: python matlab matplotlib 3d


【解决方案1】:

如果您花时间学习 matplotlib(尤其是 3d 轴)的工作原理,这非常简单:

import numpy as np  
import matplotlib.pyplot as plt  
import matplotlib.cm as cm 
from mpl_toolkits.mplot3d import Axes3D 
 
# compute data to plot 
r, theta = np.mgrid[1:16, -2*np.pi:2*np.pi:50j] 
z = r * np.exp(1j*theta)  
w = np.sqrt(r) * np.exp(1j*theta/2)  
 
# plot data  
fig = plt.figure()  
for plot_index in [1, 2]: 
    if plot_index == 1: 
        z_data, c_data = w.real, w.imag 
        z_comp, c_comp = 'Re', 'Im' 
    else: 
        z_data, c_data = w.imag, w.real 
        z_comp, c_comp = 'Im', 'Re' 
    c_data = (c_data - c_data.min()) / c_data.ptp() 
    colors = cm.viridis(c_data) 
 
    ax = fig.add_subplot(f'12{plot_index}', projection='3d') 
    surf = ax.plot_surface(z.real, z.imag, z_data, facecolors=colors,
                           clim=[z_data.min(), z_data.max()])
    ax.set_xlabel('$Re z$')  
    ax.set_ylabel('$Im z$')   
    ax.set_zlabel(f'${z_comp} w$')  
    cb = plt.colorbar(surf, ax=ax)  
    cb.set_label(f'${c_comp} w$')  
 
plt.show()

结果:

需要注意的几点:

  • Viridis 颜色图很好,jet 很差。
  • 一般而言,复杂(互锁)3d 几何图形可能存在渲染问题,因为 matplotlib 具有 2d 渲染器。幸运的是,在这种情况下,数据集耦合得足够紧密,即使您以交互方式围绕图形旋转,这似乎也不会发生。 (但如果您要将两个相交的曲面绘制在一起,things would probably be different。)
  • 可能希望启用标签的乳胶渲染以使结果更加清晰。
  • 如果您使用根据数据的 z 分量着色的默认选项,阴影看起来会好很多。

如果我们还想移植my MATLAB answer 的第二部分,您将不得不移植use a trick to stitch together the two branches of the function(正如我所说,这是正确渲染互锁表面所必需的)。对于上面代码中的具体示例,这不会给你完美的结果,因为两个分支本身在虚部中都包含不连续性,所以无论我们努力渲染两个表面,结果看起来有点糟糕:

import numpy as np 
import matplotlib.pyplot as plt 
import matplotlib.cm as cm 
from mpl_toolkits.mplot3d import Axes3D 
 
# compute data to plot 
r0 = 15 
re, im = np.mgrid[-r0:r0:31j, -r0:r0:31j] 
z = re + 1j*im 
r, theta = abs(z), np.angle(z) 
w1 = np.sqrt(r) * np.exp(1j*theta/2)  # first branch 
w2 = np.sqrt(r) * np.exp(1j*(theta + 2*np.pi)/2)  # second branch 
 
# plot data 
fig = plt.figure() 
for plot_index in [1, 2]: 
    # construct transparent bridge 
    re_bridge = np.vstack([re[-1, :], re[0, :]]) 
    im_bridge = np.vstack([im[-1, :], im[0, :]]) 
    c_bridge = np.full(re_bridge.shape + (4,), [1, 1, 1, 0])  # 0% opacity
 
    re_surf = np.vstack([re, re_bridge, re]) 
    im_surf = np.vstack([im, im_bridge, im]) 
    w12 = np.array([w1, w2]) 
    if plot_index == 1: 
        z_comp, c_comp = 'Re', 'Im' 
        z12, c12 = w12.real, w12.imag 
    else: 
        z_comp, c_comp = 'Im', 'Re' 
        z12, c12 = w12.imag, w12.real 
         
    color_arrays = cm.viridis((c12 - c12.min()) / c12.ptp()) 
    z1,z2 = z12 
    c1,c2 = color_arrays 
     
    z_bridge = np.vstack([z1[-1, :], z2[0, :]]) 
    z_surf = np.vstack([z1, z_bridge, z2]) 
    c_surf = np.vstack([c1, c_bridge, c2]) 
     
    ax = fig.add_subplot(f'12{plot_index}', projection='3d') 
    surf = ax.plot_surface(re_surf, im_surf, z_surf, facecolors=c_surf, 
                           clim=[c12.min(), c12.max()], 
                           rstride=1, cstride=1) 
    ax.set_xlabel('$Re z$') 
    ax.set_ylabel('$Im z$') 
    ax.set_zlabel(f'${z_comp} w$') 
    cb = plt.colorbar(surf, ax=ax) 
    cb.set_label(f'${c_comp} w$') 
  
plt.show()

右图中的丑陋跳跃可能需要大量工作才能修复,但这并不容易:这是两个表面数据集的实际不连续性,发生在负实数参数处。由于您的实际问题可能是more like this,因此您可能不需要面对这个问题,您可以使用上述缝合(桥接)技巧来组合您的表面。

【讨论】:

  • 确实,能从问题中引用代码的人那里得到答案是一种幸运和快乐。现在我可以按照相同的步骤翻译第二个 Matlab 代码。但是,z = [z, nan(size(w1,1),1), z(:,end:-1:1)]; w = [w1, nan(size(w1,1),1), w2(:,end:-1:1)]; 部分的 Python 版本应该是什么,您应该在其中引入 NaN 以避免在负实半轴上跳跃。其次,我尝试将颜色图更改为其他颜色(比如seismic)。颜色条仍然保留viridis。我还需要在哪里进行更改?
  • @hbaromega 我不确定这个跳跃技巧在 matplotlib 中会如何发挥作用,我稍后会尝试检查一下。至于颜色图:您必须将 cmap='seismic' 传递给对 plot_surface 的调用才能影响颜色条(我没有注意到这一点;我几乎总是使用默认的 viridis)。
  • 谢谢,cmap='seismic' 在争论中的作用就像一个魅力。如果您在 Python 中成功编写了跳跃技巧,请告诉我。我有一篇类似的帖子,其中我未能为复杂矩阵的特征值生成黎曼图:stackoverflow.com/questions/63078039/… 如果有私人聊天的选项,它也可能会有所帮助。
  • @hbaromega 看到我的更新,这就是我们可以用这种方法轻松完成的事情。图中的跳跃与matplotlib的渲染问题无关,是这个数据集和这个方法的根本问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-13
  • 2020-02-27
  • 2018-10-16
相关资源
最近更新 更多