Skip to content

Add uPlot Element#5917

Draft
NvNielen wants to merge 1 commit intozauberzeug:mainfrom
NvNielen:uplot-element
Draft

Add uPlot Element#5917
NvNielen wants to merge 1 commit intozauberzeug:mainfrom
NvNielen:uplot-element

Conversation

@NvNielen
Copy link
Copy Markdown

Motivation

This PR introduces support for uPlot, a high-performance, memory-efficient 2D plotting library. This was originally requested in #2669, but also motivated by issues related to large dataset plotting such as #3340. Compared to other plotting libraries, it has a smaller memory footprint and less overhead on rendering, which makes it ideal for processing large datasets at high refresh rates.

Implementation

The core implementation wraps uPlot as a NiceGUI element, based on uplot-vue, which exposes uPlot's config and data update mechanisms.

The design anticipates plugin support, with plans to add Wheel Zoom & Drag and legend-as-a-tooltip plugins .

The update logic should be structured to allow zoom/drag state to persist across data updates, as demonstrated in #2669 .
Some important technical considerations include keeping the API simple and extensible, down sampling support, plugin support and implementing tests.

Progress

  • uPlot base element and functionality
  • Persist zoom/drag across updates
  • Add plugin support
  • Add downsampling
  • Pytests, should include rendering, updates, and plugins.
  • Add documentation and provide clear, runnable demos, since uPlot's documentation is limited.

@NvNielen
Copy link
Copy Markdown
Author

NvNielen commented Mar 26, 2026

Any input and/or feedback very much appreciated!

@falkoschindler
Copy link
Copy Markdown
Contributor

Thanks for this PR! uPlot is a great choice for high-performance charting, and this is a solid start.

We tested the element successfully with the following code:

from nicegui import ui
from nicegui.elements.uplot.uplot import UPlot
import math

x_data = list(range(100))
y_data = [math.sin(i * 0.1) for i in range(100)]

chart = UPlot({
    'width': 800,
    'height': 400,
    'title': 'Sine Wave',
    'series': [{}, {'stroke': 'red', 'label': 'sin(x)'}],
}, data=[x_data, y_data])

@ui.button('Add Point').on_click
def add_point():
    x_data.append(len(x_data))
    y_data.append(math.sin(len(y_data) * 0.1))
    chart.update_data([x_data, y_data])

ui.run()

A few things we noticed while looking at the code:

  • The other ESM-based elements (plotly, echart, codemirror) have an __init__.py that re-exports the class, plus a ui.plotly(...) / ui.echart(...) registration. Something to keep in mind for when this gets wired up to the ui namespace.

  • uplot.py imports NumPy unconditionally, but it's only used in type hints. A TYPE_CHECKING guard would avoid making NumPy a hard dependency:

    from typing import TYPE_CHECKING
    if TYPE_CHECKING:
        import numpy as np

Looking forward to seeing this evolve!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants