具有2D投影的3D线框图:空间组织和投影频率

时间:2020-09-29 11:47:28

标签: python matplotlib 3d contourf wireframe

我正在处理由线框显示的3D图,其中2D图分别投影在x,y和z表面上。您可以在下面找到一个最小的示例。

我有2个问题:

  1. 使用contourf,每个x = 10,x = 20,...或y = 10,y = 20,...的二维图都显示在图墙上。是否有可能定义分别显示哪些x或y等高线图?例如,如果我只想将y = 0.5的xz轮廓图镜像到墙上?

添加:为了显示“ 2D图”的含义,我将代码中的“ contourf”更改为“ contour”,并将生成的图添加到此问题中。在这里,您现在可以看到不同y值的xz线,都偏移到y = 90。如果我不想拥有所有的行,但是只定义了其中的两个,该怎么办?

3D_plot_with_2D_contours

  1. 如在最小示例中所见,2D等高线图光学地覆盖了线框3D图。通过在alpha = 0.5的情况下增加透明度,我可以增加2D轮廓的透明度以至少看到线框,但这在光学上还是错误的。是否可以对对象正确排序?
import matplotlib.pyplot as plt,numpy as np
import pylab as pl

from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt,numpy as np

plt.clf()

fig = plt.figure(1,figsize=(35,17),dpi=600,facecolor='w',edgecolor='k')
fig.set_size_inches(10.5,8)
ax  = fig.gca(projection='3d')
X, Y, Z = axes3d.get_test_data(0.05)

Xnew = X + 50
Ynew = Y + 50

cset = ax.contourf(Xnew, Ynew, Z, zdir='z', offset=-100, cmap=plt.cm.coolwarm, alpha=0.5)
cset = ax.contourf(Xnew, Ynew, Z, zdir='x', offset=10, cmap=plt.cm.coolwarm, alpha=0.5) 
cset = ax.contourf(Xnew, Ynew, Z, zdir='y', offset=90, cmap=plt.cm.coolwarm, alpha = 0.5) 

ax.plot_wireframe(Xnew, Ynew, Z, rstride=5, cstride=5, color='black')

Z=Z-Z.min()
Z=Z/Z.max()

from scipy.ndimage.interpolation import zoom

Xall=zoom(Xnew,5)
Yall=zoom(Ynew,5)
Z=zoom(Z,5)

ax.set_xlim(10, 90)
ax.set_ylim(10, 90)
ax.set_zlim(-100, 100)

ax.tick_params(axis='z', which='major', pad=10)

ax.set_xlabel('X',labelpad=10)
ax.set_ylabel('Y',labelpad=10)
ax.set_zlabel('Z',labelpad=17)


ax.view_init(elev=35., azim=-70)

fig.tight_layout()

plt.show()

添加2:这是我正在使用的实际代码。但是,原始数据隐藏在csv文件中,这些文件太大而无法包含在最小示例中。这就是为什么最初将其替换为测试数据的原因。但是,也许实际的代码还是有帮助的。

from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt,numpy as np
import pylab as pl
from matplotlib.markers import MarkerStyle

import csv
with open("X.csv", 'r') as f:
  X = list(csv.reader(f, delimiter=";"))
import numpy as np
X = np.array(X[1:], dtype=np.float)

import csv
with open("Z.csv", 'r') as f:
  Z = list(csv.reader(f, delimiter=";"))
import numpy as np
Z = np.array(Z[1:], dtype=np.float)

Y = [[7,7.1,7.2,7.3,7.4,7.5,7.6,7.7,7.8,7.9,8,8.1,8.2,8.3,8.4,8.5,8.6,8.7,8.8,8.9,9]]

Xall = np.repeat(X[:],21,axis=1)
Yall = np.repeat(Y[:],30,axis=0)

from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt,numpy as np


plt.clf()

fig = plt.figure(1,figsize=(35,17),dpi=600,facecolor='w',edgecolor='k')
fig.set_size_inches(10.5,8) 
ax  = fig.gca(projection='3d')

cset = ax.contourf(Xall, Yall, Z, 2, zdir='x', offset=0,  cmap=plt.cm.coolwarm, shade = False, edgecolor='none', alpha=0.5)
cset = ax.contourf(Xall, Yall, Z, 2, zdir='y', offset=9, cmap=plt.cm.coolwarm, shade = False, edgecolor='none', alpha=0.5)

ax.plot_wireframe(Xall, Yall, Z, rstride=1, cstride=1, color='black')

Z=Z-Z.min()
Z=Z/Z.max()

from scipy.ndimage.interpolation import zoom

Xall=zoom(Xall,5)
Yall=zoom(Yall,5)
Z=zoom(Z,5)

cset = ax.plot_surface(Xall, Yall, np.zeros_like(Z)-0,facecolors=plt.cm.coolwarm(Z),shade=False,alpha=0.5,linewidth=False)

ax.set_xlim(-0.5, 31)
ax.set_ylim(6.9, 9.1)
ax.set_zlim(0, 500)

labelsx = [item.get_text() for item in ax.get_xticklabels()]
empty_string_labelsx = ['']*len(labelsx)
ax.set_xticklabels(empty_string_labelsx)

labelsy = [item.get_text() for item in ax.get_yticklabels()]
empty_string_labelsy = ['']*len(labelsy)
ax.set_yticklabels(empty_string_labelsy)

labelsz = [item.get_text() for item in ax.get_zticklabels()]
empty_string_labelsz = ['']*len(labelsz)
ax.set_zticklabels(empty_string_labelsz)

import matplotlib.ticker as ticker
ax.xaxis.set_major_locator(ticker.MultipleLocator(5))
ax.xaxis.set_minor_locator(ticker.MultipleLocator(1))
ax.yaxis.set_major_locator(ticker.MultipleLocator(0.5))
ax.yaxis.set_minor_locator(ticker.MultipleLocator(0.25))
ax.zaxis.set_major_locator(ticker.MultipleLocator(100))
ax.zaxis.set_minor_locator(ticker.MultipleLocator(50))

ax.tick_params(axis='z', which='major', pad=10)

ax.set_xlabel('X',labelpad=5,fontsize=15)
ax.set_ylabel('Y',labelpad=5,fontsize=15)
ax.set_zlabel('Z',labelpad=5,fontsize=15)


ax.view_init(elev=35., azim=-70)

fig.tight_layout()

plt.show()

2 个答案:

答案 0 :(得分:0)

(问题1的答案)要绘制表面与指定平面(y = -20,y = 20)之间的交点,需要找出Y [?] =-20和20。我发现Y [100] = 20,Y [20] =-20。

用于绘制相交线的相关代码:

# By inspection, Y[100]=20, Y[20]=-20
ax.plot3D(X[100], Y[100], Z[100], color='red', lw=6)  # line-1 at y=20
ax.plot3D(X[20], Y[20], Z[20], color='green', lw=6)   # line-2 at y=-20

# Project them on Z=-100 plane
ax.plot3D(X[100], Y[100], -100, color='red', lw=3)  # projection of Line-1
ax.plot3D(X[20], Y[20], -100, color='green', lw=3)  # projection of Line-2

输出图:

y20-20

(问题2的答案)为了使线框在表面图中突出,可以得到更好的图。表面图必须是部分透明的,这可以通过设置选项alpha=0.6来实现。相关代码如下。

Z1 = Z-Z.min()
Z1 = Z1/Z.max()
Xall = zoom(X,3)
Yall = zoom(Y,3)
Zz = zoom(Z1, 3)

surf = ax.plot_surface(Xall, Yall, Zz, rstride=10, cstride=10, 
                       facecolors = cm.jet(Zz/np.amax(Zz)),
                       linewidth=0, antialiased=True,
                       alpha= 0.6)

# Wireframe
ax.plot_wireframe(X, Y, Z, rstride=5, cstride=5, color='black', alpha=1, lw=0.8)

情节是:

combined

答案 1 :(得分:0)

替代答案。

此代码演示

  1. 表面及其对应线框的图
  2. 在指定的x和y值下创建数据及其3d线图(在表面上悬于1处)
  3. 3d线(在2中)在框架墙上的投影
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
from scipy import interpolate
import numpy as np

# use the test data for plotting
fig = plt.figure(1, figsize=(6,6), facecolor='w', edgecolor='gray')
ax  = fig.gca(projection='3d')
X, Y, Z = axes3d.get_test_data(0.1)  #get 3d data at appropriate density

# create an interpolating function
# can take a long time if data is too large
f1 = interpolate.interp2d(X, Y, Z, kind='linear')

# in general, one can use a set of other X,Y,Z that cover a surface
# preferably, (X,Y) are in grid arrangement

# make up a new set of 3d data to plot
# ranges of x1, and y1 will be inside (X,Y) of the data obtained above
# related grid, x1g,y1g,z1g will be obtained from meshgrid and the interpolated function
x1 = np.linspace(-15,15,10)
y1 = np.linspace(-15,15,10)
x1g, y1g = np.meshgrid(x1, y1)
z1g = f1(x1, y1)  #dont use (x1g, y1g)

# prep data for 3d line on the surface (X,Y,Z) at x=7.5
n = 12
x_pf = 7.5
x5 = x_pf*np.ones(n)
y5 = np.linspace(-15, 15, n)
z5 = f1(x_pf, y5)
# x5,y5,z5 can be used to plot 3d line on the surface (X,Y,Z)

# prep data for 3d line on the surface (X,Y,Z) at y=6
y_pf = 6
x6 = np.linspace(-15, 15, n)
y6 = x_pf*np.ones(n)
z6 = f1(x6, y_pf)
# x6,y6,z6 can be used to plot 3d line on the surface (X,Y,Z)

ax  = fig.gca(projection='3d')

ax.plot_surface(x1g, y1g, z1g, alpha=0.25)
ax.plot_wireframe(x1g, y1g, z1g, rstride=2, cstride=2, color='black', zorder=10, alpha=1, lw=0.8)

# 3D lines that follow the surface
ax.plot(x5,y5,z5.flatten(), color='red', lw=4)
ax.plot(x6,y6,z6.flatten(), color='green', lw=4)

# projections of 3d curves
# project red and green lines to the walls
ax.plot(-15*np.ones(len(y5)), y5, z5.flatten(), color='red', lw=4, linestyle=':', alpha=0.6)
ax.plot(x6, 15*np.ones(len(x6)), z6.flatten(), color='green', lw=4, linestyle=':', alpha=0.6)

# projections on other sides (become vertical lines)
# change to if True, to plot these
if False:
    ax.plot(x5, 15*np.ones(len(x5)), z5.flatten(), color='red', lw=4, alpha=0.3)
    ax.plot(-15*np.ones(len(x6)), y6, z6.flatten(), color='green', lw=4, alpha=0.3)

ax.set_title("Projections of 3D lines")

# set limits
ax.set_xlim(-15, 15.5)
ax.set_ylim(-15.5, 15)

plt.show();

enter image description here