nbimplot 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
nbimplot-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nbimplot
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: ImPlot-powered Jupyter plotting widget for interactive, million-point visualizations.
|
|
5
|
+
Author: nbimplot contributors
|
|
6
|
+
License: MIT
|
|
7
|
+
Keywords: implot,jupyter,plotting,visualization,widgets
|
|
8
|
+
Classifier: Framework :: Jupyter
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
12
|
+
Requires-Python: >=3.10
|
|
13
|
+
Requires-Dist: anywidget>=0.9.13
|
|
14
|
+
Requires-Dist: ipywidgets>=8.1.0
|
|
15
|
+
Requires-Dist: numpy>=1.24
|
|
16
|
+
Requires-Dist: traitlets>=5.14
|
|
17
|
+
Provides-Extra: dev
|
|
18
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# nbimplot
|
|
22
|
+
|
|
23
|
+
Jupyter-native plotting focused on high interactivity and large time-series support.
|
|
24
|
+
|
|
25
|
+
Current implementation includes:
|
|
26
|
+
|
|
27
|
+
- Notebook-only widget canvas rendering
|
|
28
|
+
- Binary transport (`numpy -> bytes -> wasm memory`)
|
|
29
|
+
- WASM core for plot state, autoscale, and min/max LOD generation
|
|
30
|
+
- Strict WASM runtime requirement (JS fallback disabled)
|
|
31
|
+
- ImPlot-required mode (`prefer_implot=True`, `strict_wasm=True` only)
|
|
32
|
+
- Lifecycle-safe cleanup for repeated cell execution
|
|
33
|
+
- Subplots via `nbimplot.Subplots`
|
|
34
|
+
- Expanded primitive APIs: `scatter`, `bubbles`, `stairs`, `stems`, `digital`,
|
|
35
|
+
`bars`, `bar_groups`, `bars_h`, `shaded`, `error_bars`, `error_bars_h`,
|
|
36
|
+
`inf_lines`, `vlines`, `hlines`, `histogram`, `histogram2d`, `heatmap`,
|
|
37
|
+
`image`, `pie_chart`, `text`, `annotation`, `dummy`
|
|
38
|
+
|
|
39
|
+
## Quick start
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
import numpy as np
|
|
43
|
+
import nbimplot as ip
|
|
44
|
+
|
|
45
|
+
y = np.sin(np.linspace(0, 100, 1_000_000, dtype=np.float32))
|
|
46
|
+
|
|
47
|
+
p = ip.Plot(width=900, height=450, title="Signal")
|
|
48
|
+
h = p.line("mid", y)
|
|
49
|
+
p.show()
|
|
50
|
+
|
|
51
|
+
h.set_data(y * 0.8)
|
|
52
|
+
p.render()
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## API
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
import nbimplot as ip
|
|
59
|
+
|
|
60
|
+
p = ip.Plot(width=900, height=450, title="Signal")
|
|
61
|
+
h = p.line("mid", y, x_axis="x1", y_axis="y1", subplot_index=0)
|
|
62
|
+
h.set_data(y_new)
|
|
63
|
+
p.render()
|
|
64
|
+
p.show()
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
`prefer_implot=False` and `strict_wasm=False` are not supported.
|
|
68
|
+
|
|
69
|
+
Additional controls:
|
|
70
|
+
|
|
71
|
+
- `p.set_view(x_min, x_max, y_min, y_max)`
|
|
72
|
+
- `p.autoscale()`
|
|
73
|
+
- `p.set_axis_scale(x="linear|log", y="linear|log")`
|
|
74
|
+
- `p.set_plot_flags(...)` for native ImPlot flags (`no_legend`, `no_menus`, etc.)
|
|
75
|
+
- `p.set_axis_state("x2|x3|y2|y3", enabled=True|False, scale="linear|log|time")`
|
|
76
|
+
- `p.set_axis_label(...)`, `p.set_axis_format(...)`, `p.set_axis_ticks(...)`, `p.clear_axis_ticks(...)`
|
|
77
|
+
- `p.set_axis_limits_constraints(...)`, `p.set_axis_zoom_constraints(...)`, `p.set_axis_link(...)`
|
|
78
|
+
- `p.set_secondary_axes(x2=..., x3=..., y2=..., y3=...)`
|
|
79
|
+
- `p.set_time_axis("x1|x2|x3|y1|y2|y3")`
|
|
80
|
+
- `p.set_colormap("Deep|Dark|Pastel|Paired|Viridis|Plasma|Hot|Cool|Pink|Jet|Twilight|RdBu|BrBG|PiYG|Spectral|Greys")`
|
|
81
|
+
- Most primitive APIs support `x_axis="x1|x2|x3"` and `y_axis="y1|y2|y3"`
|
|
82
|
+
- `p.line(..., color=\"#3b82f6\", line_weight=2.0, marker=\"circle\", marker_size=5.0)` and `handle.set_style(...)`
|
|
83
|
+
- `p.stream_line(..., capacity=N)` and `handle.append(...)` for in-place ring-buffer style updates
|
|
84
|
+
- `p.hide_next_item()` to hide the next added series/primitive without removing it
|
|
85
|
+
- `p.heatmap(..., label_fmt="%.2f", scale_min=None, scale_max=None)` and `label_fmt=""` to hide cell-value text
|
|
86
|
+
- `p.heatmap(..., show_colorbar=True, colorbar_label="Intensity", colorbar_format="%g", colorbar_flags=0)`
|
|
87
|
+
- `p.histogram2d(..., show_colorbar=True, colorbar_label="Count", colorbar_format="%g", colorbar_flags=0)`
|
|
88
|
+
- `p.image(..., bounds=((x0, y0), (x1, y1)), uv0=(0, 0), uv1=(1, 1))` for true `ImPlot::PlotImage` rendering (`z` can be 2D grayscale or `H x W x 3/4` RGB(A))
|
|
89
|
+
- `p.tag_x(...)`, `p.tag_y(...)`, `p.colormap_slider(...)`, `p.colormap_button(...)`, `p.colormap_selector(...)`
|
|
90
|
+
- `p.drag_drop_plot(...)`, `p.drag_drop_axis(...)`, `p.drag_drop_legend(...)`
|
|
91
|
+
- `p.on_perf_stats(callback, interval_ms=500)` for live FPS/WASM timings
|
|
92
|
+
- `p.on_tool_change(callback)` for drag tool updates
|
|
93
|
+
- `p.on_selection_change(callback)` for box-selection/query updates
|
|
94
|
+
|
|
95
|
+
Interactive tools:
|
|
96
|
+
|
|
97
|
+
- `p.drag_line_x(...)`
|
|
98
|
+
- `p.drag_line_y(...)`
|
|
99
|
+
- `p.drag_point(...)`
|
|
100
|
+
- `p.drag_rect(...)`
|
|
101
|
+
|
|
102
|
+
## Subplots (Native ImPlot)
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
import nbimplot as ip
|
|
106
|
+
import numpy as np
|
|
107
|
+
|
|
108
|
+
sp = ip.Subplots(
|
|
109
|
+
2,
|
|
110
|
+
2,
|
|
111
|
+
title="Dashboard",
|
|
112
|
+
width=1000,
|
|
113
|
+
height=700,
|
|
114
|
+
link_rows=True,
|
|
115
|
+
link_cols=True,
|
|
116
|
+
share_items=True,
|
|
117
|
+
)
|
|
118
|
+
sp.subplot(0, 0).line("line", np.sin(np.linspace(0, 20, 5000, dtype=np.float32)))
|
|
119
|
+
sp.subplot(0, 1).scatter("pts", np.random.randn(2000).astype(np.float32))
|
|
120
|
+
sp.subplot(1, 0).bars("bars", np.abs(np.random.randn(120)).astype(np.float32))
|
|
121
|
+
sp.subplot(1, 1).histogram("hist", np.random.randn(20_000).astype(np.float32), bins=40)
|
|
122
|
+
sp.show()
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
`Subplots(...)` supports axis-linking controls:
|
|
126
|
+
|
|
127
|
+
- `link_rows`: link y-axis within each row
|
|
128
|
+
- `link_cols`: link x-axis within each column
|
|
129
|
+
- `link_all_x`: link x-axis for all cells
|
|
130
|
+
- `link_all_y`: link y-axis for all cells
|
|
131
|
+
- Additional compatibility flags: `share_items`, `no_legend`, `no_menus`,
|
|
132
|
+
`no_resize`, `no_align`, `col_major`
|
|
133
|
+
|
|
134
|
+
Aligned-group helper:
|
|
135
|
+
|
|
136
|
+
- `ip.AlignedPlots(rows, cols, group_id="aligned", vertical=True, ...)`
|
|
137
|
+
|
|
138
|
+
## Example Notebook
|
|
139
|
+
|
|
140
|
+
- `notebooks/nbimplot_examples.ipynb`
|
|
141
|
+
- `notebooks/nbimplot_api_gallery.ipynb`
|
|
142
|
+
- `notebooks/nbimplot_benchmarks.ipynb`
|
|
143
|
+
|
|
144
|
+
## Build WASM core
|
|
145
|
+
|
|
146
|
+
### Prerequisites
|
|
147
|
+
|
|
148
|
+
- Emscripten SDK (`emcmake`, `emcc`)
|
|
149
|
+
- CMake >= 3.20
|
|
150
|
+
|
|
151
|
+
### Build (WASM core only)
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
scripts/build_wasm.sh
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Outputs are written to `nbimplot/wasm/`:
|
|
158
|
+
|
|
159
|
+
- `nbimplot_wasm.js`
|
|
160
|
+
- `nbimplot_wasm.wasm`
|
|
161
|
+
|
|
162
|
+
If outputs are missing or invalid, the widget reports a runtime error.
|
|
163
|
+
|
|
164
|
+
## Build with ImPlot sources
|
|
165
|
+
|
|
166
|
+
ImPlot is required for runtime. Build with Dear ImGui + ImPlot sources:
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
NBIMPLOT_WITH_IMPLOT=ON \
|
|
170
|
+
NBIMPLOT_IMGUI_DIR=/path/to/imgui \
|
|
171
|
+
NBIMPLOT_IMPLOT_DIR=/path/to/implot \
|
|
172
|
+
scripts/build_wasm.sh
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
If you cloned deps into `third_party/imgui` and `third_party/implot`, this also works:
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
NBIMPLOT_WITH_IMPLOT=ON scripts/build_wasm.sh
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Notes:
|
|
182
|
+
|
|
183
|
+
- `wasm/core/nbimplot_implot_layer.cpp` creates ImGui/ImPlot contexts when compiled with `NBIMPLOT_WITH_IMPLOT=1`.
|
|
184
|
+
- The final WebGL backend draw hookup is intentionally isolated behind the `ImPlotLayer::render(...)` seam.
|
|
185
|
+
|
|
186
|
+
## Performance behavior
|
|
187
|
+
|
|
188
|
+
- Raw rendering path when visible points `<= 3 * pixel_width`
|
|
189
|
+
- Min/max bucket LOD path when visible points `> 3 * pixel_width`
|
|
190
|
+
- LOD decision and output generation happen in WASM
|
nbimplot-0.1.0/README.md
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# nbimplot
|
|
2
|
+
|
|
3
|
+
Jupyter-native plotting focused on high interactivity and large time-series support.
|
|
4
|
+
|
|
5
|
+
Current implementation includes:
|
|
6
|
+
|
|
7
|
+
- Notebook-only widget canvas rendering
|
|
8
|
+
- Binary transport (`numpy -> bytes -> wasm memory`)
|
|
9
|
+
- WASM core for plot state, autoscale, and min/max LOD generation
|
|
10
|
+
- Strict WASM runtime requirement (JS fallback disabled)
|
|
11
|
+
- ImPlot-required mode (`prefer_implot=True`, `strict_wasm=True` only)
|
|
12
|
+
- Lifecycle-safe cleanup for repeated cell execution
|
|
13
|
+
- Subplots via `nbimplot.Subplots`
|
|
14
|
+
- Expanded primitive APIs: `scatter`, `bubbles`, `stairs`, `stems`, `digital`,
|
|
15
|
+
`bars`, `bar_groups`, `bars_h`, `shaded`, `error_bars`, `error_bars_h`,
|
|
16
|
+
`inf_lines`, `vlines`, `hlines`, `histogram`, `histogram2d`, `heatmap`,
|
|
17
|
+
`image`, `pie_chart`, `text`, `annotation`, `dummy`
|
|
18
|
+
|
|
19
|
+
## Quick start
|
|
20
|
+
|
|
21
|
+
```python
|
|
22
|
+
import numpy as np
|
|
23
|
+
import nbimplot as ip
|
|
24
|
+
|
|
25
|
+
y = np.sin(np.linspace(0, 100, 1_000_000, dtype=np.float32))
|
|
26
|
+
|
|
27
|
+
p = ip.Plot(width=900, height=450, title="Signal")
|
|
28
|
+
h = p.line("mid", y)
|
|
29
|
+
p.show()
|
|
30
|
+
|
|
31
|
+
h.set_data(y * 0.8)
|
|
32
|
+
p.render()
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## API
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
import nbimplot as ip
|
|
39
|
+
|
|
40
|
+
p = ip.Plot(width=900, height=450, title="Signal")
|
|
41
|
+
h = p.line("mid", y, x_axis="x1", y_axis="y1", subplot_index=0)
|
|
42
|
+
h.set_data(y_new)
|
|
43
|
+
p.render()
|
|
44
|
+
p.show()
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`prefer_implot=False` and `strict_wasm=False` are not supported.
|
|
48
|
+
|
|
49
|
+
Additional controls:
|
|
50
|
+
|
|
51
|
+
- `p.set_view(x_min, x_max, y_min, y_max)`
|
|
52
|
+
- `p.autoscale()`
|
|
53
|
+
- `p.set_axis_scale(x="linear|log", y="linear|log")`
|
|
54
|
+
- `p.set_plot_flags(...)` for native ImPlot flags (`no_legend`, `no_menus`, etc.)
|
|
55
|
+
- `p.set_axis_state("x2|x3|y2|y3", enabled=True|False, scale="linear|log|time")`
|
|
56
|
+
- `p.set_axis_label(...)`, `p.set_axis_format(...)`, `p.set_axis_ticks(...)`, `p.clear_axis_ticks(...)`
|
|
57
|
+
- `p.set_axis_limits_constraints(...)`, `p.set_axis_zoom_constraints(...)`, `p.set_axis_link(...)`
|
|
58
|
+
- `p.set_secondary_axes(x2=..., x3=..., y2=..., y3=...)`
|
|
59
|
+
- `p.set_time_axis("x1|x2|x3|y1|y2|y3")`
|
|
60
|
+
- `p.set_colormap("Deep|Dark|Pastel|Paired|Viridis|Plasma|Hot|Cool|Pink|Jet|Twilight|RdBu|BrBG|PiYG|Spectral|Greys")`
|
|
61
|
+
- Most primitive APIs support `x_axis="x1|x2|x3"` and `y_axis="y1|y2|y3"`
|
|
62
|
+
- `p.line(..., color=\"#3b82f6\", line_weight=2.0, marker=\"circle\", marker_size=5.0)` and `handle.set_style(...)`
|
|
63
|
+
- `p.stream_line(..., capacity=N)` and `handle.append(...)` for in-place ring-buffer style updates
|
|
64
|
+
- `p.hide_next_item()` to hide the next added series/primitive without removing it
|
|
65
|
+
- `p.heatmap(..., label_fmt="%.2f", scale_min=None, scale_max=None)` and `label_fmt=""` to hide cell-value text
|
|
66
|
+
- `p.heatmap(..., show_colorbar=True, colorbar_label="Intensity", colorbar_format="%g", colorbar_flags=0)`
|
|
67
|
+
- `p.histogram2d(..., show_colorbar=True, colorbar_label="Count", colorbar_format="%g", colorbar_flags=0)`
|
|
68
|
+
- `p.image(..., bounds=((x0, y0), (x1, y1)), uv0=(0, 0), uv1=(1, 1))` for true `ImPlot::PlotImage` rendering (`z` can be 2D grayscale or `H x W x 3/4` RGB(A))
|
|
69
|
+
- `p.tag_x(...)`, `p.tag_y(...)`, `p.colormap_slider(...)`, `p.colormap_button(...)`, `p.colormap_selector(...)`
|
|
70
|
+
- `p.drag_drop_plot(...)`, `p.drag_drop_axis(...)`, `p.drag_drop_legend(...)`
|
|
71
|
+
- `p.on_perf_stats(callback, interval_ms=500)` for live FPS/WASM timings
|
|
72
|
+
- `p.on_tool_change(callback)` for drag tool updates
|
|
73
|
+
- `p.on_selection_change(callback)` for box-selection/query updates
|
|
74
|
+
|
|
75
|
+
Interactive tools:
|
|
76
|
+
|
|
77
|
+
- `p.drag_line_x(...)`
|
|
78
|
+
- `p.drag_line_y(...)`
|
|
79
|
+
- `p.drag_point(...)`
|
|
80
|
+
- `p.drag_rect(...)`
|
|
81
|
+
|
|
82
|
+
## Subplots (Native ImPlot)
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
import nbimplot as ip
|
|
86
|
+
import numpy as np
|
|
87
|
+
|
|
88
|
+
sp = ip.Subplots(
|
|
89
|
+
2,
|
|
90
|
+
2,
|
|
91
|
+
title="Dashboard",
|
|
92
|
+
width=1000,
|
|
93
|
+
height=700,
|
|
94
|
+
link_rows=True,
|
|
95
|
+
link_cols=True,
|
|
96
|
+
share_items=True,
|
|
97
|
+
)
|
|
98
|
+
sp.subplot(0, 0).line("line", np.sin(np.linspace(0, 20, 5000, dtype=np.float32)))
|
|
99
|
+
sp.subplot(0, 1).scatter("pts", np.random.randn(2000).astype(np.float32))
|
|
100
|
+
sp.subplot(1, 0).bars("bars", np.abs(np.random.randn(120)).astype(np.float32))
|
|
101
|
+
sp.subplot(1, 1).histogram("hist", np.random.randn(20_000).astype(np.float32), bins=40)
|
|
102
|
+
sp.show()
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
`Subplots(...)` supports axis-linking controls:
|
|
106
|
+
|
|
107
|
+
- `link_rows`: link y-axis within each row
|
|
108
|
+
- `link_cols`: link x-axis within each column
|
|
109
|
+
- `link_all_x`: link x-axis for all cells
|
|
110
|
+
- `link_all_y`: link y-axis for all cells
|
|
111
|
+
- Additional compatibility flags: `share_items`, `no_legend`, `no_menus`,
|
|
112
|
+
`no_resize`, `no_align`, `col_major`
|
|
113
|
+
|
|
114
|
+
Aligned-group helper:
|
|
115
|
+
|
|
116
|
+
- `ip.AlignedPlots(rows, cols, group_id="aligned", vertical=True, ...)`
|
|
117
|
+
|
|
118
|
+
## Example Notebook
|
|
119
|
+
|
|
120
|
+
- `notebooks/nbimplot_examples.ipynb`
|
|
121
|
+
- `notebooks/nbimplot_api_gallery.ipynb`
|
|
122
|
+
- `notebooks/nbimplot_benchmarks.ipynb`
|
|
123
|
+
|
|
124
|
+
## Build WASM core
|
|
125
|
+
|
|
126
|
+
### Prerequisites
|
|
127
|
+
|
|
128
|
+
- Emscripten SDK (`emcmake`, `emcc`)
|
|
129
|
+
- CMake >= 3.20
|
|
130
|
+
|
|
131
|
+
### Build (WASM core only)
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
scripts/build_wasm.sh
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Outputs are written to `nbimplot/wasm/`:
|
|
138
|
+
|
|
139
|
+
- `nbimplot_wasm.js`
|
|
140
|
+
- `nbimplot_wasm.wasm`
|
|
141
|
+
|
|
142
|
+
If outputs are missing or invalid, the widget reports a runtime error.
|
|
143
|
+
|
|
144
|
+
## Build with ImPlot sources
|
|
145
|
+
|
|
146
|
+
ImPlot is required for runtime. Build with Dear ImGui + ImPlot sources:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
NBIMPLOT_WITH_IMPLOT=ON \
|
|
150
|
+
NBIMPLOT_IMGUI_DIR=/path/to/imgui \
|
|
151
|
+
NBIMPLOT_IMPLOT_DIR=/path/to/implot \
|
|
152
|
+
scripts/build_wasm.sh
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
If you cloned deps into `third_party/imgui` and `third_party/implot`, this also works:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
NBIMPLOT_WITH_IMPLOT=ON scripts/build_wasm.sh
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Notes:
|
|
162
|
+
|
|
163
|
+
- `wasm/core/nbimplot_implot_layer.cpp` creates ImGui/ImPlot contexts when compiled with `NBIMPLOT_WITH_IMPLOT=1`.
|
|
164
|
+
- The final WebGL backend draw hookup is intentionally isolated behind the `ImPlotLayer::render(...)` seam.
|
|
165
|
+
|
|
166
|
+
## Performance behavior
|
|
167
|
+
|
|
168
|
+
- Raw rendering path when visible points `<= 3 * pixel_width`
|
|
169
|
+
- Min/max bucket LOD path when visible points `> 3 * pixel_width`
|
|
170
|
+
- LOD decision and output generation happen in WASM
|