Что не так с каркасом?
Я не уверен, но думаю, что проблема в ваших данных. Он маленький, и если вы внимательно посмотрите, то увидите, что он выглядит как стопка из трех разных линий (наблюдений). Посмотрите на этот график:
там определенно есть три параллельные линии. Я полагаю, это может вызвать путаницу с plot_wireframe
, а также с plot
из предыдущего изображения. Я вижу 3 возможных решения:
Решение 1: Используйте plot
Хорошо, поэтому первое решение - вообще не использовать plot_wireframe
. Давайте использовать старый добрый plot
для создания наших собственных проводов. Но сначала давайте разберем наши данные на 3 строки:
line1 = sim_data[0:5][::-1] # NOTE: the first line is shorter
line2 = sim_data[5:12][::-1]
line3 = sim_data[12:][::-1]
Составьте их все!
# 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 мы исправили нежелательные ссылки, теперь давайте добавим параллельные ссылки (линии) для подключения наших основных линий:
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)
Теперь все в одном:
Итоговый код:
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)
Решение 2: Используйте plot_trisurf
.
Если треугольники приемлемы, другое решение состоит в том, чтобы преобразовать трисурф в каркасный тип путем некоторой подстройки.
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)
Решение 3: Использование plot_wireframe
и интерполяция в сетке linspace.
Это может быть решением, если вы хотите, чтобы гладкая поверхность выглядела хорошо. Вам просто нужно сгенерировать новую сетку и затем использовать 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)
И вы получите что-то вроде этого: