Search code examples
pythonanimationplotlysliderheatmap

Plotly with python: how to plot two heatmaps using frames and slider?


I need help creating a composite animated plotly chart in python.

The static version of such chart would be something like this Double static chart, which is done with the following code in python:

def double_hm_plot(vec1, vec2):
    fig = plotly.subplots.make_subplots(rows=1, cols=2, shared_yaxes=True, shared_xaxes=True)
    fig.add_trace(go.Heatmap(z=vec1.T, coloraxis='coloraxis1'), row=1, col=1)
    fig.add_trace(go.Heatmap(z=vec2.T, coloraxis='coloraxis2'), row=1, col=2)
    fig.update_layout(
        legend=dict(x=0.5, xanchor='center', y=1, yanchor='bottom', orientation='h'),
        coloraxis1=dict(colorscale='jet', colorbar_x=-0.20, colorbar_thickness=10),
        coloraxis2=dict(colorscale='jet', colorbar_x=1.00, colorbar_thickness=10),
        width=600, height=700)
    fig.show()

double_hm_plot(files['gas'][-1], files['solid'][-1])

The code takes two numpy arrays with two dimensions (arrays of arrays, not matrices) which contain null values and plot them as heatmaps. Relatively simple, and the coloraxis lines are just for placing the colorscales bars correctly.

I was able to make the only half of the dynamic/animated chart which I need, with only one of the heatmaps shown in "double_hm_plot", using a slider such as follows: (results: Single dynamic chart)

structure = files['gas'][1:]
min_scale, max_scale = np.min(np.min(np.min(structure))), np.max(np.max(np.max(structure)))
frames = [go.Frame(data=go.Heatmap(z=frame.T, colorscale='Turbo', 
                                   zauto=False,
                                   zmin=min_scale, zmax=max_scale
                                   ), name=i) for i, frame in enumerate(structure)]

go.Figure(data=frames[0].data, frames=frames).update_layout(
    sliders=[{"steps": [{"args":[[f.name],{"frame": {"duration": 0, "redraw": True}, "mode": "immediate",},],
                         "label":f.name, "method": "animate",}
                        for f in frames],}],
    height=600, width=300,
    yaxis={"title": 'y [m/10]'},
    xaxis={"title": 'r [m/10]', 'side': 'top'},
    title_x=0.5,
)

This second code works with one more dimension for time, and plots roughly the same way.

How could i use two side by side plots (such as in "double_hm_plot") with this slider?

I've tried a lot of things and nothing seems to work. Things like: composing frames with multiple "go.heatmap" objects, using multiple frames in the figure etc.

On the documentations I did not find much help also.

Is there any help, is this even possible?

Files for example testing: https://drive.google.com/drive/folders/1Vpt_HfJxCsYoghvwerzfHEpJAq6MJHE1?usp=share_link

EDIT:

Data loading:

# Processed loading
files = {
    'gas': np.load('gas.npy'), #insert here the path on your OS
    'solid': np.load('solid.npy')
}

Solution

  • I found an example of using a slider on a subplot of a line chart in the plotly community, so I created a subplot with a slider from your data based on it. The point is that since it is two subplots, the units that control what is displayed are also two each. The list that controls which to show and hide slides by 2 true units each. 500 graphs would also require a lot of CPU power to run, so I've made it 50 graphs.

    import numpy as np
    import plotly.subplots
    import plotly.graph_objects as go
    from plotly.subplots import make_subplots
    
    # Processed loading
    files = {
        'gas': np.load('./data/gas.npy'), #insert here the path on your OS
        'solid': np.load('./data/solid.npy')
    }
    
    vec1 = files['gas'][::10]
    vec2 = files['solid'][::10]
    
    fig = make_subplots(rows=1, cols=2, shared_yaxes=True, shared_xaxes=True)
    
    for step in range(len(vec1)):
        fig.append_trace(
            go.Heatmap(
                z=vec1[step].T,
                name=str(step),
                visible=False,
                zauto=False,
                colorscale='jet',
                coloraxis='coloraxis1'
            ),row=1, col=1)
        
        fig.append_trace(
            go.Heatmap(
                z=vec2[step].T,
                name=str(step),
                visible=False,
                zauto=False,
                colorscale='jet',
                coloraxis='coloraxis2'
            ),row=1, col=2)
        
    steps = []
    
    for i in range(0, len(fig.data), 2):
        step = dict(
            method="restyle",
            args=["visible", [False] * len(fig.data)],
        )
        step["args"][1][i:i+2] = [True, True]
        steps.append(step)
    
    sliders = [dict(
        active=0,
        currentvalue={"prefix": "index:"},
        pad={"t": 50},
        steps=steps
    )]
    
    fig.update_layout(sliders=sliders, template ="plotly_white")
    
    fig.update_layout(
            legend=dict(x=0.5, xanchor='center', y=1, yanchor='bottom', orientation='h'),
            coloraxis1=dict(colorscale='jet', colorbar_x=-0.3, colorbar_thickness=10),
            coloraxis2=dict(colorscale='jet', colorbar_x=1.00, colorbar_thickness=10),
            width=600, height=700)
    fig.update_layout(
        yaxis={"title": 'y [m/10]'},
        xaxis={"title": 'r [m/10]', 'side': 'bottom'},
        title_x=0.5,
    )
    
    fig.update_layout(width=600,height=700)
    
    fig.show()
    

    enter image description here