Pre-defined range buttons

How can I set rangeselector() buttons to zoom in on pre-defined date ranges for a time series plot? For example, I’m looking at stock market data for 2020 YTD, and I’d like to have two buttons “The Bull Run” and “the Crash”, which refer to the datetime ranege Bullrun=[2020-01-03 to 2020-02-19] and Crash=[2020-02-20 - 2020-05-06], and when I click on those buttons (instead of it being say “Last 6mo” or “YTD”), i want the plot to zoom in on those time periods specifically. Thank you.

Hi @tjf2007 welcome to the forum! For this you can use a normal layout button which modifies the xaxis range, like in the example below. For more details please refer to the tutorial on layout buttons

import plotly.graph_objects as go

import pandas as pd

# Load data
df = pd.read_csv(
    "https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv")
df.columns = [col.replace("AAPL.", "") for col in df.columns]

# Create figure
fig = go.Figure()

fig.add_trace(
    go.Scatter(x=list(df.Date), y=list(df.High)))

# Set title
fig.update_layout(
    title_text="Time series with range slider and selectors"
)

# Add range slider
fig.update_layout(
    xaxis=dict(
       
        rangeslider=dict(
            visible=True
        ),
        type="date",
        range=('2015-04-01', '2017-01-01')
    )
)
fig.update_layout(
    updatemenus=[
        dict(
            type="buttons",
            buttons=[
                dict(label="Custom",
                     method="relayout",
                     args=["xaxis", {'range':('2015-07-01', '2015-09-01'),
                                    'rangeslider':dict(visible=True),}]),]
        )]
)
fig.show()

Note that with the button your modifying all xaxis attributes so if you want some of them to persist (as with the rangeslider) you need to pass them along in the args.

1 Like

In fact a simpler syntax is to pass directly xaxis.range in the args as in

import plotly.graph_objects as go

import pandas as pd

# Load data
df = pd.read_csv(
    "https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv")
df.columns = [col.replace("AAPL.", "") for col in df.columns]

# Create figure
fig = go.Figure()

fig.add_trace(
    go.Scatter(x=list(df.Date), y=list(df.High)))

# Set title
fig.update_layout(
    title_text="Time series with range slider and selectors"
)

# Add range slider
fig.update_layout(
    xaxis=dict(
       
        rangeslider=dict(
            visible=True
        ),
        type="date",
        range=('2015-04-01', '2017-01-01')
    )
)
fig.update_layout(
    updatemenus=[
        dict(
            type="buttons",
            buttons=[
                dict(label="Custom",
                     method="relayout",
                     args=["xaxis.range", ('2015-07-01', '2015-09-01'),]),]
        )]
)
fig.show()
1 Like

I’m working on something similar, where I want to add a button that toggles on/off my hard-coded ylimits. In particular, I want args2 to revert the y range back to what was automatically set by plotly (based off the data). I found some odd behavior (and a toggle solution) that I wanted to document here in case it helps others.

My first attempt overwrote other aspects of the axis since I was setting the whole dictionary (like Emmanuelle mentions). This wasn’t the desired behavior; however, args2 (the second click on the button) successfully resets the axis to the original range ~(0, 100).

import pandas as pd
import numpy as np
import plotly.express as px

# Create Dataframe and Figure
y = list(np.random.randint(0, 10, size=49)) + [100]
x = list(range(0,50))
df = pd.DataFrame(index=x, data=y)
fig = px.line(df)
# Create Button
yrange = [0, 11]
buttons = [dict(args=["yaxis", {"range": yrange}],
                args2=["yaxis", {"range": 'auto'}],
                label="Toggle Y range",
                method='relayout')]
# Create menu and update layout
um = [dict(buttons=buttons, type='buttons', active=-1)]
fig.update_layout(updatemenus=um)
fig.show()

My second attempt - after seeing this thread - used “yaxis.range” to maintain all other aspects of the yaxis. My new button code was:

buttons = [dict(args=["yaxis.range", yrange],
                args2=["yaxis.range", 'auto'],
                label="Toggle Y range",
                method='relayout')]

This however did not revert the y-axis to (0, 100), but instead changed it to ~(-1, 4) on the second click (aka using args2). I had guessed on the “auto” keyword, and assumed it was correct since the first method of overwriting the dictionary worked. However, in the documentation, I didn’t find “auto” as an option. Note: the -1, 4 is also the default y limits with an empty Figure.

In my 3rd attempt, I set args2 to update yaxis.autorange (which I was hoping would override the range). It worked as desired; here’s the full example code for toggling a hard-coded y limit:

import pandas as pd
import numpy as np
import plotly.express as px

# Create Dataframe and Figure
y = list(np.random.randint(0, 10, size=49)) + [100]
x = list(range(0,50))
df = pd.DataFrame(index=x, data=y)
fig = px.line(df)
# Create Button
yrange = [0, 11]
# Method 3: Doesn't reset the range, but rather sets autorange to True
buttons = [dict(args=["yaxis.range", yrange],
                args2=["yaxis.autorange", True],
                label="Toggle Y range",
                method='relayout')]
# Create menu and update layout
um = [dict(buttons=buttons, type='buttons', active=-1)]
fig.update_layout(updatemenus=um)
fig.show()

I’m guessing that “auto” is an invalid value for yaxis.range. I’d love to understand why one method fell back to (essentially) autorange=True, and the other method fell back to (hard-coded?) default of (-1,4).