deckgl-marimo 0.2.0__tar.gz → 0.4.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.
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/.gitignore +4 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/PKG-INFO +138 -29
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/README.md +133 -27
- deckgl_marimo-0.4.0/docs/binary-transfer-optimization-research.md +282 -0
- deckgl_marimo-0.4.0/examples/arc_binary_compare.py +341 -0
- deckgl_marimo-0.4.0/examples/column_binary_compare.py +355 -0
- deckgl_marimo-0.4.0/examples/displacement.py +101 -0
- deckgl_marimo-0.4.0/examples/ellipse.py +103 -0
- deckgl_marimo-0.4.0/examples/generate_1m_polygons.py +77 -0
- deckgl_marimo-0.4.0/examples/line_binary_compare.py +330 -0
- deckgl_marimo-0.4.0/examples/path_binary_compare.py +374 -0
- deckgl_marimo-0.4.0/examples/pointcloud_binary_compare.py +339 -0
- deckgl_marimo-0.4.0/examples/polygon_1m_stress.py +227 -0
- deckgl_marimo-0.4.0/examples/polygon_binary_compare.py +390 -0
- deckgl_marimo-0.4.0/examples/polygon_perf.py +296 -0
- deckgl_marimo-0.4.0/examples/polygon_stress.py +261 -0
- deckgl_marimo-0.4.0/examples/scatterplot_binary_compare.py +344 -0
- deckgl_marimo-0.4.0/js/src/index.js +257 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/js/src/layer-factory.js +68 -3
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/pyproject.toml +4 -2
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/src/deckgl_marimo/__init__.py +15 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/src/deckgl_marimo/_base.py +45 -3
- deckgl_marimo-0.4.0/src/deckgl_marimo/_binary.py +168 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/src/deckgl_marimo/_map.py +42 -2
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/src/deckgl_marimo/layers/__init__.py +7 -0
- deckgl_marimo-0.4.0/src/deckgl_marimo/layers/_composite.py +411 -0
- deckgl_marimo-0.4.0/src/deckgl_marimo/layers/_core.py +1005 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/src/deckgl_marimo/static/deckgl-marimo.bundle.js +165 -165
- deckgl_marimo-0.4.0/tests/test_base_layer.py +132 -0
- deckgl_marimo-0.4.0/tests/test_binary.py +320 -0
- deckgl_marimo-0.4.0/tests/test_layers/test_composite.py +372 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/uv.lock +178 -6
- deckgl_marimo-0.2.0/examples/__marimo__/session/01_scatterplot.py.json +0 -126
- deckgl_marimo-0.2.0/examples/__marimo__/session/02_hexagon.py.json +0 -126
- deckgl_marimo-0.2.0/examples/__marimo__/session/03_geojson.py.json +0 -100
- deckgl_marimo-0.2.0/examples/__marimo__/session/04_heatmap.py.json +0 -126
- deckgl_marimo-0.2.0/examples/__marimo__/session/05_arc.py.json +0 -126
- deckgl_marimo-0.2.0/examples/__marimo__/session/06_path.py.json +0 -113
- deckgl_marimo-0.2.0/examples/__marimo__/session/07_polygon.py.json +0 -113
- deckgl_marimo-0.2.0/examples/__marimo__/session/08_column.py.json +0 -126
- deckgl_marimo-0.2.0/examples/__marimo__/session/09_icon.py.json +0 -113
- deckgl_marimo-0.2.0/examples/__marimo__/session/10_text.py.json +0 -113
- deckgl_marimo-0.2.0/examples/__marimo__/session/11_comprehensive.py.json +0 -217
- deckgl_marimo-0.2.0/examples/__marimo__/session/hexagon_example.py.json +0 -100
- deckgl_marimo-0.2.0/js/src/index.js +0 -148
- deckgl_marimo-0.2.0/src/deckgl_marimo/layers/_core.py +0 -574
- deckgl_marimo-0.2.0/tests/test_base_layer.py +0 -70
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/.github/workflows/ci.yml +0 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/.github/workflows/publish.yml +0 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/examples/01_scatterplot.py +0 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/examples/02_hexagon.py +0 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/examples/03_geojson.py +0 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/examples/04_heatmap.py +0 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/examples/05_arc.py +0 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/examples/06_path.py +0 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/examples/07_polygon.py +0 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/examples/08_column.py +0 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/examples/09_icon.py +0 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/examples/10_text.py +0 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/examples/11_comprehensive.py +0 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/examples/hexagon_example.py +0 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/js/esbuild.config.mjs +0 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/js/package-lock.json +0 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/js/package.json +0 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/js/src/accessor-resolver.js +0 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/src/deckgl_marimo/_basemaps.py +0 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/src/deckgl_marimo/_data.py +0 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/src/deckgl_marimo/_utils.py +0 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/src/deckgl_marimo/_view_state.py +0 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/src/deckgl_marimo/controls/__init__.py +0 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/src/deckgl_marimo/layers/_aggregation.py +0 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/src/deckgl_marimo/layers/_geo.py +0 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/src/deckgl_marimo/layers/_mesh.py +0 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/src/deckgl_marimo/static/deckgl-marimo.bundle.css +0 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/src/deckgl_marimo/widget.css +0 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/src/deckgl_marimo/widget.js +0 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/src/deckgl_marimo/widget.py +0 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/tests/test_data.py +0 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/tests/test_layers/__init__.py +0 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/tests/test_layers/test_aggregation.py +0 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/tests/test_layers/test_core.py +0 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/tests/test_map.py +0 -0
- {deckgl_marimo-0.2.0 → deckgl_marimo-0.4.0}/tests/test_widget.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: deckgl-marimo
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: deck.gl visualization library for marimo notebooks — interactive maps with 33 layer types
|
|
5
5
|
Project-URL: Homepage, https://github.com/kihaji/deckgl-marimo
|
|
6
6
|
Project-URL: Documentation, https://kihaji.github.io/deckgl-marimo
|
|
@@ -22,9 +22,12 @@ Classifier: Topic :: Scientific/Engineering :: GIS
|
|
|
22
22
|
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
23
23
|
Requires-Python: >=3.10
|
|
24
24
|
Requires-Dist: anywidget>=0.9.0
|
|
25
|
-
Requires-Dist: marimo>=0.
|
|
25
|
+
Requires-Dist: marimo>=0.22
|
|
26
26
|
Requires-Dist: narwhals>=1.0.0
|
|
27
|
+
Requires-Dist: pandas>=2.3.3
|
|
27
28
|
Requires-Dist: traitlets>=5.0.0
|
|
29
|
+
Provides-Extra: binary
|
|
30
|
+
Requires-Dist: numpy; extra == 'binary'
|
|
28
31
|
Provides-Extra: dev
|
|
29
32
|
Requires-Dist: duckdb; extra == 'dev'
|
|
30
33
|
Requires-Dist: geopandas; extra == 'dev'
|
|
@@ -50,11 +53,14 @@ Interactive [deck.gl](https://deck.gl) visualization library for [marimo](https:
|
|
|
50
53
|
|
|
51
54
|
## Features
|
|
52
55
|
|
|
53
|
-
- **
|
|
56
|
+
- **12 deck.gl layer types** — scatter plots, hexagonal bins, heatmaps, arcs, paths, polygons, GeoJSON, 3D columns, lines, point clouds, and more
|
|
57
|
+
- **Binary data transfer** — bypass JSON serialization for large datasets (30x faster, 4x smaller payloads)
|
|
54
58
|
- **Multi-layer maps** — compose multiple layers on a single map
|
|
55
59
|
- **Standalone layers** — display any layer directly without explicit map setup
|
|
56
60
|
- **Marimo-native reactivity** — bind layer properties to sliders, dropdowns, and other widgets
|
|
61
|
+
- **Performance metrics** — built-in FPS counter and frame time tracking via `perf_metrics` traitlet
|
|
57
62
|
- **Multiple data sources** — pandas, polars, geopandas, DuckDB, GeoJSON dicts, and URLs
|
|
63
|
+
- **Authenticated data loading** — pass HTTP headers, API keys, or credentials for remote data sources
|
|
58
64
|
- **Fully offline** — all JavaScript bundled in the package, no CDN dependencies
|
|
59
65
|
- **Viewport readback** — read the current map center, zoom, pitch, and bearing from Python
|
|
60
66
|
- **Click & hover events** — inspect picked objects reactively in downstream cells
|
|
@@ -160,30 +166,143 @@ rel = duckdb.sql("SELECT lon, lat, value FROM 'data.parquet' WHERE value > 100")
|
|
|
160
166
|
layer = dgl.ScatterplotLayer(data=rel, get_position=["lon", "lat"])
|
|
161
167
|
```
|
|
162
168
|
|
|
169
|
+
### Binary data for large datasets
|
|
170
|
+
|
|
171
|
+
For datasets with 100k+ rows, binary data transfer bypasses JSON serialization entirely, sending typed arrays directly to the GPU via deck.gl's native binary format.
|
|
172
|
+
|
|
173
|
+
**Using `use_binary=True` (automatic packing from list-of-dicts):**
|
|
174
|
+
|
|
175
|
+
```python
|
|
176
|
+
layer = dgl.ScatterplotLayer(
|
|
177
|
+
data=large_df.to_dict("records"),
|
|
178
|
+
get_position=["lon", "lat"],
|
|
179
|
+
get_fill_color="color",
|
|
180
|
+
get_radius="radius",
|
|
181
|
+
use_binary=True,
|
|
182
|
+
)
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
**Using pre-built numpy arrays (fastest — zero dict iteration):**
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
import numpy as np
|
|
189
|
+
from deckgl_marimo._binary import pack_binary
|
|
190
|
+
|
|
191
|
+
# Prepare arrays
|
|
192
|
+
positions = np.column_stack([lons, lats]).astype(np.float32)
|
|
193
|
+
colors = np.array(color_data, dtype=np.uint8) # (n, 4)
|
|
194
|
+
|
|
195
|
+
# Create layer spec (no data — binary provides it)
|
|
196
|
+
layer = dgl.ScatterplotLayer(
|
|
197
|
+
get_fill_color=[255, 140, 0], # constant props still go in spec
|
|
198
|
+
radius_min_pixels=2,
|
|
199
|
+
use_binary=True,
|
|
200
|
+
)
|
|
201
|
+
spec = layer.to_spec()
|
|
202
|
+
|
|
203
|
+
# Pack binary buffer
|
|
204
|
+
meta, buf = pack_binary(
|
|
205
|
+
n=len(positions),
|
|
206
|
+
attributes={
|
|
207
|
+
"getPosition": (positions, "float32", 2),
|
|
208
|
+
"getFillColor": (colors, "uint8", 4),
|
|
209
|
+
},
|
|
210
|
+
)
|
|
211
|
+
meta["id"] = spec["id"]
|
|
212
|
+
|
|
213
|
+
# Send to map
|
|
214
|
+
map_widget.binary_metadata = {"layers": [meta]}
|
|
215
|
+
map_widget.binary_data = buf
|
|
216
|
+
map_widget.layer_specs = [spec]
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
**Performance at 200k polygons:**
|
|
220
|
+
|
|
221
|
+
| Mode | Serialization | Payload | Speedup |
|
|
222
|
+
|------|--------------|---------|---------|
|
|
223
|
+
| JSON | 1,167 ms | 62 MB | — |
|
|
224
|
+
| Binary | 39 ms | 14.5 MB | 30x faster, 4.3x smaller |
|
|
225
|
+
|
|
226
|
+
Binary data is supported on: `ScatterplotLayer`, `PolygonLayer`, `PathLayer`, `ArcLayer`, `LineLayer`, `ColumnLayer`, and `PointCloudLayer`.
|
|
227
|
+
|
|
228
|
+
### Performance metrics
|
|
229
|
+
|
|
230
|
+
The `Map` widget includes a built-in FPS counter that reports metrics back to Python:
|
|
231
|
+
|
|
232
|
+
```python
|
|
233
|
+
map_widget = dgl.Map(basemap="dark-matter", center=(0, 0), zoom=1)
|
|
234
|
+
widget = mo.ui.anywidget(map_widget)
|
|
235
|
+
|
|
236
|
+
# Read performance metrics (updated every 500ms)
|
|
237
|
+
perf = widget.value.get("perf_metrics", {})
|
|
238
|
+
fps = perf.get("fps") # frames per second
|
|
239
|
+
frame_time = perf.get("frameTimeAvg") # ms per frame
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Authenticated remote data
|
|
243
|
+
|
|
244
|
+
Any layer that loads data from a URL supports custom HTTP headers via
|
|
245
|
+
`fetch_headers`, or full control over the fetch request via `load_options`.
|
|
246
|
+
|
|
247
|
+
```python
|
|
248
|
+
# Bearer token
|
|
249
|
+
layer = dgl.GeoJsonLayer(
|
|
250
|
+
data="https://secure-api.example.com/data.geojson",
|
|
251
|
+
fetch_headers={"Authorization": "Bearer my-token"},
|
|
252
|
+
get_fill_color=[0, 180, 230, 160],
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
# API key
|
|
256
|
+
layer = dgl.GeoJsonLayer(
|
|
257
|
+
data="https://api.example.com/features",
|
|
258
|
+
fetch_headers={"X-API-Key": "abc123"},
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
# Full fetch control (mTLS / CORS / custom options)
|
|
262
|
+
layer = dgl.GeoJsonLayer(
|
|
263
|
+
data="https://internal.example.com/data.geojson",
|
|
264
|
+
load_options={
|
|
265
|
+
"fetch": {
|
|
266
|
+
"credentials": "include",
|
|
267
|
+
"mode": "cors",
|
|
268
|
+
"headers": {"Authorization": "Bearer token"},
|
|
269
|
+
}
|
|
270
|
+
},
|
|
271
|
+
)
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
Both parameters are available on all layer types via `BaseLayer`. When
|
|
275
|
+
`fetch_headers` and `load_options` both specify headers, the `load_options`
|
|
276
|
+
headers take precedence.
|
|
277
|
+
|
|
163
278
|
## Available layers
|
|
164
279
|
|
|
165
|
-
### Fully tested (
|
|
280
|
+
### Fully tested (12)
|
|
281
|
+
|
|
282
|
+
| Layer | Use case | Binary support |
|
|
283
|
+
|-------|----------|----------------|
|
|
284
|
+
| `ScatterplotLayer` | Point data | Yes |
|
|
285
|
+
| `GeoJsonLayer` | Polygons, lines, points from GeoJSON/GeoDataFrame | — |
|
|
286
|
+
| `ArcLayer` | Origin-destination flows | Yes |
|
|
287
|
+
| `PathLayer` | Routes, trajectories | Yes |
|
|
288
|
+
| `PolygonLayer` | Filled regions | Yes |
|
|
289
|
+
| `IconLayer` | Marker icons | — |
|
|
290
|
+
| `TextLayer` | Labels | — |
|
|
291
|
+
| `ColumnLayer` | 3D bars on map | Yes |
|
|
292
|
+
| `HexagonLayer` | Hexagonal binning | — |
|
|
293
|
+
| `HeatmapLayer` | Density visualization | — |
|
|
294
|
+
| `LineLayer` | Straight lines between point pairs | Yes |
|
|
295
|
+
| `PointCloudLayer` | 3D point clouds (LiDAR, etc.) | Yes |
|
|
166
296
|
|
|
167
|
-
|
|
168
|
-
|-------|----------|
|
|
169
|
-
| `ScatterplotLayer` | Point data |
|
|
170
|
-
| `GeoJsonLayer` | Polygons, lines, points from GeoJSON/GeoDataFrame |
|
|
171
|
-
| `ArcLayer` | Origin-destination flows |
|
|
172
|
-
| `PathLayer` | Routes, trajectories |
|
|
173
|
-
| `PolygonLayer` | Filled regions |
|
|
174
|
-
| `IconLayer` | Marker icons |
|
|
175
|
-
| `TextLayer` | Labels |
|
|
176
|
-
| `ColumnLayer` | 3D bars on map |
|
|
177
|
-
| `HexagonLayer` | Hexagonal binning |
|
|
178
|
-
| `HeatmapLayer` | Density visualization |
|
|
297
|
+
`LineLayer` and `PointCloudLayer` are newly exported experimental layers.
|
|
179
298
|
|
|
180
|
-
### Experimental (
|
|
299
|
+
### Experimental (21+)
|
|
181
300
|
|
|
182
301
|
All additional deck.gl layers are available as experimental stubs via `deckgl_marimo.layers`:
|
|
183
302
|
|
|
184
303
|
```python
|
|
185
304
|
from deckgl_marimo.layers import TripsLayer, MVTLayer, H3HexagonLayer, ContourLayer
|
|
186
|
-
# ... and
|
|
305
|
+
# ... and more
|
|
187
306
|
```
|
|
188
307
|
|
|
189
308
|
## Basemaps
|
|
@@ -200,18 +319,8 @@ dgl.Map(basemap="https://my-tileserver.example.com/style.json")
|
|
|
200
319
|
|
|
201
320
|
### `Content-Length` errors in the marimo console
|
|
202
321
|
|
|
203
|
-
|
|
204
|
-
in the server console when a notebook loads. This is a known issue with uvicorn's
|
|
205
|
-
default `h11` HTTP parser serving the large JS bundle. The map still works correctly.
|
|
206
|
-
|
|
207
|
-
To suppress it, install `httptools` so uvicorn uses a faster HTTP parser, then
|
|
208
|
-
**fully restart marimo** (kill and relaunch):
|
|
322
|
+
This is fixed in Marimo >= 0.22.0 please update to that.
|
|
209
323
|
|
|
210
|
-
```bash
|
|
211
|
-
uv add httptools
|
|
212
|
-
# then restart marimo
|
|
213
|
-
uv run marimo edit your_notebook.py
|
|
214
|
-
```
|
|
215
324
|
|
|
216
325
|
## License
|
|
217
326
|
|
|
@@ -10,11 +10,14 @@ Interactive [deck.gl](https://deck.gl) visualization library for [marimo](https:
|
|
|
10
10
|
|
|
11
11
|
## Features
|
|
12
12
|
|
|
13
|
-
- **
|
|
13
|
+
- **12 deck.gl layer types** — scatter plots, hexagonal bins, heatmaps, arcs, paths, polygons, GeoJSON, 3D columns, lines, point clouds, and more
|
|
14
|
+
- **Binary data transfer** — bypass JSON serialization for large datasets (30x faster, 4x smaller payloads)
|
|
14
15
|
- **Multi-layer maps** — compose multiple layers on a single map
|
|
15
16
|
- **Standalone layers** — display any layer directly without explicit map setup
|
|
16
17
|
- **Marimo-native reactivity** — bind layer properties to sliders, dropdowns, and other widgets
|
|
18
|
+
- **Performance metrics** — built-in FPS counter and frame time tracking via `perf_metrics` traitlet
|
|
17
19
|
- **Multiple data sources** — pandas, polars, geopandas, DuckDB, GeoJSON dicts, and URLs
|
|
20
|
+
- **Authenticated data loading** — pass HTTP headers, API keys, or credentials for remote data sources
|
|
18
21
|
- **Fully offline** — all JavaScript bundled in the package, no CDN dependencies
|
|
19
22
|
- **Viewport readback** — read the current map center, zoom, pitch, and bearing from Python
|
|
20
23
|
- **Click & hover events** — inspect picked objects reactively in downstream cells
|
|
@@ -120,30 +123,143 @@ rel = duckdb.sql("SELECT lon, lat, value FROM 'data.parquet' WHERE value > 100")
|
|
|
120
123
|
layer = dgl.ScatterplotLayer(data=rel, get_position=["lon", "lat"])
|
|
121
124
|
```
|
|
122
125
|
|
|
126
|
+
### Binary data for large datasets
|
|
127
|
+
|
|
128
|
+
For datasets with 100k+ rows, binary data transfer bypasses JSON serialization entirely, sending typed arrays directly to the GPU via deck.gl's native binary format.
|
|
129
|
+
|
|
130
|
+
**Using `use_binary=True` (automatic packing from list-of-dicts):**
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
layer = dgl.ScatterplotLayer(
|
|
134
|
+
data=large_df.to_dict("records"),
|
|
135
|
+
get_position=["lon", "lat"],
|
|
136
|
+
get_fill_color="color",
|
|
137
|
+
get_radius="radius",
|
|
138
|
+
use_binary=True,
|
|
139
|
+
)
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**Using pre-built numpy arrays (fastest — zero dict iteration):**
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
import numpy as np
|
|
146
|
+
from deckgl_marimo._binary import pack_binary
|
|
147
|
+
|
|
148
|
+
# Prepare arrays
|
|
149
|
+
positions = np.column_stack([lons, lats]).astype(np.float32)
|
|
150
|
+
colors = np.array(color_data, dtype=np.uint8) # (n, 4)
|
|
151
|
+
|
|
152
|
+
# Create layer spec (no data — binary provides it)
|
|
153
|
+
layer = dgl.ScatterplotLayer(
|
|
154
|
+
get_fill_color=[255, 140, 0], # constant props still go in spec
|
|
155
|
+
radius_min_pixels=2,
|
|
156
|
+
use_binary=True,
|
|
157
|
+
)
|
|
158
|
+
spec = layer.to_spec()
|
|
159
|
+
|
|
160
|
+
# Pack binary buffer
|
|
161
|
+
meta, buf = pack_binary(
|
|
162
|
+
n=len(positions),
|
|
163
|
+
attributes={
|
|
164
|
+
"getPosition": (positions, "float32", 2),
|
|
165
|
+
"getFillColor": (colors, "uint8", 4),
|
|
166
|
+
},
|
|
167
|
+
)
|
|
168
|
+
meta["id"] = spec["id"]
|
|
169
|
+
|
|
170
|
+
# Send to map
|
|
171
|
+
map_widget.binary_metadata = {"layers": [meta]}
|
|
172
|
+
map_widget.binary_data = buf
|
|
173
|
+
map_widget.layer_specs = [spec]
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**Performance at 200k polygons:**
|
|
177
|
+
|
|
178
|
+
| Mode | Serialization | Payload | Speedup |
|
|
179
|
+
|------|--------------|---------|---------|
|
|
180
|
+
| JSON | 1,167 ms | 62 MB | — |
|
|
181
|
+
| Binary | 39 ms | 14.5 MB | 30x faster, 4.3x smaller |
|
|
182
|
+
|
|
183
|
+
Binary data is supported on: `ScatterplotLayer`, `PolygonLayer`, `PathLayer`, `ArcLayer`, `LineLayer`, `ColumnLayer`, and `PointCloudLayer`.
|
|
184
|
+
|
|
185
|
+
### Performance metrics
|
|
186
|
+
|
|
187
|
+
The `Map` widget includes a built-in FPS counter that reports metrics back to Python:
|
|
188
|
+
|
|
189
|
+
```python
|
|
190
|
+
map_widget = dgl.Map(basemap="dark-matter", center=(0, 0), zoom=1)
|
|
191
|
+
widget = mo.ui.anywidget(map_widget)
|
|
192
|
+
|
|
193
|
+
# Read performance metrics (updated every 500ms)
|
|
194
|
+
perf = widget.value.get("perf_metrics", {})
|
|
195
|
+
fps = perf.get("fps") # frames per second
|
|
196
|
+
frame_time = perf.get("frameTimeAvg") # ms per frame
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Authenticated remote data
|
|
200
|
+
|
|
201
|
+
Any layer that loads data from a URL supports custom HTTP headers via
|
|
202
|
+
`fetch_headers`, or full control over the fetch request via `load_options`.
|
|
203
|
+
|
|
204
|
+
```python
|
|
205
|
+
# Bearer token
|
|
206
|
+
layer = dgl.GeoJsonLayer(
|
|
207
|
+
data="https://secure-api.example.com/data.geojson",
|
|
208
|
+
fetch_headers={"Authorization": "Bearer my-token"},
|
|
209
|
+
get_fill_color=[0, 180, 230, 160],
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
# API key
|
|
213
|
+
layer = dgl.GeoJsonLayer(
|
|
214
|
+
data="https://api.example.com/features",
|
|
215
|
+
fetch_headers={"X-API-Key": "abc123"},
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
# Full fetch control (mTLS / CORS / custom options)
|
|
219
|
+
layer = dgl.GeoJsonLayer(
|
|
220
|
+
data="https://internal.example.com/data.geojson",
|
|
221
|
+
load_options={
|
|
222
|
+
"fetch": {
|
|
223
|
+
"credentials": "include",
|
|
224
|
+
"mode": "cors",
|
|
225
|
+
"headers": {"Authorization": "Bearer token"},
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
)
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Both parameters are available on all layer types via `BaseLayer`. When
|
|
232
|
+
`fetch_headers` and `load_options` both specify headers, the `load_options`
|
|
233
|
+
headers take precedence.
|
|
234
|
+
|
|
123
235
|
## Available layers
|
|
124
236
|
|
|
125
|
-
### Fully tested (
|
|
237
|
+
### Fully tested (12)
|
|
238
|
+
|
|
239
|
+
| Layer | Use case | Binary support |
|
|
240
|
+
|-------|----------|----------------|
|
|
241
|
+
| `ScatterplotLayer` | Point data | Yes |
|
|
242
|
+
| `GeoJsonLayer` | Polygons, lines, points from GeoJSON/GeoDataFrame | — |
|
|
243
|
+
| `ArcLayer` | Origin-destination flows | Yes |
|
|
244
|
+
| `PathLayer` | Routes, trajectories | Yes |
|
|
245
|
+
| `PolygonLayer` | Filled regions | Yes |
|
|
246
|
+
| `IconLayer` | Marker icons | — |
|
|
247
|
+
| `TextLayer` | Labels | — |
|
|
248
|
+
| `ColumnLayer` | 3D bars on map | Yes |
|
|
249
|
+
| `HexagonLayer` | Hexagonal binning | — |
|
|
250
|
+
| `HeatmapLayer` | Density visualization | — |
|
|
251
|
+
| `LineLayer` | Straight lines between point pairs | Yes |
|
|
252
|
+
| `PointCloudLayer` | 3D point clouds (LiDAR, etc.) | Yes |
|
|
126
253
|
|
|
127
|
-
|
|
128
|
-
|-------|----------|
|
|
129
|
-
| `ScatterplotLayer` | Point data |
|
|
130
|
-
| `GeoJsonLayer` | Polygons, lines, points from GeoJSON/GeoDataFrame |
|
|
131
|
-
| `ArcLayer` | Origin-destination flows |
|
|
132
|
-
| `PathLayer` | Routes, trajectories |
|
|
133
|
-
| `PolygonLayer` | Filled regions |
|
|
134
|
-
| `IconLayer` | Marker icons |
|
|
135
|
-
| `TextLayer` | Labels |
|
|
136
|
-
| `ColumnLayer` | 3D bars on map |
|
|
137
|
-
| `HexagonLayer` | Hexagonal binning |
|
|
138
|
-
| `HeatmapLayer` | Density visualization |
|
|
254
|
+
`LineLayer` and `PointCloudLayer` are newly exported experimental layers.
|
|
139
255
|
|
|
140
|
-
### Experimental (
|
|
256
|
+
### Experimental (21+)
|
|
141
257
|
|
|
142
258
|
All additional deck.gl layers are available as experimental stubs via `deckgl_marimo.layers`:
|
|
143
259
|
|
|
144
260
|
```python
|
|
145
261
|
from deckgl_marimo.layers import TripsLayer, MVTLayer, H3HexagonLayer, ContourLayer
|
|
146
|
-
# ... and
|
|
262
|
+
# ... and more
|
|
147
263
|
```
|
|
148
264
|
|
|
149
265
|
## Basemaps
|
|
@@ -160,18 +276,8 @@ dgl.Map(basemap="https://my-tileserver.example.com/style.json")
|
|
|
160
276
|
|
|
161
277
|
### `Content-Length` errors in the marimo console
|
|
162
278
|
|
|
163
|
-
|
|
164
|
-
in the server console when a notebook loads. This is a known issue with uvicorn's
|
|
165
|
-
default `h11` HTTP parser serving the large JS bundle. The map still works correctly.
|
|
166
|
-
|
|
167
|
-
To suppress it, install `httptools` so uvicorn uses a faster HTTP parser, then
|
|
168
|
-
**fully restart marimo** (kill and relaunch):
|
|
279
|
+
This is fixed in Marimo >= 0.22.0 please update to that.
|
|
169
280
|
|
|
170
|
-
```bash
|
|
171
|
-
uv add httptools
|
|
172
|
-
# then restart marimo
|
|
173
|
-
uv run marimo edit your_notebook.py
|
|
174
|
-
```
|
|
175
281
|
|
|
176
282
|
## License
|
|
177
283
|
|