Display a custom colorbar with `Mesh3d` and `vertexcolor`

Hi there,

I have two brain surface data defined over the same mesh, one is a statistical map and the other a simple background which gives a nicer rendering of the brain. When displaying only one of these, everything works perfectly fine, I am using Mesh3d and setting the intensity and colorscale, and I can display the colorbar (or not) based on a boolean input parameter.
This basically looks like this:

x, y, z = coords.T
i, j, k = faces.T
colorbar = True
mesh_3d = go.Mesh3d(x=x, y=y, z=z, i=i, j=j, k=k,
                                 intensity=stat_map,
                                 colorscale=colors,
                                 showscale=colorbar)

Now, the problem is that the statistical map can be thresholded by the user, meaning that we donโ€™t want to plot the statistical map values between -threshold and +threshold. Instead, we want to draw the background map with a different color scale (usually we use something like coldhot for the stat map and Greys for the background map). For the moment, the only way I could do that is to compute the color of each vertex and provide it through vertexcolor instead of through intensity and colorscale to Mesh3d:

vertexcolor = _get_vertexcolor(
                 surf_map, our_cmap, norm, threshold, bg_map
             )
mesh_3d = go.Mesh3d(x=x, y=y, z=z, i=i, j=j, k=k,
                                 vertexcolor=vertexcolor,
                                 showscale=colorbar)

The output is what I expect except that I couldnโ€™t find a way to display and customize the colorbar. The showscale parameter is completely ignored and providing a colorscale in addition to vertexcolor to Mesh3d doesnโ€™t seem to solve the issue. Furthermore, Iโ€™d like to be able to customize the colorbar to have a specific color for the threshoded part.
To give a better idea of what Iโ€™m trying to do, this is what it looks like with Matplotlib (threshold=2.0) and what I would like to reproduce with plotly:

te

Hope this post was understandable.
Let me know if not, and I will give more details.

Thanks for the amazing work!

Nicolas

Hi @NicolasGensollen,

Welcome to Plotly Forum!
Please take a look at an answer to a question, regarding definition of a discrete custom colormap, here:
https://community.plotly.com/t/colors-for-discrete-ranges-in-heatmaps/7780/14
and let us know if it helps.

Hi @empet

Thanks for the welcoming message!
I had a look at your reference and it was definitely a helpful resource to better understand how to build discrete custom colormaps, thank you.
However, in my situation, the problem is not really on the construction of the colorscale, but rather on how to use it with vertexcolor in Mesh3d. I think I could define a colorscale matching the way I color vertex, but it seems like you cannot display the colorbar when using vertexcolor.
That is doing the following will NOT display the colorbar:

# Compute colors for vertices in a custom way
vertexcolor = _get_vertexcolor(
                 surf_map, our_cmap, norm, threshold, bg_map
             )
# Let's pretend I can build a colorscale making sense with vertexcolor
colorscale = _get_colorscale(...)
mesh_3d = go.Mesh3d(x=x, y=y, z=z, i=i, j=j, k=k,
                    vertexcolor=vertexcolor,
                    colorscale=colorscale,
                    showscale=True) # This does NOT display the colorbar

Does this make sense? Do you know if it is possible to do something like this?

If not, I will think a little bit more about how I could compute intensity values from my two input surfaces and color maps.

@NicolasGensollen
vertexcolor is a list of color codes, not a list of values to be mapped to a colorscale. Thatโ€™s why colorscale and showscale=True, are inactive when you are setting vertexcolor.

Since you did not provide any data to see exactly how you associate the color codes to your vertices, I can only suppose that if at a vertex is measured some value you are assigning some color to that vertex. If this is the case, then you can add a dummy trace to your mesh3d, as follows:

  • define a scatter3d trace, with x, y, z as lists of point coordinates associated to vertices to be colored. Its definition should be as follows:
fig.add_scatter3d(x =[....], y=[...], z=[...], mode = 'markers',
                           marker=dict(size=0.01, 
                                       color=[list of values of the same length as x, y, or z],
                                       colorscale="your colorscale",   
                                       showscale=True, 
                                       colorbar_thickness=23)))

The small marker size makes the markers invisible, but the new trace adds a colorbar to your figure.

In order to get an informative colorbar you should control the correspondence between vertex color in mesh3d definition and color list of values associated to these vertices in scatter3d.