Adding planar surfaces to trisurf

I’m quite new to Plotly. I’m trying to generate a plot that combines a 3D surface plot (from a volume) with 2D planar surfaces.

For the first bit, I followed this guide, using create_trisurf to visualise a 3D “segment”, i.e. a number of 2D segmentations (binary masks) that define a 3D volume.

from skimage import measure
from plotly import figure_factory as FF
from plotly.offline import iplot
init_notebook_mode(connected=True) 

image = PixArr.transpose(2,1,0)

verts, faces = measure.marching_cubes_classic(image, spacing=image.shape)

x,y,z = zip(*verts) 

colormap=['rgb(255,105,180)','rgb(255,255,51)','rgb(0,191,255)']
    
fig = FF.create_trisurf(x=x,
                        y=y, 
                        z=z, 
                        plot_edges=False,
                        colormap=colormap,
                        simplices=faces,
                        backgroundcolor='rgb(64, 64, 64)',
                        title='Segment')

iplot(fig)

PixArr is a numpy array of shape (F, C, R), containing F frames of 2D binary masks with R rows and C columns.

I managed to get what I wanted from the segmentation data.

Next I followed the example here to plot a plane.

I wrote a function that takes a list of DICOM images and generates a list of points that mark out the corners of each image, and I unpack the points into lists X, Y and Z of the x, y and z-coordinates for one of the “boxes” that defines one plane and plot it:

data = [{'type': 'mesh3d',        
         'x': X,
         'y': Y,
         'z': Z,
         'color': 'red',
         'opacity': 0.1}]

plane = go.Figure(data=data, layout={})

iplot(plane)

That also worked, but I was unable to loop through each set of X, Y, Z lists for each plane using add_trace to plot all planes in the figure. It appears that add_trace cannot be used for go.Figure(). That’s one issue, but the solution to that may lie in the next barrier I hit: Trying to combine a planar trace to the trisurf graph.

I tried to follow the solution posted for this thread, i.e.

Data = [fig.data[0], fig.data[1], plane]

iplot(Data)

but I got the following traceback:

ValueError:
Invalid element(s) received for the ‘data’ property of
Invalid elements include: [Figure({
‘data’: [{‘color’: ‘red’,
‘opacity’: 0.1,
‘type’: ‘mesh3d’,
‘x’: [-129.80790963, 126.19209036999999, 126.19209042250645,
-129.80790957749355],
‘y’: [-109.97568891, -109.97568896250647, 146.02431103749353,
146.02431109],
‘z’: [73.859869, 73.859869, 73.859869, 73.859869]}],
‘layout’: {‘template’: ‘…’}
})]

The 'data' property is a tuple of trace instances
that may be specified as:
  - A list or tuple of trace instances
    (e.g. [Scatter(...), Bar(...)])
  - A single trace instance
    (e.g. Scatter(...), Bar(...), etc.)
  - A list or tuple of dicts of string/value properties where:
    - The 'type' property specifies the trace type
        One of: ['area', 'bar', 'barpolar', 'box',
                 'candlestick', 'carpet', 'choropleth',
                 'choroplethmapbox', 'cone', 'contour',
                 'contourcarpet', 'densitymapbox', 'funnel',
                 'funnelarea', 'heatmap', 'heatmapgl',
                 'histogram', 'histogram2d',
                 'histogram2dcontour', 'image', 'indicator',
                 'isosurface', 'mesh3d', 'ohlc', 'parcats',
                 'parcoords', 'pie', 'pointcloud', 'sankey',
                 'scatter', 'scatter3d', 'scattercarpet',
                 'scattergeo', 'scattergl', 'scattermapbox',
                 'scatterpolar', 'scatterpolargl',
                 'scatterternary', 'splom', 'streamtube',
                 'sunburst', 'surface', 'table', 'treemap',
                 'violin', 'volume', 'waterfall']

    - All remaining properties are passed to the constructor of
      the specified trace type

    (e.g. [{'type': 'scatter', ...}, {'type': 'bar, ...}])

I would greatly appreciate some (newbie-level) help in understanding what went wrong, or guidance on how I can go about combining these two different graph types, ideally, with multiple planar graphs. Thanks.

I have the same issue. It can be solved by calling go.Figure on the whole data (CT and the plane).

So, instead of creating

Data = [fig.data[0], fig.data[1], plane]

You need to call

data += fig.to_dict()['data'][0:2]

before

plane = go.Figure(data=data, layout={})

Also, you should to do something like

fig = FF.create_trisurf(x=x,
                        y=y, 
                        z=z, 
                        plot_edges=False,
                        colormap=colormap,
                        simplices=faces,
                        backgroundcolor='rgb(64, 64, 64)',
                        title='Segment')

data = [{'type': 'mesh3d',        
         'x': X,
         'y': Y,
         'z': Z,
         'color': 'red',
         'opacity': 0.1}]

data += fig.to_dict()['data'][0:2]

fig_plane = go.Figure(data=data, layout={})
iplot(fig_plane)