Skip to main content

ImPlot-powered Jupyter plotting widget for interactive, million-point visualizations.

Project description

nbimplot

Jupyter-native, ImPlot-powered plotting for very large arrays.

nbimplot is built around three constraints:

  • notebook cell rendering only (no native windows, no side process)
  • binary transfer (numpy -> bytes -> wasm heap)
  • WASM-owned interaction, state, and LOD

The runtime is strict: ImPlot + WASM + WebGL2 are required.

Install

python -m pip install -U nbimplot

Minimum recommended widget/runtime stack:

python -m pip install -U "nbimplot>=0.1.6" "anywidget>=0.9.21" ipywidgets jupyterlab_widgets

Quick Start

import numpy as np
import nbimplot as ip

y = np.sin(np.linspace(0, 100, 1_000_000, dtype=np.float32))

p = ip.Plot(width=900, height=450, title="Signal")
h = p.line("mid", y)
p.show()

# Update in place, then redraw
h.set_data((0.8 * y).astype(np.float32))
p.render()

Interaction Defaults

  • initial X/Y view auto-fits to available data
  • double-click inside plot area resets view (autoscale)
  • right-drag box zoom, wheel zoom, drag pan, legend toggle

Core API

import numpy as np
import nbimplot as ip

y = np.random.randn(200_000).astype(np.float32).cumsum()

p = ip.Plot(width=1000, height=420, title="Core API")
h = p.line("price", y, color="#22c55e", line_weight=2.0, marker="none")
p.set_plot_flags(no_legend=False, no_menus=False, no_box_select=False)
p.set_colormap("Viridis")
p.show()

# Later update
h.set_data((y * 1.01).astype(np.float32))
p.render()

Common Examples

1) Line + Streaming

import numpy as np
import nbimplot as ip

p = ip.Plot(width=1000, height=380, title="Streaming")
h = p.stream_line("ticks", capacity=200_000, initial=np.zeros(1000, dtype=np.float32))
p.show()

chunk = np.random.randn(20_000).astype(np.float32)
h.append(chunk)
p.render()

2) Scatter / Bars / Histogram

import numpy as np
import nbimplot as ip

rng = np.random.default_rng(7)
x = rng.normal(0, 1, 4000).astype(np.float32)
y = (0.5 * x + 0.2 * rng.normal(size=x.size)).astype(np.float32)

p = ip.Plot(width=1100, height=420, title="Stat Plots")
p.scatter("cloud", y, x=x, size=2.0)
p.vlines("cuts", np.array([-1.0, 1.0], dtype=np.float32))
p.hlines("zero", np.array([0.0], dtype=np.float32))
p.show()

p2 = ip.Plot(width=1100, height=360, title="Histogram")
p2.histogram("x-dist", x, bins=60)
p2.show()

3) Heatmap / Histogram2D / Image

import numpy as np
import nbimplot as ip

rng = np.random.default_rng(0)
z = rng.normal(size=(50, 80)).astype(np.float32)

p = ip.Plot(width=1100, height=420, title="Heatmap")
p.set_colormap("Plasma")
p.heatmap(
    "z",
    z,
    label_fmt="",  # empty format disables cell text
    show_colorbar=True,
    colorbar_label="Intensity",
    colorbar_format="%.3f",
)
p.show()

x = rng.normal(size=200_000).astype(np.float32)
y = (0.3 * x + rng.normal(size=x.size)).astype(np.float32)
p2 = ip.Plot(width=1100, height=420, title="Histogram2D")
p2.histogram2d(
    "h2d",
    x,
    y,
    x_bins=100,
    y_bins=80,
    label_fmt="",
    show_colorbar=True,
    colorbar_label="Count",
)
p2.show()

4) Subplots

import numpy as np
import nbimplot as ip

sp = ip.Subplots(
    2,
    2,
    title="Dashboard",
    width=1100,
    height=760,
    link_rows=True,
    link_cols=True,
    share_items=True,
)

t = np.linspace(0, 30, 4000, dtype=np.float32)
sp.subplot(0, 0).line("sin", np.sin(t))
sp.subplot(0, 1).scatter("noise", np.random.randn(3000).astype(np.float32))
sp.subplot(1, 0).bars("bars", np.abs(np.random.randn(120)).astype(np.float32))
sp.subplot(1, 1).histogram("hist", np.random.randn(20_000).astype(np.float32), bins=50)
sp.show()

Plot and Primitive Coverage

Implemented plot/primitive APIs include:

  • line, stream_line
  • scatter, bubbles, stairs, stems, digital
  • bars, bar_groups, bars_h, shaded
  • error_bars, error_bars_h
  • inf_lines, vlines, hlines
  • histogram, histogram2d, heatmap, image, pie_chart
  • text, annotation, dummy
  • tag_x, tag_y, colormap_slider, colormap_button, colormap_selector
  • drag_line_x, drag_line_y, drag_point, drag_rect
  • drag_drop_plot, drag_drop_axis, drag_drop_legend

For a broader cookbook, see docs/EXAMPLES.md.

View, Axes, and Performance Controls

  • p.set_view(x_min, x_max, y_min, y_max)
  • p.autoscale()
  • p.set_axis_scale(x="linear|log", y="linear|log")
  • p.set_axis_state("x2|x3|y2|y3", enabled=True|False, scale="linear|log|time")
  • p.set_secondary_axes(x2=..., x3=..., y2=..., y3=...)
  • p.set_time_axis("x1|x2|x3|y1|y2|y3")
  • p.set_axis_label(...), p.set_axis_format(...)
  • p.set_axis_ticks(...), p.clear_axis_ticks(...)
  • p.set_axis_limits_constraints(...), p.set_axis_zoom_constraints(...), p.set_axis_link(...)
  • p.hide_next_item()
  • p.on_perf_stats(callback, interval_ms=500)
  • p.on_tool_change(callback)
  • p.on_selection_change(callback)

Example Notebooks

  • notebooks/nbimplot_examples.ipynb
  • notebooks/nbimplot_api_gallery.ipynb
  • notebooks/nbimplot_benchmarks.ipynb

Troubleshooting

Failed to load model class 'AnyModel' from module 'anywidget'

This is usually a server-kernel env mismatch or stale lab assets.

python -m pip install -U "nbimplot>=0.1.6" "anywidget>=0.9.21" ipywidgets jupyterlab_widgets
jupyter lab clean

Then restart the full JupyterLab server.

Quick verification:

import nbimplot as ip, anywidget, sys
print("python:", sys.executable)
print("anywidget:", anywidget.__version__)
print("has Plot:", hasattr(ip, "Plot"))

Unable to enable ImPlot in the WASM core or WebGL context errors

Strict mode requires WebGL2.

!!document.createElement("canvas").getContext("webgl2")

If this is false, run from a local desktop browser session with GPU acceleration enabled.

Build WASM Core

Prerequisites:

  • Emscripten SDK (emcmake, emcc)
  • CMake >= 3.20

Build:

scripts/build_wasm.sh

Expected outputs in nbimplot/wasm/:

  • nbimplot_wasm.js
  • nbimplot_wasm.wasm

Build explicitly with local ImGui/ImPlot sources:

NBIMPLOT_WITH_IMPLOT=ON \
NBIMPLOT_IMGUI_DIR=/path/to/imgui \
NBIMPLOT_IMPLOT_DIR=/path/to/implot \
scripts/build_wasm.sh

If you use vendored deps:

NBIMPLOT_WITH_IMPLOT=ON scripts/build_wasm.sh

Performance Model

  • raw path when visible points <= 3 * pixel_width
  • min/max LOD when visible points > 3 * pixel_width
  • LOD computed in WASM, complexity scales with screen pixels

Project details


Download files

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

Source Distribution

nbimplot-0.1.6.tar.gz (392.7 kB view details)

Uploaded Source

Built Distribution

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

nbimplot-0.1.6-py3-none-any.whl (393.3 kB view details)

Uploaded Python 3

File details

Details for the file nbimplot-0.1.6.tar.gz.

File metadata

  • Download URL: nbimplot-0.1.6.tar.gz
  • Upload date:
  • Size: 392.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.12

File hashes

Hashes for nbimplot-0.1.6.tar.gz
Algorithm Hash digest
SHA256 e95fb4b98b5318ec7e06cc21bc040bb976793b4f1ed3035594aa7ac643c144fa
MD5 137f218f4e637ee4a77bc72e2267031c
BLAKE2b-256 073612893bbcba33856b0b57cac6ae2f7f924918004faa68b28533a96c5f55c9

See more details on using hashes here.

File details

Details for the file nbimplot-0.1.6-py3-none-any.whl.

File metadata

  • Download URL: nbimplot-0.1.6-py3-none-any.whl
  • Upload date:
  • Size: 393.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.12

File hashes

Hashes for nbimplot-0.1.6-py3-none-any.whl
Algorithm Hash digest
SHA256 4427aa67b0003704f7fee4bf4f859425dea2c1f96979733e0bbca6f93502bb18
MD5 97f6389aa9495e0f1d71a29c54566650
BLAKE2b-256 b4c070556feef68e783090ba155567d2833683205a55899d8ccd557c5ca04a01

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