plotly / plotly.py

The interactive graphing library for Python :sparkles: This project now includes Plotly Express!
https://plotly.com/python/
MIT License
16.11k stars 2.54k forks source link

3d Surface bug in Python? A custom colorscale defined with rgba values ignores the alpha specification #1859

Closed lucapinello closed 4 years ago

lucapinello commented 4 years ago

Hi There!

I am trying to create a surface with surfacecolor and a custom colorscale to set a per point transparency.

The global opacity is working well, however the per point opacity specified in a custom colorscale with the rga definitions are ignored.

This is what I am doing:

from skimage.draw import circle
import plotly.graph_objects as go
import pandas as pd
import numpy as np
%pylab inline

# Read data from a csv
z_data = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/api_docs/mt_bruno_elevation.csv')

#make a custom surfacecolor to color just the middle of the surface
surfacecolor = np.zeros((25, 25), dtype=np.uint8)
rr, cc = circle(12.5, 12.5, 5)
surfacecolor[rr, cc] = 1
plt.matshow(surfacecolor)

#simple colorscale from black to pure red
colorscale=[ 
        [0, "rgb(0, 0, 0)"],
        [1.0, "rgb(255, 0, 0)"]]

#Plotting a surface with the global opacity is working well!
fig = go.Figure(data=[go.Surface(z=z_data.values,opacity=0.8, surfacecolor=surfacecolor,colorscale=colorscale)])

fig.update_layout(title='Mt Bruno Elevation', autosize=False,
                  width=500, height=500,
                  margin=dict(l=65, r=50, b=65, t=90))

fig.show()

# Same as before but now we use rgba to set the transparency, black now should be full transparent
colorscale=[ 
        [0, "rgba(0, 0, 0,0)"],
        [1.0, "rgba(255, 0, 0,1)"]]

#per point opacity is broken :(
fig = go.Figure(data=[go.Surface(z=z_data.values,
                                 surfacecolor=surfacecolor,
                                 colorscale=colorscale)])

fig.update_layout(title='Mt Bruno Elevation', autosize=False,
                  width=500, height=500,
                  margin=dict(l=65, r=50, b=65, t=90))

fig.show()

#this is not working :(

I created a jupyter notebook so you can reproduce the error

lucapinello commented 4 years ago

3d-surface-plots.zip

lucapinello commented 4 years ago

This seems broken also in the javascript version. The colorbar shows the right transparency but the surface does not, I created a codepen here: https://codepen.io/lucapinello/pen/gOOoeRd

empet commented 4 years ago

@lucapinello Plotly doesn't work (and it has never worked ) with a colorscale having rgba colors in its definition. As you noticed it acccepts a rgba based colorscale, but retains only the rgb elements. The transparency is set only by the opacity value.

lucapinello commented 4 years ago

Wow thanks for the super quick reply!

Any hope this will be supported in the future? Or where to look to extend this function to propagate the transparency?

I am trying to overlay different surfaces (all identical) to color different regions of a single surface. Some regions may overlap so I was thinking to have some per point alpha to control this better. I tried the global opacity, unfortunately, it doesn't work well for this since the final result will depend on the plotting order.

Any other way to accomplish this?

Anyway thanks a lot for this amazing library!

empet commented 4 years ago

You can post a feature request on the plotly.js repo.

nicolaskruchten commented 4 years ago

Thanks for the feedback @lucapinello ! I've gone ahead and created https://github.com/plotly/plotly.js/issues/4331 to track this request, as it would have to be implemented in the JS layer first before being available in the Python layer of the Plotly stack :)

lucapinello commented 4 years ago

Yes, this makes perfect sense. Thank you so much @nicolaskruchten !