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.
@@ -0,0 +1,6 @@
1
+ __pycache__/
2
+ .pytest_cache/
3
+ *.pyc
4
+ wasm/build/
5
+ nbimplot/wasm/nbimplot_wasm.js
6
+ nbimplot/wasm/nbimplot_wasm.wasm
@@ -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
@@ -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