# ggplot-rs in the browser (WASM) + DuckDB-Wasm spatial
**▶ Live: <https://sipemu.github.io/ggplot-rs/>** (auto-deployed from `main`).
Two interactive dashboards, all client-side (DuckDB-Wasm with the `spatial`
extension + ggplot-rs compiled to WebAssembly):
1. **World choropleth** — DuckDB reads **Natural Earth** countries and
`ST_AsText`s the geometry to WKT; ggplot-rs renders an SVG. Hover for a
country's population; **click a country to re-query DuckDB and zoom to its
continent** (⟳ World resets).
2. **Live earthquakes** — DuckDB reads the USGS *past-30-days* GeoJSON feed and
ggplot-rs colours the quakes by magnitude; the points trace the tectonic
plate boundaries.
3. **Linked views** — a 100k-point scatter drawn by the raster (`canvas`)
backend; **drag to brush** — the selected points stay bright while the rest
fade, and a ggplot-rs bar chart updates with the per-group counts in your
selection. Two ggplot-rs plots, linked in JS.

*(The screenshot above is the exact same render, produced natively by the CLI
from the identical DuckDB query — the browser path is byte-for-byte the same
`render_svg_native`.)*
## Build & run
```sh
# 1. Build the ggplot-rs WASM bundle (needs wasm-pack + the wasm32 target)
wasm-pack build crates/ggplot-rs-wasm --target web --out-dir ../../web/pkg --out-name ggplot_rs
# 2. Serve this directory over HTTP (module workers require it)
python3 -m http.server -d web 8080
# open http://localhost:8080
```
The bundle is ~310 KB of `.wasm` (no polars, no plotters — it uses the
plotters-free `SvgBackend`). `web/pkg/` is a build artifact and is git-ignored.
## How it fits together
```
DuckDB-Wasm (data + spatial) ggplot-rs WASM (grammar + SVG)
ST_Read(...) / ST_AsText(geom) ──► render_geo({ geometry, fill, label, … })
(shapefile, GeoJSON, GeoPackage) → <svg> with <title> hover tooltips
```
`render_geo(specJson) -> String` (see `crates/ggplot-rs-wasm/src/lib.rs`) takes columnar geometry +
options and returns an SVG document. Every mark is a real DOM element, so hover
works via the native `<title>` tooltip plus a little CSS.
## Scaling to many points
SVG is great up to ~10k–50k elements. For larger data, **aggregate in DuckDB**
(`GROUP BY`, hex-binning, `ST_` clustering, sampling) before rendering — DuckDB
crunches millions of rows client-side and ggplot-rs draws the compact summary.
For raw million-point scatter, a canvas/WebGL `DrawBackend` would be the next
step (the backend trait is designed for it).
## Real data
Swap the demo query's `VALUES` for a file read:
```sql
SELECT ST_AsText(geom) AS geometry, name, pop_est
FROM ST_Read('https://.../ne_110m_admin_0_countries.geojson')
```