I could solve the problem by creating simple arrays using numpy
for surface plotting and switching to go.Surface
from Mesh3D
. Any solutions concerning the latter are still welcomed.
The complete code:
import pandas as pd
import plotly.graph_objects as go
import numpy as np
data = pd.read_excel(r"C:\Users\canoe\OneDrive\Asztali gép\Malin study (biathlon)\course profile plot_male.xlsx", sheet_name='Munka1')
x = data['x'].values
y = data['y'].values
z = data['alt'].values
i = data['incl'].values
X = np.vstack([x, x])
Y = np.vstack([y, y])
Z = np.vstack([[350] * len(x), z -0.1])
I = np.vstack([i, i])
fig = go.Figure()
fig.add_trace(go.Scatter3d(
x=x,
y=y,
z=z,
mode='lines',
line=dict(
color=i,
width=13,
colorscale='Jet',
colorbar=dict(
title=dict(
text='Incline [deg]',
font=dict(size=14, color='black')
),
thickness=20,
len=0.6,
tickfont=dict(size=12, color='black'),
tickmode='linear',
tickformat='.2f',
outlinewidth=1,
outlinecolor='black'
)
)
))
for j in range(0, len(x), 20):
color_value= i[j]
fig.add_trace(go.Surface(
z=Z,
x=X,
y=Y,
surfacecolor=I,
colorscale='jet',
cmin=min(i), cmax=max(i),
showscale=False,
opacity=0.7
))
fig.add_trace(go.Scatter3d(
x=x,
y=y,
z=[350] * len(x),
mode='lines',
line=dict(color='black', width=3),
name="Profile Curve"
))
for j in range(0, len(x), 20):
fig.add_trace(go.Scatter3d(
x=[x[j], x[j]],
y=[y[j], y[j]],
z=[350, z[j]],
mode='lines',
line=dict(color='dimgray', width=2),
opacity=0.6,
showlegend=False
))
fig.update_layout(
title="3D Course Profile Colored by Incline",
template='plotly_white',
scene=dict(
xaxis=dict(title='Meters north from start position', showgrid=True, zeroline=False),
yaxis=dict(title='Meters east from start position', showgrid=True, zeroline=False),
zaxis=dict(title='Altitude [m]', showgrid=True, zeroline=False),
aspectmode='manual',
aspectratio=dict(x=1.25, y=1, z=0.7)
),
margin=dict(l=0, r=0, b=0, t=50)
)
fig.show()
Version nr.2 using matplotlib.pyplot
:
I post a simpler solution using matplotlib.pyplot
but without edge colouring:
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from matplotlib import cm
import matplotlib.ticker as ticker
data = pd.read_excel(r'')
X_1d = data['x'].values
Y_1d = data['y'].values
Z_1d = data['alt'].values
I_1d = data['incl'].values
fig = plt.figure(figsize=(8, 5))
ax = fig.add_subplot(111, projection='3d')
X = np.vstack([X_1d, X_1d])
Y = np.vstack([Y_1d, Y_1d])
Z = np.vstack([Z_1d, Z_1d + (max(Z_1d)-min(Z_1d))]) #[350]*len(X_1d), Z_1d + 50 (and below twice)
I = np.vstack([I_1d, I_1d])
norm = plt.Normalize(I.min(), I.max())
colors = cm.jet(norm(I))
fig = plt.figure(figsize=(8, 5))
ax = fig.add_subplot(111, projection='3d')
ax.plot(X_1d, Y_1d, Z_1d + (max(Z_1d)-min(Z_1d)), color='black', linewidth=2)
surf = ax.plot_surface(X, Y, Z, facecolors=cm.jet(norm(I)), rstride=1, cstride=1, linewidth=0, antialiased=True, alpha=0.7)
ax.plot_wireframe(X, Y, Z, color='k', linewidth=1, alpha=1.0)
mappable = cm.ScalarMappable(norm=norm, cmap=cm.jet)
mappable.set_array(I)
cbar = fig.colorbar(mappable, ax=ax, shrink=0.5, alpha=0.7, aspect=5, extend='both', extendrect=True, spacing='proportional', format=ticker.FormatStrFormatter('%.1f'))
cbar.set_label('Incline [deg]', rotation=270, labelpad=15)
cbar.ax.axhline(max(I_1d), color='black', linewidth=1.2, linestyle='--')
cbar.ax.axhline(min(I_1d), color='black', linewidth=1.2, linestyle='--')
ax.set_xticks([])
ax.set_yticks([])
ax.set_zticks([])
ax.xaxis.line.set_color((0.0, 0.0, 0.0, 0.0))
ax.yaxis.line.set_color((0.0, 0.0, 0.0, 0.0))
ax.zaxis.line.set_color((0.0, 0.0, 0.0, 0.0))
ax.xaxis.set_pane_color((1.0, 1.0, 1.0, 0.0))
ax.yaxis.set_pane_color((1.0, 1.0, 1.0, 0.0))
ax.zaxis.set_pane_color((1.0, 1.0, 1.0, 0.0))
plt.tight_layout()
plt.show()