Author and compose Mosaic clients as anywidgets.
Project description
boro
author and compose mosaic clients as anywidgets
install
uv add boro
what
mosaic is an architecture for interactive linked views over millions of rows: clients publish queries, a coordinator manages and cross-filters them against a data source (e.g., duckdb).
vgplot is how you usually author custom mosaic-based visualizations, a bundle with its own grammar and layout. boro is the same client/coordinator architecture, but each client is a standalone anywidget.
primitives
three anywidgets:
Coordinator— owns aDataSourceand the js-side mosaic engine. brokers queries over arrow ipc. headless.Selection— wraps a mosaicSelection.valuesyncs the array of clauses (sql predicates) to python.Client— base class. Requiredcoord; conventionalfilter_by(read side) andtarget(publish side) selection slots, bothboro.SelectionTrait. Subclasses can declare further selection slots withboro.SelectionTrait().
The base accepts a unified selection= shortcut covering all four shapes:
Histogram(c, ..., selection=sel) # crossfilter (both slots = sel)
Histogram(c, ..., selection=(scope, detail)) # asymmetric pair
Histogram(c, ..., selection=(sel, None)) # read-only (filter only)
Histogram(c, ..., selection=(None, sel)) # publish-only
Explicit filter_by= / target= kwargs override the shortcut.
each client is its own _esm and DOM. the mosaic engine and js deps live once,
in the coordinator; clients reach it via host.getWidget(...).
hello world
import boro
import duckdb
con = duckdb.connect()
con.execute("CREATE TABLE flights AS SELECT * FROM read_parquet('flights.parquet')")
c = boro.Coordinator.connect(con)
sel = boro.Selection.crossfilter(c)
Histogram(c, table="flights", column="delay", selection=sel)
Scatter(c, table="flights", x="distance", y="delay", selection=sel)
>>> sel.value
[{'value': [5, 30], 'sql': '"delay" BETWEEN 5 AND 30', 'meta': {...}, 'source': '...'}]
writing a client
import boro
import traitlets
class RowCounter(boro.Client):
_esm = """
export default {
async render({ model, host, signal, el }) {
el.style.cssText = "font: 14px ui-sans-serif; padding: 6px 8px;";
el.textContent = "…";
const coord = await host.getWidget(model.get("coord"));
const { Query, msql, createClient } = coord.exports;
const ctx = await createClient({ model, host, signal });
ctx.liveQuery({
filterBy: ctx.filterBy,
query: (filter) =>
Query.from(model.get("table"))
.select({ n: msql.count() })
.where(filter ?? []),
onResult: (result) => {
if (!result.isSuccess) {
return;
}
const n = Number(result.data.toColumns().n[0]);
el.textContent = `${n.toLocaleString()} rows`;
},
});
},
};
"""
table = traitlets.Unicode().tag(sync=True)
def __init__(self, coord: boro.Coordinator, table: str, **kwargs):
super().__init__(coord=coord, table=table, **kwargs)
RowCounter(c, table="flights", selection=sel)
coord.exports provides Query / msql (mosaic-sql), mc (mosaic-core), and
createClient. createClient({ model, host, signal }) returns a ctx that
exposes:
ctx.selections.<name>— resolved mosaicSelections, one perboro.SelectionTraitfield on the Python class (filter_by/targetcome from the base; subclasses can declare more).ctx.state(name, opts?)— a{get, set, subscribe}handle on a sync trait. Optional{target, clause}opts auto-derive a clause from the trait and publish it to a Selection on every change.ctx.liveQuery({ filterBy }, queryFn, onState)— registers a filter-driven query.onStatereceives{status: 'idle'|'pending'|'success'|'error', data, error}.ctx.coordinator— the mosaicCoordinatorfor one-shot ad-hoc queries (await ctx.coordinator.query(sql, { type: 'arrow' })).ctx.client,ctx.clients,ctx.signal— the synthetic primaryMosaicClient(clause source identity), theSetof all sibling clients used for cross-filter exclusion instate-derived clauses, and the abort signal scoped to this render.
example
uv run jupyterlab examples/
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file boro-0.0.0.tar.gz.
File metadata
- Download URL: boro-0.0.0.tar.gz
- Upload date:
- Size: 12.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
79b0621b125c93580de9bbf30784204b38e70a9fd883fe757f1a1560dd8df0bf
|
|
| MD5 |
af435a994b2c3001728ad79563004edb
|
|
| BLAKE2b-256 |
7b502a9cf15d0e46b3f1768b27e32e90006912f8fed6df7cef68b27cf8f6a7dd
|
File details
Details for the file boro-0.0.0-py3-none-any.whl.
File metadata
- Download URL: boro-0.0.0-py3-none-any.whl
- Upload date:
- Size: 15.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4657a987fc461998dcb52271fe374bbd7d87e15db67135a22d7e4e92d623fb8c
|
|
| MD5 |
16446d831459b60289524b4ff022c4d3
|
|
| BLAKE2b-256 |
b0d035df76979ae731ece4751b0cee8e3ccccc087d2b59dc3b3b7574a3b2969a
|