私は、ワイヤフレームを使用して(X_I、Y_I)の関数としての形態z_iの3Dデータをプロットする必要があります。私は以下のコードを書きました:
import numpy as np
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import axes3d
import scipy.interpolate as spint
## Data to plot
sim_data = np.array([[ 20, 1, 8],
[ 20, 2, 7],
[ 20, 4, 7],
[ 20, 6, 6],
[ 20, 10, 6],
[ 50, 0.4, 15],
[ 50, 0.8, 11],
[ 50, 1, 10],
[ 50, 2, 8],
[ 50, 4, 7],
[ 50, 6, 7],
[ 50, 10, 7],
[100, 0.4, 22],
[100, 0.8, 15],
[100, 1, 13],
[100, 2, 10],
[100, 4, 8],
[100, 6, 7],
[100, 10, 7]])
x = sim_data[:, 0]
y = sim_data[:, 1]
z = sim_data[:, 2]
# Do trisurf plot
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_trisurf(x, y, z)
ax.set_xlabel('Air flow')
ax.set_ylabel('Fuel rate')
ax.set_zlabel('Temp.')
ax.text2D(0.05, 0.95, "Trisurf plot", transform=ax.transAxes)
# Transform from vector to grid
X, Y = np.meshgrid(x, y)
xi = (X, Y)
Z = spint.griddata((x,y), z, xi)
# Do wireframe plot
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_wireframe(X, Y, Z)
ax.set_xlabel('Air flow')
ax.set_ylabel('Fuel rate')
ax.set_zlabel('Temp.')
ax.text2D(0.05, 0.95, "Wireframe plot", transform=ax.transAxes)
# Do surface plot
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(X, Y, Z)
ax.set_xlabel('Air flow')
ax.set_ylabel('Fuel rate')
ax.set_zlabel('Temp.')
ax.text2D(0.05, 0.95, "Surface plot", transform=ax.transAxes)
しかし、私は(赤い矢印でマークされた)いくつかの迷惑な余分な配線を取得します:
どのように私は、この矢印を取り除くことができますか?方法によって、表面プロットをしようとしているときに、私は同じ問題を抱えています:
私の目標は、以下のようなtrisurfプロットと同様のプロットを持っていることですが、ワイヤーフレーム可視化。
事前に感謝します。
ワイヤーフレームと間違っては何ですか?
私はわからないが、私はこの問題は、あなたのデータであると思います。それは小さなだとあなたは慎重に見ている場合、あなたはそれが三つの異なるライン(観測)のスタックのように見えることがわかります。このプロットを見てください:
it's definitely there are three parallel lines over there. I suppose, that's might cause confusion with plot_wireframe
, as well as with plot
from the previous image. I see 3 possible solutions:
Solution 1: Use plot
Ok, so the first solution is not to use plot_wireframe
at all. Let's use good old one plot
to build our own wires. But first, let's break our data into 3 lines data:
line1 = sim_data[0:5][::-1] # NOTE: the first line is shorter
line2 = sim_data[5:12][::-1]
line3 = sim_data[12:][::-1]
Plot them all!
# a helper function
def prepare_fig(fw=7, fh=7, view = (25, 30)):
fig = plt.figure(figsize=(fw, fh))
ax = fig.add_subplot(111, projection='3d')
ax.view_init(view[0], view[-1])
return ax
ax = prepare_fig()
ax.title.set_text('3 Lines')
for line in [line1, line2, line3]:
x, y, z = line[:, 0], line[:, 1], line[:, 2]
ax.plot(x, y, z, c='tab:blue', linewidth=3)
Ok, we fixed undesired links, now let's add parallel links (lines) to connect our main lines:
ax = prepare_fig()
ax.title.set_text('Paralel links')
for i in range(len(line3)):
x, y, z = [], [], []
if i < len(line1):
x.append(line1[:, 0][i])
y.append(line1[:, 1][i])
z.append(line1[:, 2][i])
else:
# line1 is shorter so we will put nan here (for now)
x.append(np.nan)
y.append(np.nan)
z.append(np.nan)
x.extend([line2[:, 0][i], line3[:, 0][i]])
y.extend([line2[:, 1][i], line3[:, 1][i]])
z.extend([line2[:, 2][i], line3[:, 2][i]])
ax.plot(x, y, z, c='tab:blue', linewidth=3)
Now all in one:
Final Code:
ax = prepare_fig()
ax.title.set_text('Handmade Wireframe (enclosed)')
line1 = sim_data[0:5][::-1]
line2 = sim_data[5:12][::-1]
line3 = sim_data[12:][::-1]
for line in [line1, line2, line3]:
x, y, z = line[:, 0], line[:, 1], line[:, 2]
ax.plot(x, y, z, c='tab:blue', linewidth=3)
for i in range(len(line3)):
x, y, z = [], [], []
if i < len(line1):
x.append(line1[:, 0][i])
y.append(line1[:, 1][i])
z.append(line1[:, 2][i])
else:
# put nan because line1 is shorter
# x.append(np.nan)
# y.append(np.nan)
# z.append(np.nan)
# Or you can just replace it with last line1 value
x.append(line1[:, 0][-1])
y.append(line1[:, 1][-1])
z.append(line1[:, 2][-1])
x.extend([line2[:, 0][i], line3[:, 0][i]])
y.extend([line2[:, 1][i], line3[:, 1][i]])
z.extend([line2[:, 2][i], line3[:, 2][i]])
ax.plot(x, y, z, c='tab:blue', linewidth=3)
Solution 2: Use plot_trisurf
.
If triangles are acceptable, another solution is to transform trisurf to wireframe-like by some tweaking.
x = sim_data[:, 0]
y = sim_data[:, 1]
z = sim_data[:, 2]
ax = prepare_fig()
ax.title.set_text('Trisurf Wireframe')
trisurf = ax.plot_trisurf(x, y, z)
# turn of surface color, you can control it with alpha here:
trisurf.set_facecolor(mpl.colors.colorConverter.to_rgba('w', alpha=0.0))
# setting wire color
trisurf.set_edgecolor('tab:blue')
#setting wire width
trisurf.set_linewidth(3)
Solution 3: Use plot_wireframe
and interpolation at linspace grid.
あなたが格好良い滑らかな表面をしたい場合、これが解決策になるかもしれません。あなただけの新しいグリッドを生成し、使用する必要があるscipy
のspint.griddata
補間を実行します:
import scipy.interpolate as spint
x = sim_data[:, 0]
y = sim_data[:, 1]
z = sim_data[:, 2]
# generate new linear grid based on previous
X, Y = np.meshgrid(np.linspace(min(x), max(x), len(x)),
np.linspace(min(y), max(y), len(y)))
Z = spint.griddata((x, y), z, (X, Y))
ax = prepare_fig()
ax.title.set_text('Interpotation on Linspace Grid')
# ax.plot_wireframe(X, Y, Z, rstride=3, cstride=3)
ax.plot_surface(X, Y, Z, rstride=3, cstride=3)
そして、あなたはこのような何かを取得します。