Skip to content

Get started 🚀

The plotly-resampler package offers two primary modules:

  • figure_resampler: a wrapper for plotly.graph_objects Figures, coupling dynamic resampling functionality with the Figure.
  • aggregation: This module contains interfaces for the various aggregation methods implemented in tsdownsample.

Installation ⚙️

Install via pip:

pip install plotly-resampler

Usage 📈

Plotly-Resampler facilitates dynamic resampling in two ways:

  • Automatic Approach (low code overhead)

  • Manual Approach (data aggregation configurability, graph construction speedups)

    1. By utilizing Dash callbacks to augment a go.Figure with dynamic aggregation functionality.

      Note

      This is particularly advantageous when working with Dash or outside Jupyter environments.

    2. By utilizing FigureWidget.layout.on_change , when a go.FigureWidget is used within a .ipynb environment.

      • steps:

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

        Note

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

Tip

For significant faster initial loading of the Figure, we advise to

  1. wrap the constructor of the plotly Figure with either FigureResampler or FigureWidgetResampler
  2. add the trace data as hf_x and hf_y

Note

Any plotly Figure can be wrapped with dynamic aggregation functionality! 🎉
But only go.Scatter/go.Scattergl traces will be resampled!

Examples ✅

register_plotly_resampler

import plotly.graph_objects as go; import numpy as np
from plotly_resampler import register_plotly_resampler, unregister_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

# to undo the wrapping, call the unregister_plotly_resampler function

FigureResampler

# NOTE: this example works in a notebook environment
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')

Overview

In the example below, we demonstrate the (x-axis)overview feature of plotly-ressampler. For more information you can check out the examples to find dash apps and in-notebook use-cases.

!!! Note: - This overview is only available for the FigureResampler and not for the FigureWidgetResampler. - As a recent and experimental feature, user feedback is crucial. Please report any issues encountered!

FigureResampler overview

FigureWidget

The gif below demonstrates the example usage of FigureWidgetResampler, where JupyterLab is used as the environment and the FigureWidgetResampler.

Note how (i) the figure output is redirected into a new view, and (ii) 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 of plotly-resampler figures can be adjusted using the hf_data property.

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