|
11 | 11 |
|
12 | 12 | """ |
13 | 13 |
|
| 14 | +import dash |
14 | 15 | import numpy as np |
15 | 16 | import plotly.graph_objects as go |
16 | | -import dash |
17 | 17 | from dash import Input, Output, State, callback_context, dcc, html, no_update |
18 | 18 | from dash_extensions.enrich import DashProxy, Serverside, ServersideOutputTransform |
19 | | -from trace_updater import TraceUpdater |
20 | 19 |
|
21 | 20 | # The overview figure requires clientside callbacks, whose JavaScript code is located |
22 | 21 | # in the assets folder. We need to tell dash where to find this folder. |
23 | | -from plotly_resampler import FigureResampler, ASSETS_FOLDER |
| 22 | +from plotly_resampler import ASSETS_FOLDER, FigureResampler |
24 | 23 |
|
25 | 24 | # -------------------------------- Data and constants --------------------------------- |
26 | 25 | # Data that will be used for the plotly-resampler figures |
|
31 | 30 | GRAPH_ID = "graph-id" |
32 | 31 | OVERVIEW_GRAPH_ID = "overview-graph" |
33 | 32 | STORE_ID = "store" |
34 | | -TRACEUPDATER_ID = "traceupdater" |
35 | 33 |
|
36 | 34 |
|
37 | 35 | # --------------------------------------Globals --------------------------------------- |
38 | | -# Remark how the assests folder is passed to the Dash(proxy) application |
| 36 | +# NOTE: Remark how the assests folder is passed to the Dash(proxy) application and how |
| 37 | +# the lodash script is included as an external script. |
39 | 38 | app = DashProxy( |
40 | | - __name__, transforms=[ServersideOutputTransform()], assets_folder=ASSETS_FOLDER |
| 39 | + __name__, |
| 40 | + transforms=[ServersideOutputTransform()], |
| 41 | + assets_folder=ASSETS_FOLDER, |
| 42 | + external_scripts=["https://cdn.jsdelivr.net/npm/lodash/lodash.min.js"], |
41 | 43 | ) |
42 | 44 |
|
43 | 45 | app.layout = html.Div( |
44 | 46 | [ |
45 | 47 | html.H1("plotly-resampler + dash-extensions", style={"textAlign": "center"}), |
46 | 48 | html.Button("plot chart", id="plot-button", n_clicks=0), |
47 | 49 | html.Hr(), |
48 | | - # The graph and its needed components to serialize and update efficiently |
49 | | - # Note: we also add a dcc.Store component, which will be used to link the |
50 | | - # server side cached FigureResampler object |
| 50 | + # The graph, overview graph, and servside store for the FigureResampler graph |
51 | 51 | dcc.Graph(id=GRAPH_ID), |
52 | 52 | dcc.Graph(id=OVERVIEW_GRAPH_ID), |
53 | 53 | dcc.Loading(dcc.Store(id=STORE_ID)), |
54 | | - TraceUpdater(id=TRACEUPDATER_ID, gdID=GRAPH_ID), |
55 | 54 | ] |
56 | 55 | ) |
57 | 56 |
|
@@ -104,19 +103,22 @@ def plot_graph(_): |
104 | 103 | ) |
105 | 104 |
|
106 | 105 |
|
107 | | -# --- FigureResampler update logic --- |
| 106 | +# --- FigureResampler update callback --- |
| 107 | + |
| 108 | +# The plotly-resampler callback to update the graph after a relayout event (= zoom/pan) |
| 109 | +# As we use the figure again as output, we need to set: allow_duplicate=True |
108 | 110 | @app.callback( |
109 | | - Output(TRACEUPDATER_ID, "updateData"), |
| 111 | + Output(GRAPH_ID, "figure", allow_duplicate=True), |
110 | 112 | Input(GRAPH_ID, "relayoutData"), |
111 | 113 | State(STORE_ID, "data"), # The server side cached FigureResampler per session |
112 | 114 | prevent_initial_call=True, |
113 | 115 | ) |
114 | | -def update_fig(relayoutdata, fig): |
| 116 | +def update_fig(relayoutdata: dict, fig: FigureResampler): |
115 | 117 | if fig is None: |
116 | 118 | return no_update |
117 | | - return fig.construct_update_data(relayoutdata) |
| 119 | + return fig.construct_update_data_patch(relayoutdata) |
118 | 120 |
|
119 | 121 |
|
120 | 122 | # --------------------------------- Running the app --------------------------------- |
121 | 123 | if __name__ == "__main__": |
122 | | - app.run_server(debug=False, port=9023, use_reloader=False) |
| 124 | + app.run_server(debug=True, port=9023, use_reloader=False) |
0 commit comments