Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple imshow on the same plot, with opacity slider

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()
like image 803
Basj Avatar asked Oct 22 '25 08:10

Basj


1 Answers

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

enter image description here

like image 147
Phoenix Avatar answered Oct 23 '25 23:10

Phoenix



Donate For Us

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