11
11
__author__ = "Jonas Van Der Donckt, Jeroen Van Der Donckt, Emiel Deprost"
12
12
13
13
import warnings
14
- from typing import Tuple
14
+ from typing import Tuple , List
15
15
16
16
import dash
17
17
import plotly .graph_objects as go
@@ -41,26 +41,98 @@ def __init__(
41
41
show_mean_aggregation_size : bool = True ,
42
42
convert_traces_kwargs : dict | None = None ,
43
43
verbose : bool = False ,
44
+ show_dash_kwargs : dict | None = None ,
44
45
):
46
+ """Initialize a dynamic aggregation data mirror using a dash web app.
47
+
48
+ Parameters
49
+ ----------
50
+ figure: BaseFigure
51
+ The figure that will be decorated. Can be either an empty figure
52
+ (e.g., ``go.Figure()``, ``make_subplots()``, ``go.FigureWidget``) or an
53
+ existing figure.
54
+ convert_existing_traces: bool
55
+ A bool indicating whether the high-frequency traces of the passed ``figure``
56
+ should be resampled, by default True. Hence, when set to False, the
57
+ high-frequency traces of the passed ``figure`` will not be resampled.
58
+ default_n_shown_samples: int, optional
59
+ The default number of samples that will be shown for each trace,
60
+ by default 1000.\n
61
+ .. note::
62
+ * This can be overridden within the :func:`add_trace` method.
63
+ * If a trace withholds fewer datapoints than this parameter,
64
+ the data will *not* be aggregated.
65
+ default_downsampler: AbstractSeriesDownsampler
66
+ An instance which implements the AbstractSeriesDownsampler interface and
67
+ will be used as default downsampler, by default ``EfficientLTTB`` with
68
+ _interleave_gaps_ set to True. \n
69
+ .. note:: This can be overridden within the :func:`add_trace` method.
70
+ resampled_trace_prefix_suffix: str, optional
71
+ A tuple which contains the ``prefix`` and ``suffix``, respectively, which
72
+ will be added to the trace its legend-name when a resampled version of the
73
+ trace is shown. By default a bold, orange ``[R]`` is shown as prefix
74
+ (no suffix is shown).
75
+ show_mean_aggregation_size: bool, optional
76
+ Whether the mean aggregation bin size will be added as a suffix to the trace
77
+ its legend-name, by default True.
78
+ convert_traces_kwargs: dict, optional
79
+ A dict of kwargs that will be passed to the :func:`add_traces` method and
80
+ will be used to convert the existing traces. \n
81
+ .. note::
82
+ This argument is only used when the passed ``figure`` contains data and
83
+ ``convert_existing_traces`` is set to True.
84
+ verbose: bool, optional
85
+ Whether some verbose messages will be printed or not, by default False.
86
+ show_dash_kwargs: dict, optional
87
+ A dict that will be used as default kwargs for the :func:`show_dash` method.
88
+ Note that the passed kwargs will be take precedence over these defaults.
89
+
90
+ """
45
91
# Parse the figure input before calling `super`
46
- if is_figure (figure ) and not is_fr (figure ): # go.Figure
47
- # Base case, the figure does not need to be adjusted
92
+ if is_figure (figure ) and not is_fr (figure ):
93
+ # A go.Figure
94
+ # => base case: the figure does not need to be adjusted
48
95
f = figure
49
96
else :
50
97
# Create a new figure object and make sure that the trace uid will not get
51
98
# adjusted when they are added.
52
99
f = self ._get_figure_class (go .Figure )()
53
100
f ._data_validator .set_uid = False
54
101
55
- if isinstance (figure , BaseFigure ): # go.FigureWidget or AbstractFigureAggregator
56
- # A base figure object, we first copy the layout and grid ref
102
+ if isinstance (figure , BaseFigure ):
103
+ # A base figure object, can be;
104
+ # - a go.FigureWidget
105
+ # - a plotly-resampler figure: subclass of AbstractFigureAggregator
106
+ # => we first copy the layout, grid_str and grid ref
57
107
f .layout = figure .layout
108
+ f ._grid_str = figure ._grid_str
58
109
f ._grid_ref = figure ._grid_ref
59
110
f .add_traces (figure .data )
111
+ elif isinstance (figure , dict ) and (
112
+ "data" in figure or "layout" in figure # or "frames" in figure # TODO
113
+ ):
114
+ # A figure as a dict, can be;
115
+ # - a plotly figure as a dict (after calling `fig.to_dict()`)
116
+ # - a pickled (plotly-resampler) figure (after loading a pickled figure)
117
+ # => we first copy the layout, grid_str and grid ref
118
+ f .layout = figure .get ("layout" )
119
+ f ._grid_str = figure .get ("_grid_str" )
120
+ f ._grid_ref = figure .get ("_grid_ref" )
121
+ f .add_traces (figure .get ("data" ))
122
+ # `pr_props` is not None when loading a pickled plotly-resampler figure
123
+ f ._pr_props = figure .get ("pr_props" )
124
+ # `f._pr_props`` is an attribute to store properties of a
125
+ # plotly-resampler figure. This attribute is only used to pass
126
+ # information to the super() constructor. Once the super constructor is
127
+ # called, the attribute is removed.
128
+
129
+ # f.add_frames(figure.get("frames")) TODO
60
130
elif isinstance (figure , (dict , list )):
61
131
# A single trace dict or a list of traces
62
132
f .add_traces (figure )
63
133
134
+ self ._show_dash_kwargs = show_dash_kwargs if show_dash_kwargs is not None else {}
135
+
64
136
super ().__init__ (
65
137
f ,
66
138
convert_existing_traces ,
@@ -129,7 +201,9 @@ def show_dash(
129
201
``config`` parameter for this property in this method.
130
202
See more https://dash.plotly.com/dash-core-components/graph
131
203
**kwargs: dict
132
- Additional app.run_server() kwargs. e.g.: port
204
+ Additional app.run_server() kwargs. e.g.: port, ...
205
+ Also note that these kwargs take precedence over the ones passed to the
206
+ constructor via the ``show_dash_kwargs`` argument.
133
207
134
208
"""
135
209
graph_properties = {} if graph_properties is None else graph_properties
@@ -150,14 +224,19 @@ def show_dash(
150
224
151
225
# 2. Run the app
152
226
if (
153
- self .layout .height is not None
154
- and mode == "inline"
227
+ mode == "inline"
155
228
and "height" not in kwargs
156
229
):
157
- # If figure height is specified -> re-use is for inline dash app height
158
- kwargs ["height" ] = self .layout .height + 18
230
+ # If app height is not specified -> re-use figure height for inline dash app
231
+ # Note: default layout height is 450 (whereas default app height is 650)
232
+ # See: https://plotly.com/python/reference/layout/#layout-height
233
+ fig_height = self .layout .height if self .layout .height is not None else 450
234
+ kwargs ["height" ] = fig_height + 18
235
+
236
+ # kwargs take precedence over the show_dash_kwargs
237
+ kwargs = {** self ._show_dash_kwargs , ** kwargs }
159
238
160
- # store the app information, so it can be killed
239
+ # Store the app information, so it can be killed
161
240
self ._app = app
162
241
self ._host = kwargs .get ("host" , "127.0.0.1" )
163
242
self ._port = kwargs .get ("port" , "8050" )
@@ -213,3 +292,11 @@ def register_update_graph_callback(
213
292
dash .dependencies .Input (graph_id , "relayoutData" ),
214
293
prevent_initial_call = True ,
215
294
)(self .construct_update_data )
295
+
296
+ def _get_pr_props_keys (self ) -> List [str ]:
297
+ # Add the additional plotly-resampler properties of this class
298
+ return super ()._get_pr_props_keys () + ["_show_dash_kwargs" ]
299
+
300
+ def _ipython_display_ (self ):
301
+ # To display the figure inline as a dash app
302
+ self .show_dash (mode = "inline" )
0 commit comments