With Plotly, I'd like to display two imshow on the same page, at the same place, with opacity.
This nearly works:
import plotly.express as px, numpy as np
from skimage import io
img = io.imread('https://upload.wikimedia.org/wikipedia/commons/thumb/0/00/Crab_Nebula.jpg/240px-Crab_Nebula.jpg')
fig = px.imshow(img)
x = np.random.random((100, 200))
fig2 = px.imshow(x)
fig.show()
fig2.show()
but it displays the two imshow images in two different tabs.
How to display the two "imshow" on the same plot, with an opacity slider for both layers?
For reference, here is the matplotlib equivalent:
import numpy as np, matplotlib.pyplot as plt, matplotlib.widgets as mpwidgets, scipy.misc
x = scipy.misc.face(gray=False) # shape (768, 1024, 3)
y = np.random.random((100, 133)) # shape (100, 133)
fig, (ax0, ax1) = plt.subplots(2, 1, gridspec_kw={'height_ratios': [5, 1]})
OPACITY = 0.5
img0 = ax0.imshow(x, cmap="jet")
img1 = ax0.imshow(y, cmap="jet", alpha=OPACITY, extent=img0.get_extent())
slider0 = mpwidgets.Slider(ax=ax1, label='opacity', valmin=0, valmax=1, valinit=OPACITY)
slider0.on_changed(lambda value: img1.set_alpha(value))
plt.show()
The main problem is that pre-computing all traces is an essential step to create the layer.Slider in Plotly as documented here. Therefore, we want to compute the only required trace on the fly rather than pre-computing all traces upfront. Moreover, I totally agree with you that it is ineffective solution to build all traces in advanced on the user machine because this will take long time and consume huge amount of memory, especially if the image has large size.
From my perspective, I see the best option is to use both Plotly and ipywidgets and doing this will save much more time and memory in compared to the first option. In the solution below, I update the only trace with the selected opacity by the user interactively.
Full Code
import plotly.express as px
import plotly.graph_objects as go
from skimage import io
import numpy as np
from PIL import Image
from ipywidgets import FloatSlider, VBox
img = io.imread("https://images.unsplash.com/photo-1543349689-9a4d426bee8e?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=801&q=80")
noise = np.random.random(img.shape[:2])
fig = go.FigureWidget(px.imshow(img))
fig.add_trace(go.Heatmap(z=noise, opacity=0.0,
showscale=False, colorscale ="Greys",
name = "noise"))
def update(value):
fig.update_traces(opacity=value["new"],selector=({'name':'noise'}))
Opacity_slider = FloatSlider(value=0.0,min=0.0,max=1.0,
step=0.1, description='Opacity:')
Opacity_slider.observe(update, names="value")
vb = VBox((fig, Opacity_slider))
vb.layout.align_items = 'center'
display(vb)
Output

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With