Skip to content

Get started 🚀

plotly-resampler serves two main modules:

  • figure_resampler: a wrapper for plotly.graph_objects Figures, coupling the dynamic resampling functionality to the Figure.

  • aggregation: a module that withholds various data aggregation methods.

Installation ⚙️

Install via pip:

pip install plotly-resampler

How to use 📈

Dynamic resampling callbacks are realized:

  • Automatically (low code overhead):

    • using the register_plotly_resampler function To add dynamic resampling using a FigureWidget, you should:

      1. Import and call the register_plotly_resampler
      2. Just use your regular graph construction code

      Once this method is called, it will automatically convert all new defined plotly graph objects into a FigureResampler or FigureWidgetResampler object. The mode parameter of this method allows to define which type of the aformentioned resampling objects is used.

  • Manually (data aggregation configurability, graph construction speedups):

    • Dash callbacks, when a go.Figure object is wrapped with dynamic aggregation functionality.

      Note

      This is especially useful when working with dash functionality or when you do not want to solely operate in jupyter environments.

      To add dynamic resampling, you should:

      1. wrap the plotly Figure with FigureResampler
      2. call .show_dash() on the Figure
    • FigureWidget.layout.on_change , when a go.FigureWidget is used within a .ipynb environment.

      Note

      This is especially useful when developing in jupyter environments and when you cannot open/forward a network-port.

      To add dynamic resampling using a FigureWidget, you should:

      1. wrap your plotly Figure (can be a go.Figure with FigureWidgetResampler)
      2. output the FigureWidgetResampler instance in a cell

Tip

For significant faster initial loading of the Figure, we advise to wrap the constructor of the plotly Figure with either FigureResampler or FigureWidgetResampler and add the trace data as hf_x and hf_y

Note

Any plotly Figure can be wrapped with dynamic aggregation functionality! 🎉

But, (obviously) only the scatter traces will be resampled.

Working examples ✅

register_plotly_resampler

import plotly.graph_objects as go; import numpy as np
from plotly_resampler import register_plotly_resampler

# Call the register function once and all Figures/FigureWidgets will be wrapped
# according to the register_plotly_resampler its `mode` argument
register_plotly_resampler(mode='auto')

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


# when working in an IPython environment, this will automatically be a
# FigureWidgetResampler else, this will be an FigureResampler
f = go.Figure()
f.add_trace({"y": noisy_sin + 2, "name": "yp2"})
f

FigureResampler

import plotly.graph_objects as go; import numpy as np
from plotly_resampler import FigureResampler

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

fig = FigureResampler(go.Figure())
fig.add_trace(go.Scattergl(name='noisy sine', showlegend=True), hf_x=x, hf_y=sin)

fig.show_dash(mode='inline')

FigureWidget

The gif below demonstrates the example usage of FigureWidgetResampler, where JupyterLab is used as the environment and the FigureWidgetResampler instance its output is redirected into a new view. Also note how you are able to dynamically add traces!

FigureWidget example

Furthermore, plotly’s FigureWidget allows to conveniently add callbacks to for example click events. This allows creating a high-frequency time series annotation app in a couple of lines; as shown in the gif below and in this notebook.

Annotate Twitter

Important considerations & tips 🚨

  • When running the code on a server, you should forward the port of the FigureResampler.show_dash method to your local machine.
    Note that you can add dynamic aggregation to plotly figures with the FigureWidgetResampler wrapper without needing to forward a port!
  • In general, when using downsampling one should be aware of (possible) aliasing effects. The [R] in the legend indicates when the corresponding trace is resampled (and thus possibly distorted). The ~ delta suffix in the legend represents the mean index delta for consecutive aggregated data points.
  • The plotly autoscale event (triggered by the autoscale button or a double-click within the graph), does not reset the axes but autoscales the current graph-view of plotly-resampler figures. This design choice was made as it seemed more intuitive for the developers to support this behavior with double-click than the default axes-reset behavior. The graph axes can ofcourse be resetted by using the reset_axis button. If you want to give feedback and discuss this further with the developers, see this issue #49.

Dynamically adjusting the scatter data 🔩

The raw high-frequency trace data can be adjusted using the hf_data property of the plotly-resampler Figure instance.

Working example ⬇️:

import plotly.graph_objects as go; import numpy as np
from plotly_resampler import FigureResampler
# Note: a FigureWidgetResampler can be used here as well

# Construct the hf-data
x = np.arange(1_000_000)
sin = (3 + np.sin(x / 200) + np.random.randn(len(x)) / 10) * x / 1_000

fig = FigureResampler(go.Figure())
fig.add_trace(go.Scattergl(name='noisy sine', showlegend=True), hf_x=x, hf_y=sin)
fig.show_dash(mode='inline')

# After some time -> update the hf_data y property of the trace
# As we only have 1 trace, this needs to be mapped
fig.hf_data[-1]['y'] = - sin ** 2

Note

hf_data only withholds high-frequency traces (i.e., traces that are aggregated). To add non high-frequency traces (i.e., traces with fewer data points than max_n_samples), you need to set the limit_to_view argument to True when adding the corresponding trace with the add_trace function.

Tip

The FigureWidgetResampler graph will not be automatically redrawn after adjusting the fig its hf_data property. The redrawing can be triggered by manually calling either:

Plotly-resampler & not high-frequency traces 🔍

Tip

In the Skin conductance example of the basic_example.ipynb, we deal with such low-frequency traces.

The add_trace method allows configuring argument which allows us to deal with low-frequency traces.

Use-cases

  • not resampling trace data: To achieve this, set:

  • max_n_samples = len(hf_x)

  • not resampling trace data, but slicing to the view: To achieve this, set:

  • max_n_samples = len(hf_x)
  • limit_to_view = True

Note

For, irregularly sampled traces which are filled (e.g. colored background signal quality trace of the skin conductance example), it is important that you set gap_handler to NoGapHandler for that trace.

Otherwise, when you leave gap_handler to MedDiffGapHandler, you may get weird background shapes such as ⬇️: Skin conductance example with gap interleaving

When gap_handler is set to NoGapHandler you get ⬇️: Skin conductance example without gap interleaving