plotly / plotly.py

The interactive graphing library for Python :sparkles: This project now includes Plotly Express!
https://plotly.com/python/
MIT License
15.62k stars 2.51k forks source link

layout.on_change is not triggered when a plotly figure is zoomed in when the figure is viewed with fig.show() or streamlit.plotly_figure(fig) #4634

Closed s-baumann closed 2 weeks ago

s-baumann commented 2 weeks ago

There is an example case for my issue here on stack overflow. The solution of ericlavault is reproduced below:

import pandas as pd
import datetime as dt
import plotly.graph_objects as go
from IPython.display import display

returns = pd.DataFrame({
    'time': [dt.date(2020, 1, 1), dt.date(2020, 1, 2), dt.date(2020, 1, 3), dt.date(2020, 1, 4), dt.date(2020, 1, 5), dt.date(2020, 1, 6)],
    'longs': [0, 1, 2, 3, 4, 3],
    'shorts': [0, -1, -2, -3, -4, -4]
})

returns['time'] = returns['time'].astype(str)

def renormalise_returns(returns, renorm_date):
    long_data = returns.melt(id_vars = ['time'])
    long_data.sort_values(by = 'time', inplace=True)
    cum_at_start = long_data[long_data['time'] >= renorm_date].groupby(['variable']).first().reset_index().rename(columns = {'value': 'old_value'}).drop(columns = ['time'])
    long_data2 = pd.merge(long_data, cum_at_start, how = 'left', on = ['variable'])
    long_data2['value'] = long_data2['value'] - long_data2['old_value']
    long_data2.drop(columns = ['old_value'], inplace=True)
    finn = long_data2.pivot(index = ['time'], columns = ['variable'], values = 'value').reset_index()
    return finn

fig = go.FigureWidget([
    go.Scatter(x=returns['time'], y=returns['longs'], name='Longs', line=dict(color="#0c56cc")),
    go.Scatter(x=returns['time'], y=returns['shorts'], name="Shorts", line=dict(color="#850411", dash="dash"))
])

def zoom(layout, xrange):
    xrange_zoom_min, xrange_zoom_max = xrange
    df2 = renormalise_returns(returns, xrange_zoom_min)
    fig.update_traces(selector=dict(name='Longs'), x=df2['time'], y=df2['longs'])
    fig.update_traces(selector=dict(name='Shorts'), x=df2['time'], y=df2['shorts'])

fig.layout.on_change(zoom, 'xaxis.range')

display(fig)

This does work in that if you run this in an ipython notebook then you will see a chart. If you zoom in on that chart then the zoom function above is triggered.

If you instead use fig.show() or streamlit.plotly_figure(fig) however the zoom function is never triggered.

s-baumann commented 2 weeks ago

Close as this appears to be beyond the capabilities of these output channels as there is no process running that can perform updates to the data.