Skip to main content

Visualizing large time series with plotly

Project description

Plotly-Resampler logo

PyPI Latest Release support-version codecov Downloads PRs Welcome Documentation Testing

plotly_resampler: visualize large sequential data by adding resampling functionality to Plotly figures

Plotly 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.

basic example gif

In this Plotly-Resampler demo over 110,000,000 data points are visualized!

Installation

pip pip install plotly-resampler

Features :tada:

  • Convenient to use:
    • just add either
      • register_plotly_resampler function to your notebook with the best suited mode argument.
      • FigureResampler decorator around a plotly Figure and call .show_dash()
      • FigureWidgetResampler decorator around a plotly Figure and output the instance in a cell
    • allows all other plotly figure construction flexibility to be used!
  • Environment-independent
    • can be used in Jupyter, vscode-notebooks, Pycharm-notebooks, Google Colab, DataSpell, and even as application (on a server)
  • Interface for various aggregation algorithms:
    • ability to develop or select your preferred sequence aggregation method

Usage

Add dynamic aggregation to your plotly Figure (unfold your fitting use case)

  • 🤖 Automatically (minimal code overhead):

    Use the register_plotly_resampler function
    1. Import and call the register_plotly_resampler method
    2. Just use your regular graph construction code
    • code example:
      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
      
      
      # auto mode: 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
      

    Note: This wraps all plotly graph object figures with a FigureResampler | FigureWidgetResampler. This can thus also be used for the plotly.express interface. 🎉

  • 👷 Manually (higher data aggregation configurability, more speedup possibilities):

    • Within a jupyter environment without creating a web application
      1. wrap the plotly Figure with FigureWidgetResampler
      2. output the FigureWidgetResampler instance in a cell
      import plotly.graph_objects as go; import numpy as np
      from plotly_resampler import FigureResampler, FigureWidgetResampler
      
      x = np.arange(1_000_000)
      noisy_sin = (3 + np.sin(x / 200) + np.random.randn(len(x)) / 10) * x / 1_000
      
      # OPTION 1 - FigureWidgetResampler: dynamic aggregation via `FigureWidget.layout.on_change`
      fig = FigureWidgetResampler(go.Figure())
      fig.add_trace(go.Scattergl(name='noisy sine', showlegend=True), hf_x=x, hf_y=noisy_sin)
      
      fig
      
    • Using a web-application with dash callbacks
      1. wrap the plotly Figure with FigureResampler
      2. call .show_dash() on the Figure
      import plotly.graph_objects as go; import numpy as np
      from plotly_resampler import FigureResampler, FigureWidgetResampler
      
      x = np.arange(1_000_000)
      noisy_sin = (3 + np.sin(x / 200) + np.random.randn(len(x)) / 10) * x / 1_000
      
      # OPTION 2 - FigureResampler: dynamic aggregation via a Dash web-app
      fig = FigureResampler(go.Figure())
      fig.add_trace(go.Scattergl(name='noisy sine', showlegend=True), hf_x=x, hf_y=noisy_sin)
      
      fig.show_dash(mode='inline')
      

    Tip 💡: 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


Note: Any plotly Figure can be wrapped with FigureResampler and FigureWidgetResampler! 🎉 But, (obviously) only the scatter traces will be resampled.

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!
  • The FigureWidgetResampler uses the IPython main thread for its data aggregation functionality, so when this main thread is occupied, no resampling logic can be executed. For example; if you perform long computations within your notebook, the kernel will be occupied during these computations, and will only execute the resampling operations that take place during these computations after finishing that computation.
  • In general, when using downsampling one should be aware of (possible) aliasing effects. The [R] 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.
  • 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 issue #49.

Cite

Paper (preprint): https://arxiv.org/abs/2206.08703

@inproceedings{van2022plotly,
  title={Plotly-resampler: Effective visual analytics for large time series},
  author={Van Der Donckt, Jonas and Van Der Donckt, Jeroen and Deprost, Emiel and Van Hoecke, Sofie},
  booktitle={2022 IEEE Visualization and Visual Analytics (VIS)},
  pages={21--25},
  year={2022},
  organization={IEEE}
}

Future work 🔨

  • Support .add_traces() (currently only .add_trace is supported)
  • Support hf_color and hf_markersize, see #148
  • Create C bindings for our EfficientLTTB algorithm.
  • Integrate with tsdownsample :racehorse:


👤 Jonas Van Der Donckt, Jeroen Van Der Donckt, Emiel Deprost

Project details


Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

plotly_resampler-0.8.3.2.tar.gz (46.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

plotly_resampler-0.8.3.2-cp310-cp310-manylinux_2_35_x86_64.whl (70.1 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.35+ x86-64

File details

Details for the file plotly_resampler-0.8.3.2.tar.gz.

File metadata

  • Download URL: plotly_resampler-0.8.3.2.tar.gz
  • Upload date:
  • Size: 46.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.3.2 CPython/3.10.6 Linux/5.15.0-67-generic

File hashes

Hashes for plotly_resampler-0.8.3.2.tar.gz
Algorithm Hash digest
SHA256 5cac870d6d269cdd71d28def4cae310c609c02aac636c0831176188f16021f44
MD5 5f7a26e67e2711ba8d866c41cb4879b4
BLAKE2b-256 194f43f591976de48685196f3d569738fe3d54c3d7c0afec7b2c40ea0e4b6bc0

See more details on using hashes here.

File details

Details for the file plotly_resampler-0.8.3.2-cp310-cp310-manylinux_2_35_x86_64.whl.

File metadata

File hashes

Hashes for plotly_resampler-0.8.3.2-cp310-cp310-manylinux_2_35_x86_64.whl
Algorithm Hash digest
SHA256 c3de2cef735e68fce5c64033cd725b650a9af25e56629bca81d12475c689e58b
MD5 80fe462f1c4dde8f4388b1f9d978bc48
BLAKE2b-256 c402cc1eb5855cb6e7ec23985f7d6b8d93f45a822ad83ff6373943ab057a1bf1

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page