Search code examples
pythonplotly-pythonplotly-express

Using plotly express to show image and plot with animation


I need some help making an animation with plotly express where each frame will include an image and a graph (preferably a plotly express graph) side by side. My goal is to have the animation be corresponding to time steps from each frame. Plotly express has an example of this with just images shown in the link below. But I do not know how to make a plotly express graph take the place of one of the images in the example.

The link below will lead you to the plotly express example for "Combining animations and facets"

Link to plotly for specific example: 'Combining animations and facets' (https://plotly.com/python/imshow/)

'''

from skimage import data, io
import plotly.express as px
data = io.imread("https://github.com/scikit-image/skimage-tutorials/raw/main/images/cells.tif")
data = data.reshape((15, 4, 256, 256))[5:]
fig = px.imshow(data, animation_frame=0, facet_col=1, binary_string=True)
fig.show()

'''

Update:

So I can make side my side plots with images but I'm having a difficult time with animating it. Below is my current code:

'''

imgR=np.random.rand(360,1000)
imgR2=np.random.rand(360,1000)
      
fig = make_subplots(rows=1, cols=2)

fig.add_trace(
    go.Scatter(x=[1, 2, 3,4,5], y=[4, 5, 6,7,8]),
    row=1, col=1
)

fig.add_trace(
    px.imshow(imgR).data[0],
    row=1, col=2
)
frames=[go.Frame(data=[go.Scatter(x=[3,5,2,5,3],y=[3,4,5,3,3]),px.imshow(imgR2).data[0]],traces=[0,1])]

fig.frames=frames
                 
button = dict(
             label='Play',
             method='animate',
             args=[None, dict(frame=dict(duration=50, redraw=False), 
                              transition=dict(duration=0),
                              fromcurrent=True,
                              mode='immediate')])

fig.update_layout(updatemenus=[dict(type='buttons',
                              showactive=False,
                              y=0,
                              x=1.05,
                              xanchor='left',
                              yanchor='bottom',
                              buttons=[button] )
                                      ],
                 width=800, height=500)
fig.update_layout(height=600, width=800, title_text="Side By Side Subplots")

fig.show()

'''

Any help will be appreciated.


Solution

  • There are a number of things you need to be systematic with

    1. make sure each frame has a name
    2. make sure each trace is using correct axes
    3. build sliders from list of frames
    from plotly.subplots import make_subplots
    import plotly.graph_objects as go
    import plotly.express as px
    import pandas as pd
    import numpy as np
    
    imgR = np.random.rand(20, 40)
    
    fig = make_subplots(rows=1, cols=2)
    x = [1, 2, 3, 4, 5]
    y = [4, 5, 6, 7, 8]
    
    fig.add_trace(go.Scatter(x=[1, 2, 3, 4, 5], y=[4, 5, 6, 7, 8]), row=1, col=1)
    fig.add_trace(px.imshow(imgR).data[0], row=1, col=2)
    
    frames = []
    for i in range(5):
        if i > 0:
            np.random.shuffle(x)
            np.random.shuffle(y)
        # need to name the frame for slider, plus make sure both traces are using
        # correct axes
        frames.append(
            go.Frame(
                name=str(i),
                data=[
                    go.Scatter(x=x, y=y),
                    px.imshow(np.random.rand(20, 40) if i > 0 else imgR)
                    .update_traces(xaxis="x2", yaxis="y2")
                    .data[0],
                ],
            )
        )
    
    # now have all parts to puild figure
    figa = go.Figure(data=fig.data, frames=frames, layout=fig.layout)
    
    # add slider
    figa.update_layout(
        sliders=[
            {
                "active": 0,
                "currentvalue": {"prefix": "animation_frame="},
                "len": 0.9,
                "steps": [
                    {
                        "args": [
                            [fr.name],
                            {
                                "frame": {"duration": 0, "redraw": True},
                                "mode": "immediate",
                                "fromcurrent": True,
                            },
                        ],
                        "label": fr.name,
                        "method": "animate",
                    }
                    for fr in figa.frames
                ],
            }
        ],
    )