Home > other >  Is there a way to dynamically change a plotly animation axis scale per frame?
Is there a way to dynamically change a plotly animation axis scale per frame?

Time:10-16

I have an animated plotly scatter graph which plots x,y coordinates normally within the 0-0.5 range with date/time being the frame key. Sometime however I will have to handle anomalous data points which will be well out with this range. I would like the graph to be able to dynamically scale so that the points are not lost off screen. Is this possible?

def draw(x1,y1,timestamp):

    d = {
        "x1": x1_trim,
        "y1": y1_trim,
        "time": time_trim
    }
    
    df = pd.DataFrame(d)
  
    fig = px.scatter(df, x="x1", y="y1", animation_frame="time")
    fig.update_yaxes(autorange=True)
    fig.update_xaxes(autorange=True)
    fig.show()

I've tried using update_x/yaxes with autorange but it doesn't seem to work.

CodePudding user response:

As pointed out in the comments, there is a way to change a plotly animation axis scale per frame. The question remains how dynamic it's possible to make it. But if we can say that you've made a few calculations that will let you know which frames you'd like to adjust the ranges for, then a combination of a dict like yranges = {2002:[0, 200]} and a for-loop on the frames should do the trick. Let's take a subset of the dataset px.data.gapminder as an example. And let's say that you'd like to adjust the range of the yaxis for the frame that displays data for the year 2002 in the following figure:

enter image description here

Then you can include the following snippet, and get the figure below for year = 2002:

yranges = {2002:[0, 200]}
for f in fig.frames:
    if int(f.name) in yranges.keys():
        f.layout.update(yaxis_range = yranges[int(f.name)])

enter image description here

Complete code:

import plotly.express as px
df = px.data.gapminder()
df = df[(df['continent'] == 'Asia') & (df['year'].isin([1997, 2002, 2007]))]

scales = [2002]

fig = px.scatter(df, x="gdpPercap", y="lifeExp", animation_frame="year", animation_group="country",
           size="pop", color="continent", hover_name="country",
           log_x=True, size_max=55, range_x=[100,100000], range_y=[25,90])

yranges = {2002:[0, 200]}

for f in fig.frames:
    if int(f.name) in yranges.keys():
        f.layout.update(yaxis_range = yranges[int(f.name)])

fig.show()

CodePudding user response:

  • each frame can have it's own layout
  • after constructing figure, loop over frames and define x & y axis range
  • code below
import pandas as pd
import numpy as np
import plotly.express as px
import plotly.graph_objects as go

df = pd.DataFrame(
    {
        "time": np.tile(pd.date_range("1-jan-2021", freq="1H", periods=12), 10),
        "x": np.random.uniform(1, 4, 120),
        "y": np.random.uniform(2, 5, 120),
    }
)
fig = px.scatter(df, x="x", y="y", animation_frame=df["time"].dt.strftime("%H:%M"))

go.Figure(
    data=fig.data,
    frames=[
        fr.update(
            layout={
                "xaxis": {"range": [min(fr.data[0].x) - 0.1, max(fr.data[0].x)   0.1]},
                "yaxis": {"range": [min(fr.data[0].y) - 0.1, max(fr.data[0].y)   0.1]},
            }
        )
        for fr in fig.frames
    ],
    layout=fig.layout,
)
  • Related