Skip to content

Commit 1e80f4e

Browse files
authored
Merge pull request #47 from predict-idlab/figurewidget
🌾 figurewidget support
2 parents 8810bd5 + 2ad0752 commit 1e80f4e

16 files changed

+3349
-413
lines changed

README.md

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
[![support-version](https://img.shields.io/pypi/pyversions/plotly-resampler)](https://img.shields.io/pypi/pyversions/plotly-resampler)
99
[![codecov](https://img.shields.io/codecov/c/github/predict-idlab/plotly-resampler?logo=codecov)](https://codecov.io/gh/predict-idlab/plotly-resampler)
1010
[![Code quality](https://img.shields.io/lgtm/grade/python/github/predict-idlab/plotly-resampler?label=code%20quality&logo=lgtm)](https://lgtm.com/projects/g/predict-idlab/plotly-resampler/context:python)
11+
[![Downloads](https://pepy.tech/badge/plotly-resampler)](https://pepy.tech/project/plotly-resampler)
1112
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?)](http://makeapullrequest.com)
1213
[![Documentation](https://github.com/predict-idlab/plotly-resampler/actions/workflows/deploy-docs.yml/badge.svg)](https://github.com/predict-idlab/plotly-resampler/actions/workflows/deploy-docs.yml)
1314
[![Testing](https://github.com/predict-idlab/plotly-resampler/actions/workflows/test.yml/badge.svg)](https://github.com/predict-idlab/plotly-resampler/actions/workflows/test.yml)
@@ -17,7 +18,7 @@
1718

1819
> `plotly_resampler`: visualize large sequential data by **adding resampling functionality to Plotly figures**
1920
20-
[Plotly](https://github.com/plotly/plotly.py) is an awesome interactive visualization library, however it can get pretty slow when a lot of data points are visualized (100 000+ datapoints). This library solves this by downsampling the data respective to the view and then plotting the downsampled points. When you interact with the plot (panning, zooming, ...), [dash](https://github.com/plotly/dash) callbacks are used to resample and redraw the figures.
21+
[Plotly](https://github.com/plotly/plotly.py) is an awesome interactive visualization library, however it can get pretty slow when a lot of data points are visualized (100 000+ datapoints). This library solves this by downsampling (aggregating) the data respective to the view and then plotting the aggregated points. When you interact with the plot (panning, zooming, ...), callbacks are used to aggregate data and update the figure.
2122

2223
<p align="center">
2324
<a href="#readme">
@@ -27,6 +28,10 @@
2728

2829
In [this Plotly-Resampler demo](https://github.com/predict-idlab/plotly-resampler/blob/main/examples/basic_example.ipynb) over `110,000,000` data points are visualized!
2930

31+
<!-- These dynamic aggregation callbacks are realized with: -->
32+
<!-- * [Dash](https://github.com/plotly/dash) when a `go.Figure` object is wrapped with dynamic aggregation functionality, see example ⬆️. -->
33+
<!-- * The [FigureWidget.layout.on_change](https://plotly.com/python-api-reference/generated/plotly.html?highlight=on_change#plotly.basedatatypes.BasePlotlyType.on_change) method, when a `go.FigureWidget` is used within a `.ipynb` environment. -->
34+
3035
<!-- #### Useful links -->
3136

3237
<!-- - [Documentation]() work in progress 🚧 -->
@@ -41,48 +46,66 @@ In [this Plotly-Resampler demo](https://github.com/predict-idlab/plotly-resample
4146

4247
## Usage
4348

44-
To **add dynamic resampling to your plotly Figure**, you should;
45-
1. wrap the plotly Figure with `FigureResampler`
46-
2. call `.show_dash()` on the Figure
49+
To **add dynamic resampling** to your plotly Figure
50+
* using a web application with *Dash* callbacks, you should;
51+
1. wrap the plotly Figure with `FigureResampler`
52+
2. call `.show_dash()` on the Figure
53+
* within a *jupyter* environment and *without creating a web application*, you should:
54+
1. wrap the plotly Figure with `FigureWidgetResampler`
55+
2. output the `FigureWidgetResampler` instance in a cell
4756

4857
> **Note**:
49-
> Any plotly Figure can be wrapped with FigureResampler! 🎉
58+
> Any plotly Figure can be wrapped with `FigureResampler` and `FigureWidgetResampler`! 🎉
5059
> But, (obviously) only the scatter traces will be resampled.
5160
5261
> **Tip** 💡:
53-
> For significant faster initial loading of the Figure, we advise to wrap the constructor of the plotly Figure with `FigureResampler` and add the trace data as `hf_x` and `hf_y`
62+
> For significant faster initial loading of the Figure, we advise to wrap the constructor of the plotly Figure and add the trace data as `hf_x` and `hf_y`
5463
5564
### Minimal example
5665

5766
```python
5867
import plotly.graph_objects as go; import numpy as np
59-
from plotly_resampler import FigureResampler
68+
from plotly_resampler import FigureResampler, FigureWidgetResampler
6069

6170
x = np.arange(1_000_000)
6271
noisy_sin = (3 + np.sin(x / 200) + np.random.randn(len(x)) / 10) * x / 1_000
6372

73+
# OPTION 1 - FigureResampler: dynamic aggregation via a Dash web-app
6474
fig = FigureResampler(go.Figure())
6575
fig.add_trace(go.Scattergl(name='noisy sine', showlegend=True), hf_x=x, hf_y=noisy_sin)
6676

6777
fig.show_dash(mode='inline')
6878
```
6979

80+
#### FigureWidgetResampler: dynamic aggregation via `FigureWidget.layout.on_change`
81+
```python
82+
...
83+
# OPTION 2 - FigureWidgetResampler: dynamic aggregation via `FigureWidget.layout.on_change`
84+
fig = FigureWidgetResampler(go.Figure())
85+
fig.add_trace(go.Scattergl(name='noisy sine', showlegend=True), hf_x=x, hf_y=noisy_sin)
86+
87+
fig
88+
```
89+
7090
### Features
7191

7292
* **Convenient** to use:
73-
* just add the `FigureResampler` decorator around a plotly Figure and call `.show_dash()`
93+
* just add either
94+
* `FigureResampler` decorator around a plotly Figure and call `.show_dash()`
95+
* `FigureWidgetResampler` decorator around a plotly Figure and output the instance in a cell
7496
* allows all other plotly figure construction flexibility to be used!
7597
* **Environment-independent**
7698
* can be used in Jupyter, vscode-notebooks, Pycharm-notebooks, Google Colab, and even as application (on a server)
77-
* Interface for **various downsampling algorithms**:
78-
* ability to define your preferred sequence aggregation method
99+
* Interface for **various aggregation algorithms**:
100+
* ability to develop or select your preferred sequence aggregation method
79101

80102

81103
### Important considerations & tips
82104

83-
* When running the code on a server, you should forward the port of the `FigureResampler.show_dash()` method to your local machine.
105+
* When running the code on a server, you should forward the port of the `FigureResampler.show_dash()` method to your local machine.<br>
106+
**Note** that you can add dynamic aggregation to plotly figures with the `FigureWidgetResampler` wrapper without needing to forward a port!
84107
* In general, when using downsampling one should be aware of (possible) [aliasing](https://en.wikipedia.org/wiki/Aliasing) effects.
85-
The <b><a style="color:orange">[R]</a></b> in the legend indicates when the corresponding trace is being resampled (and thus possibly distorted) or not.
108+
The <b><a style="color:orange">[R]</a></b> in the legend indicates when the corresponding trace is being resampled (and thus possibly distorted) or not. Additionally, the `~<range>` suffix represent the mean aggregation bin size in terms of the sequence index.
86109

87110
## Future work 🔨
88111

docs/sphinx/aggregation.rst

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
1-
-----------
2-
Aggregation
3-
-----------
1+
----------------------------
2+
Series-wise data aggregation
3+
----------------------------
44

5+
^^^^^^^^^^^^^^^^^^^^^
6+
Aggregation interface
7+
^^^^^^^^^^^^^^^^^^^^^
58

6-
^^^^^^^^^^^^^^^^^^
7-
Aggregator classes
8-
^^^^^^^^^^^^^^^^^^
9-
10-
.. automodule:: plotly_resampler.aggregation.aggregators
9+
.. automodule:: plotly_resampler.aggregation.aggregation_interface
1110
:members:
1211
:undoc-members:
1312
:show-inheritance:
1413

14+
----------
1515

16-
^^^^^^^^^^^^^^^^^^^^^
17-
Aggregation interface
18-
^^^^^^^^^^^^^^^^^^^^^
16+
^^^^^^^^^^^^^^^^^^
17+
Aggregator classes
18+
^^^^^^^^^^^^^^^^^^
1919

20-
.. automodule:: plotly_resampler.aggregation.aggregation_interface
20+
.. automodule:: plotly_resampler.aggregation.aggregators
2121
:members:
2222
:undoc-members:
23-
:show-inheritance:
23+
:show-inheritance:

docs/sphinx/figure_resampler.rst

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,28 @@
1-
----------------
1+
^^^^^^^^^^^^^^^^^^^^^^^^
2+
AbstractFigureAggregator
3+
^^^^^^^^^^^^^^^^^^^^^^^^
4+
5+
.. autoclass:: plotly_resampler.figure_resampler.figure_resampler_interface.AbstractFigureAggregator
6+
:members:
7+
:undoc-members:
8+
:show-inheritance:
9+
10+
^^^^^^^^^^^^^^^
211
FigureResampler
3-
----------------
12+
^^^^^^^^^^^^^^^
13+
14+
15+
.. autoclass:: plotly_resampler.figure_resampler.FigureResampler
16+
:members:
17+
:undoc-members:
18+
:show-inheritance:
19+
20+
21+
^^^^^^^^^^^^^^^^^^^^^
22+
FigureWidgetResampler
23+
^^^^^^^^^^^^^^^^^^^^^
424

5-
.. automodule:: plotly_resampler.figure_resampler
25+
.. autoclass:: plotly_resampler.figure_resampler.FigureWidgetResampler
626
:members:
727
:undoc-members:
828
:show-inheritance:

docs/sphinx/getting_started.rst

Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,45 +4,57 @@
44
Getting started 🚀
55
==================
66

7+
``plotly-resampler`` serves two main **modules**:
78

8-
``plotly-resampler`` maintains its interactiveness on large data by applying front-end
9-
**resampling**.
10-
11-
12-
Users can interact with 2 components:
13-
14-
* :ref:`FigureResampler <FigureResampler>`: a wrapper for *plotly.graph\_objects* that serves the adaptive resampling functionality.
15-
* :ref:`aggregation <aggregation>`: this module withholds various data aggregation methods.
9+
* :py:mod:`figure_resampler <plotly_resampler.figure_resampler>`: a wrapper for *plotly.graph\_objects Figures*, coupling the dynamic resampling functionality to the *Figure*.
10+
* :py:mod:`aggregation <plotly_resampler.aggregation>`: a module that withholds various data aggregation methods.
1611

1712
Installation ⚙️
1813
---------------
1914

20-
Install via :raw-html:`<a href="https://pypi.org/project/plotly-resampler/"><b>pip</b><a>`:
15+
Install via `pip <https://pypi.org/project/plotly-resampler>`_:
2116

2217
.. code:: bash
2318
2419
pip install plotly-resampler
2520
26-
2721
How to use 📈
2822
-------------
2923

30-
To **add dynamic resampling to a plotly Figure**, you should;
24+
Dynamic resampling callbacks are realized with either:
25+
26+
* `Dash <https://github.com/plotly/dash>`_ callbacks, when a ``go.Figure`` object is wrapped with dynamic aggregation functionality.
27+
28+
.. note::
29+
30+
This is especially useful when working with **dash functionality** or when you do **not want to solely operate in jupyter environments**.
31+
32+
To **add dynamic resampling**, you should:
33+
1. wrap the plotly Figure with :class:`FigureResampler <plotly_resampler.figure_resampler.FigureResampler>`
34+
2. call :func:`.show_dash() <plotly_resampler.figure_resampler.FigureResampler.show_dash>` on the Figure
3135

32-
1. wrap the plotly Figure with :class:`FigureResampler <plotly_resampler.figure_resampler.FigureResampler>`
33-
2. call :func:`.show_dash() <plotly_resampler.figure_resampler.FigureResampler.show_dash>` on the Figure
36+
* `FigureWidget.layout.on_change <https://plotly.com/python-api-reference/generated/plotly.html?highlight=on_change#plotly.basedatatypes.BasePlotlyType.on_change>`_ , when a ``go.FigureWidget`` is used within a ``.ipynb`` environment.
37+
38+
.. note::
39+
40+
This is especially useful when developing in ``jupyter`` environments and when **you cannot open/forward a network-port**.
41+
42+
43+
To **add dynamic resampling** using a **FigureWidget**, you should:
44+
1. wrap your plotly Figure (can be a ``go.Figure``) with :class:`FigureWidgetResampler <plotly_resampler.figure_resampler.FigureWidgetResampler>`
45+
2. output the ```FigureWidgetResampler`` instance in a cell
3446

3547
.. tip::
3648

37-
For **significant faster initial loading** of the Figure, we advise to wrap the constructor of the plotly Figure with :class:`FigureResampler <plotly_resampler.figure_resampler.FigureResampler>` and add the trace data as ``hf_x`` and ``hf_y``
49+
For **significant faster initial loading** of the Figure, we advise to wrap the constructor of the plotly Figure with either :class:`FigureResampler <plotly_resampler.figure_resampler.FigureResampler>` or :class:`FigureWidgetResampler <plotly_resampler.figure_resampler.FigureWidgetResampler>` and add the trace data as ``hf_x`` and ``hf_y``
3850

3951
.. note::
4052

41-
Any plotly Figure can be wrapped with :class:`FigureResampler <plotly_resampler.figure_resampler.FigureResampler>`! 🎉 :raw-html:`<br>`
42-
But, (obviously) only the scatter traces will be resampled.
53+
Any plotly Figure can be wrapped with dynamic aggregation functionality! 🎉 :raw-html:`<br>`
54+
But, (obviously) only the scatter traces will be resampled.
4355

44-
Working example
45-
------------------
56+
Working examples
57+
-------------------
4658

4759
.. code:: py
4860
@@ -57,6 +69,10 @@ Working example ✅
5769
5870
fig.show_dash(mode='inline')
5971
72+
The gif below demonstrates the example usage of of :class:`FigureWidgetResampler <plotly_resampler.figure_resampler.FigureWidgetResampler>`, where ``JupyterLab`` is used as environment and the ``FigureWidgetResampler`` instance it's output is redirected into a new view. Also note how you are able to dynamically add traces!
73+
74+
.. image:: https://raw.githubusercontent.com/predict-idlab/plotly-resampler/main/docs/sphinx/_static/figurewidget.gif
75+
6076
Important considerations & tips 🚨
6177
----------------------------------
6278

@@ -99,7 +115,7 @@ Plotly-resampler & not high-frequency traces 🔍
99115
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
100116

101117
.. Tip::
102-
118+
103119
In the *Skin conductance example* of the :raw-html:`<a href="https://github.com/predict-idlab/plotly-resampler/tree/main/examples"><b>basic_example.ipynb</b><a>`, we deal with such low-frequency traces.
104120

105121
The :func:`add_trace <plotly_resampler.figure_resampler.FigureResampler.add_trace>` method allows configuring argument which allows us to deal with low-frequency traces.
@@ -108,11 +124,11 @@ The :func:`add_trace <plotly_resampler.figure_resampler.FigureResampler.add_trac
108124
Use-cases
109125
"""""""""
110126

111-
* **not resampling** trace data: To achieve this, set:
127+
* **not resampling** trace data: To achieve this, set:
112128

113129
* ``max_n_samples`` = len(hf_x)
114130

115-
* **not resampling** trace data, but **slicing to the view**: To achieve this, set:
131+
* **not resampling** trace data, but **slicing to the view**: To achieve this, set:
116132

117133
* ``max_n_samples`` = len(hf_x)
118134
* ``limit_to_view`` = True

docs/sphinx/index.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ This is the documentation of `plotly-resampler <https://github.com/predict-idlab
1010

1111
.. image:: https://raw.githubusercontent.com/predict-idlab/plotly-resampler/main/docs/sphinx/_static/basic_example.gif
1212

13+
.. raw:: html
14+
15+
<br><br>
16+
17+
As shown in the demo above, ``plotly-resampler`` maintains its interactiveness on large data by applying front-end **resampling respective to the view**.
18+
1319
.. raw:: html
1420

1521
<embed>

examples/README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,12 @@ plotly-resampler in various use cases.
77

88
The testing CI/CD of plotly resampler uses _selenium_ and _selenium-wire_ to test the
99
interactiveness of various figures. All these figures are shown in
10-
the [basic-example notebook](basic_example.ipynb)
10+
the [basic example notebook](basic_example.ipynb)
11+
12+
### 0.1 Figurewidget example
13+
14+
The [figurewidget example notebook](figurewidget_example.ipynb) utilizes the `FigureWidgetResampler` wrapper to
15+
create a `go.FigureWidget` with dynamic aggregation functionality. A major advantage of this approach is that this does not create a web application, thus not needing to be able to create / forward a network port.
1116

1217
## 1. Dash apps
1318

0 commit comments

Comments
 (0)