The example on Plot.ly about the 3D Wireframes has helped me a lot. But there is one thing that bothered me: A wireframe is represented by a multitude of line objects. This is slightly unintuitive and makes the legend harder to read. Here’s a nice work-around: Use one linestrip and interrupt it by Not-a-Number values. I just wanted to share it, in case anybody else had the same issue:
from numpy import NaN, radians
import plotly
import numpy as np
import plotly.graph_objs as go
def wireframe3d( uRange, vRange, f, **kwargs ):
def data_gen():
for u in uRange:
yield (NaN, NaN, NaN) # <- NaN functions as a 'line break'
for v in vRange:
yield f(u,v)
for v in vRange:
yield (NaN, NaN, NaN)
for u in uRange:
yield f(u,v)
data = data_gen()
next(data)
data = np.vstack(data)
def text_gen():
for u in uRange:
yield '???'
for v in vRange:
yield 'u: %.3f v: %.3f' % (u,v)
for v in vRange:
yield '???'
for u in uRange:
yield 'u: %.3f v: %.3f' % (u,v)
text = text_gen()
next(text)
text = tuple(text)
return go.Scatter3d(
x = data[:,0], y = data[:,1], z = data[:,2],
text = text, mode = 'lines', **kwargs
)
surface = wireframe3d(
np.linspace(-2,+2,11),
np.linspace(-1,+1,11),
lambda u,v: (u,v,u*v),
line = dict(color='#FF0000', width=2),
name = 'Surface'
)
sin = lambda x: np.sin(radians(x))
cos = lambda x: np.cos(radians(x))
sphere = wireframe3d(
np.linspace( 0, 360, 19),
np.linspace(-90, +90, 19),
lambda u,v: ( cos(u)*cos(v), sin(u)*cos(v), sin(v) ),
line = dict(color='#0000FF', width=2),
name = 'Sphere'
)
layout = go.Layout(
title='Wireframe Plot',
scene = dict(
aspectratio = dict(x=1, y=1, z=1),
aspectmode = 'data'
)
)
fig = go.Figure(data=[surface,sphere],layout=layout)
plotly.offline.plot(fig)