--- url: /mosaic/what-is-mosaic.md --- # What is Mosaic? Mosaic is a framework for linking data visualizations, tables, input widgets, and other data-driven components, while leveraging a database for scalable processing. With Mosaic, you can interactively visualize and explore millions and even billions of data points. A key idea is that interface components – Mosaic *clients* – publish their data needs as queries that are managed by a central *coordinator*. The coordinator may further optimize queries before issuing them to a backing *data source* such as [DuckDB](/duckdb/). ## Linked Interactions Mosaic supports interaction across clients through reactive variables: *params* and *selections*. *Params* represent single values that may be shared across components. When a param updates, clients that subscribe to that param will update in turn. As in the [normalized stocks example](/examples/normalize) below, params can be used in SQL expressions to create truly dynamic queries, with recalculation pushed to the database. Upon each update, data is queried from a backing DuckDB instance—here running directly in the browser via WebAssembly. *Move the cursor to see the return on investment if one had invested on a specific day.* *Selections*, on the other hand, represent filter criteria, just like a SQL `WHERE` clause. A single Mosaic selection may combine predicates provided by a variety of diverse clients. Mosaic selections can also synthesize ("resolve") different criteria for different clients, enabling complex coordination behaviors such as cross-filtering. Below is an [interactive dashboard of Seattle weather data](/examples/weather). *Drag in the top scatter plot to update a selection that filters the bar chart below. Click (or shift-click) either the color legend or the bar chart to populate a second selection that filters the scatter plot.* ## Queries & Optimization Consider some time-series data with 50,000 sample points, visualized as an area chart. *Drag along the top overview chart to filter and zoom the focus chart below.* Interaction with the top chart populates a Mosaic *selection* with the queried data range. Mosaic's *coordinator* manages access to the database, handles selection updates, and also caches results. But there's more: we don't need to draw all 50,000 points! After all, the chart itself is less than 700 pixels wide. [vgplot](/vgplot/), a Mosaic-based grammar of graphics, includes `area` and `line` marks that automatically apply optimizations to reduce the data to only a few sample points per-pixel, while preserving a perceptually faithful visualization. Next let's visualize over 200,000 flight records. The first histogram shows flight arrival delays, the second shows hour of departure. Selecting intervals in one chart will cross-filter the other. *Try selecting highly delayed flights. Note how much more likely they are to leave later in the day.* When the selection changes we need to filter the data and recount the number of records in each bin. The Mosaic coordinator analyzes these queries and automatically optimizes updates by building tables (["materialized views"](https://en.wikipedia.org/wiki/Materialized_view)) of pre-aggregated data in the database, binned at the level of input pixels for the currently active view. While 200,000 points will stress many web-based visualization tools, Mosaic doesn't break a sweat. Now go ahead and try this with [10 million records](/examples/flights-10m)! ## Putting the Pieces Together The Mosaic project consists of a suite of packages. ### Application-Level Packages * [`vgplot`](/vgplot/): A **v**isualization **g**rammar for building interactive Mosaic-powered visualizations and dashboards. This package provides an integrated API with convenient, composable methods that combine multiple Mosaic packages (core, inputs, plot, etc.). This API re-exports much of the `mosaic-core`, `mosaic-sql`, `mosaic-plot`, and `mosaic-inputs` packages, enabling use in a stand-alone fashion. * [`mosaic-spec`](/spec/): Declarative specification of Mosaic-powered applications as JSON or YAML files. This package provides a parser and code generation framework for reading specifications in a JSON format and generating live Mosaic visualizations and dashboards using the [`vgplot`](/vgplot/) API. * [`duckdb-server`](/server/): A Python-based server that runs a local DuckDB instance and supports queries over Web Sockets or HTTP, returning data in [Apache Arrow](https://arrow.apache.org/) or JSON format. * [`mosaic-widget`](/jupyter/): A Jupyter widget for Mosaic that renders vgplot specifications in Jupyter notebook cells, with data processing by DuckDB in the Python kernel. ### Core Packages * [`mosaic-core`](/core/): The core Mosaic components. A central coordinator, parameters, and selections for linking values or query predicates (respectively) across Mosaic clients. The Mosaic coordinator can send queries over the network to a backing server (`socket` and `rest` connectors) or to a client-side [DuckDB-WASM](https://duckdb.org/2021/10/29/duckdb-wasm.html) instance (`wasm` connector). The binary [Apache Arrow](https://arrow.apache.org/) format is used for efficient data transfer. * [`mosaic-sql`](/sql/): An API for convenient construction and analysis of SQL queries. Includes support for aggregate functions, window functions, and arbitrary expressions with dynamic parameters. Query objects coerce to SQL query strings. * [`mosaic-inputs`](/inputs/): Data-driven input components such as menus, text search boxes, and sortable, load-on-scroll data tables. * [`mosaic-plot`](https://github.com/uwdata/mosaic/tree/main/packages/vgplot/plot): An interactive grammar of graphics in which marks (plot layers) serve as individual Mosaic clients. Marks can push data processing (binning, filtering, aggregation, regression, ...) to the database and apply mark-specific optimizations (such as [M4](https://observablehq.com/@uwdata/m4-scalable-time-series-visualization) for line/area charts). Once data and parameters are marshalled, [Observable Plot](https://observablehq.com/plot) is used to render [SVG](https://developer.mozilla.org/en-US/docs/Web/SVG) output. This package also provides interactors for linked selection, filtering, and highlighting using Mosaic Params and Selections. ::: tip For convenience, the `vgplot` package re-exports much of the `mosaic-core`, `mosaic-sql`, `mosaic-plot`, and `mosaic-inputs` packages. For most applications, it is sufficient to either import `@uwdata/vgplot` alone or in conjunction with `@uwdata/mosaic-spec`. ::: ## An Active Research Project Mosaic is an active research project from the [UW Interactive Data Lab](https://idl.uw.edu/), in collaboration with the [CMU Data Interaction Group](https://dig.cmu.edu/). We are interested in unifying advances in scalable visualization methods with languages for interactive visualization. This is an exciting area with a number of open challenges! For more, read the [TVCG'24 Mosaic research paper](https://idl.uw.edu/papers/mosaic). There will inevitably be some shortcomings, bugs, and documentation gaps. We do not yet consider Mosaic "production-ready", but believe that Mosaic (or something like it) is a valuable next step for interactive data systems. If you're interested in contributing, please see our [GitHub repository](https://github.com/uwdata/mosaic). ## Acknowledgments Mosaic builds on code and ideas from a number of open source efforts, including [DuckDB](https://duckdb.org/), [Apache Arrow](https://arrow.apache.org/), [anywidget](https://anywidget.dev/), [Falcon](https://github.com/vega/falcon), [Vega-Lite](https://vega.github.io/vega-lite/), and [Observable Plot](https://observablehq.com/plot/). Thanks! --- --- url: /mosaic/why-mosaic.md --- # Why Mosaic? Though many expressive visualization tools exist, scalability to large datasets and interoperability across tools remain challenging. The visualization community lacks open, standardized tools for integrating visualization specifications with scalable analytic databases. While libraries like [D3](https://d3js.org) embrace Web standards for cross-tool interoperability, higher-level frameworks often make closed-world assumptions, complicating integration with other tools and environments. ## Mosaic is scalable Visualization tools such as [ggplot2](https://ggplot2.tidyverse.org/), [Vega-Lite / Altair](https://vega.github.io/vega-lite/), and [Observable Plot](https://observablehq.com/plot/) support an expressive range of visualizations with a concise syntax. However, these tools were not designed to handle millions of data points. Mosaic provides greater scalability by pushing data-heavy computation to a backing [DuckDB](/duckdb/) database. Mosaic improves performance further by caching results and, when possible, performing automatic query optimization. The figure below shows render times for static plots over increasing dataset sizes. Mosaic provides faster results, often by one or more orders of magnitude. DuckDB-WASM in the browser fares well, though is limited (compared to a DuckDB server) by WebAssembly's lack of parallel processing. [VegaFusion](https://vegafusion.io/) performs server-side optimization for *bars* and *2D histograms*, but otherwise provides results identical to Vega-Lite. When it comes to interaction, Mosaic really shines! For many forms of aggregated data, the coordinator will automatically pre-aggregate data into smaller tables ("materialized views") to support real-time interaction with billion+ element databases. The figure below shows benchmark results for optimized interactive updates. Even with billions of rows, Mosaic with a server-side DuckDB instance maintains interactive response rates. If not already present, Mosaic will build pre-aggregated data tables when the mouse cursor enters a view. For very large data sets with longer pre-aggregation times, precomputation and server-side caching are supported. Other tasks, like changing a color encoding or adjusting a smoothing parameter, can be carried out quickly in the browser alone, including over aggregated data. Mosaic clients have the flexibility of choosing what works best. ## Mosaic is interoperable Mosaic provides an open, "middle-tier" architecture that manages data access and linked selections between clients. With a shared architecture, a visualization framework can readily interoperate with other libraries, including input components and other visualization tools. We demonstrate this through the design of [vgplot](/vgplot/), a Mosaic-based grammar of interactive graphics that combines concepts from existing visualization tools. To link across views, Mosaic provides a generalized *selection* abstraction inspired by [Vega-Lite](https://vega.github.io/vega-lite/). Compared to Vega-Lite, Mosaic selections are decoupled from input event handling and support more complex resolution strategies — with computation offloaded to a backing scalable database. Importantly, Mosaic selections are first-class entities, and not internal to a single visualization language or tool. Any component that implements the Mosaic *client* interface can both issue queries and be automatically filtered by a provided *selection*. Mosaic inputs and vgplot plots can freely interact, as can any other components or visualizations (such as custom [D3](https://d3js.org) plots) that follow the Mosaic client interface. Though written in JavaScript and deployable over the Web, Mosaic was designed to work well in data science environments such as Jupyter notebooks, too. A DuckDB server can run in a host environment such as a Python kernel and communicate with a Web-based output cell interface. See the [Mosaic Jupyter Widget](/jupyter/) for more. ## Mosaic is extensible Mosaic can readily be extended with new clients, or, as in the case of [vgplot](/vgplot/), entire component libraries. Possible future additions include network visualization tools, WebGL/WebGPU enabled clients for more scalable rendering, and more! As sketched in the code below, data-consuming elements (plot layers, widgets, etc) can be realized as Mosaic clients that provide queries and accept resulting data. ```js import { MosaicClient } from '@uwdata/mosaic-core'; import { Query } from '@uwdata/mosaic-sql'; export class CustomClient extends MosaicClient { /** * Create a new client instance, with a backing table name * and an optional filterBy selection. */ constructor(tableName, filterBy) { super(filterBy); this.tableName = tableName; } /** * Return a SQL query for the client's data needs, * ideally using @uwdata/mosaic-sql query helpers. * Be sure to incorporate the given filter criteria. */ query(filter = []) { return Query .from(this.tableName) .select(/* desired columns here */) .where(filter); } /** * Process query result data. This method is called by the * coordinator to pass query results from the database. */ queryResult(data) { // visualize, analyze, ... } } ``` If you are interested in creating your own Mosaic clients, see the [Mosaic GitHub repository](https://github.com/uwdata/mosaic). For concrete examples, start with the source code of [Mosaic inputs](https://github.com/uwdata/mosaic/tree/main/packages/vgplot/inputs/src). Once you've instantiated a custom client, register it using [`coordinator.connect(client)`](/api/core/coordinator.html#connect). Mosaic can also be extended with additional database connectors, and – though not for the faint of heart! – even the central coordinator can be replaced to experiment with alternative query management and optimization schemes. --- --- url: /mosaic/get-started.md --- # Get Started Mosaic can be imported for use in JavaScript projects, leveraged within Jupyter notebooks, or deployed alongside a standalone DuckDB server. ## Use in JavaScript Include the desired Mosaic libraries in your project dependencies and import them as part of your application. For a working standalone example, take a look at the [Cross-Filter Flights 10M notebook](https://observablehq.com/@uwdata/mosaic-cross-filter-flights-10m) on Observable. The snippet below imports vgplot, configures the coordinator to use DuckDB-WASM, and creates a plot with a single `areaY` mark to produce a time-series chart for the database table `"stocks"`. To access the central coordinator, use the `coordinator()` method, which is exported by [Mosaic core](/core/) and also re-exported by [Mosaic vgplot](/vgplot/). ```js import * as vg from "@uwdata/vgplot"; // configure the coordinator to use DuckDB-WASM // creates a new database instance running in-browser vg.coordinator().databaseConnector(vg.wasmConnector()); // load data into the database // executes a query generated by the loadCSV helper vg.coordinator().exec(vg.loadCSV("stocks", "stock-data.csv")); // create an area chart, returned as an HTML element // you can subsequently add this to your webpage const chart = vg.plot( vg.areaY(vg.from("stocks"), { x: "Date", y: "Price" }) ); ``` ## Use in Python + Jupyter Mosaic ships a Python API for building interactive visualizations in Jupyter and marimo notebooks. See [Mosaic vgplot in Python](/vgplot/?lang=python) and the [Jupyter widget](/jupyter/) docs to get started. ## Deploy in Observable Framework Mosaic-powered visualizations can be in deployed dashboards or data apps published with [Observable Framework](https://observablehq.com/framework/). For guidance on deploying Mosaic and using DuckDB to prepare data, see the [Mosaic + Framework example site](https://uwdata.github.io/mosaic-framework-example). ## Use with LLMs The documentation is also available in an LLM-friendly plain-text format following the [llms.txt convention](https://llmstxt.org/). Point an AI assistant at these files, or paste their contents into a chat, to give it context about Mosaic: * [`llms.txt`](/llms.txt) — an index of the documentation with links to each page. * [`llms-full.txt`](/llms-full.txt) — the full documentation concatenated into a single file. ## Run and develop locally To run Mosaic examples on a local DuckDB server or work on Mosaic development, make a local clone of the [Mosaic GitHub repository](https://github.com/uwdata/mosaic). ### Installation For local installation you should have `pnpm` and `node` version 18 or higher. * Clone https://github.com/uwdata/mosaic. * Run `pnpm i` to install dependencies. * Run `pnpm test` to run the test suite. ### Run Examples After installation, you can run examples locally, using either DuckDB-WASM or a DuckDB server to load and process data. * Run `pnpm dev` to launch a local web server and view examples. By default, the examples use DuckDB-WASM in the browser. The `socket` and `rest` connectors will only work if a local DuckDB server is running. For greater performance, launch and connect to a local DuckDB server as described below below. To launch a local DuckDB server: * Install [hatch](https://hatch.pypa.io/latest/install/), if not already present. * Run `pnpm server` to launch the [`duckdb-server`](/server/). This runs the server in development mode, so the server will restart if you change its code. --- --- url: /mosaic/core.md --- # Mosaic Core The Mosaic `core` API includes a central *coordinator* as well as *params* and *selections* for linking values or query predicates (respectively) across Mosaic *clients*. The coordinator can send queries over the network to a backing server (`socket` and `rest` clients) or to an in-browser DuckDB-WASM instance (`wasm` client). The figure above illustrates a typical Mosaic setup. The coordinator collects queries from clients, issues them to DuckDB, and returns the results to clients. User interactions with a client can populate selections with filter clauses. Upon selection updates, the coordinator determines filter queries and updates clients with the filtered data. ## Clients Mosaic *clients* are responsible for publishing their data needs and performing data processing tasks—such as rendering a visualization—once data is provided by the coordinator. Clients typically take the form of Web (HTML/SVG) elements, but are not required to. A Web element may even consist of multiple clients, such as multiple marks (chart layers) in [vgplot](/vgplot/). Upon registration with a [`coordinator.connect(client)`](/api/core/coordinator.html#connect) call, the coordinator calls the client `fields()` method to request a list of column names and optional summary statistics. If a client does not require any field information, it can provide an empty list. The Coordinator queries the data source for requested metadata (e.g., column type) and statistics, and returns them via the client `fieldInfo()` method. Next, the coordinator calls the client `query()` method. The return value may be a SQL query string or a structured object that produces a query upon string coercion. Mosaic includes a [query builder API](/sql/) that simplifies the construction of complex queries while enabling query analysis without need of a parser. The `query` method takes a single argument: an optional `filter` predicate (akin to a SQL `WHERE` clause) indicating a data subset. The client is responsible for incorporating the filter criteria into the returned query. Before the coordinator submits a query for execution, it calls `queryPending()` to inform the client. Once query execution completes, the coordinator returns data via the client `queryResult()` method or reports an error via `queryError()`. Clients can also request queries in response to internal events. The client `requestQuery()` method issues a query to the coordinator with a guarantee that it will be evaluated. The `requestUpdate()` method makes throttled requests for a standard `query()`; multiple calls to `requestUpdate()` may result in only one query (the most recent) being serviced. Finally, clients may expose a `filterBy` Selection property. The predicates provided by `filterBy` are passed as an argument to the client `query()` method by the coordinator. [Developing Clients for Web Frameworks](/web-clients/) [Client API Reference](/api/core/client) ## Coordinator The *coordinator* is responsible for managing client data needs. Clients are registered via the coordinator `connect(client)` method, and similarly removed using `disconnect()`. Upon registration, the event lifecycle begins. In addition to the `fields` and `query` calls described above, the coordinator checks if a client exposes a `filterBy` property, and if so, adds the client to a *filter group*: a set of clients that share the same `filterBy` selection. Upon changes to this selection (e.g., due to interactions such as brushing or zooming), the coordinator collects updated queries for all corresponding clients, queries the data source, and updates clients in turn. The Coordinator additionally performs optimizations including caching and pre-aggregation. [Coordinator API Reference](/api/core/coordinator) ## Data Source The coordinator submits queries to a *data source* using an extensible set of database connectors. Mosaic uses [DuckDB](/duckdb/) as a backing database and provides connectors for communicating with a DuckDB server via Web Sockets or HTTP calls, with DuckDB-WASM in the browser, or through [Jupyter widgets](/jupyter/) to DuckDB in Python. To transfer data, Mosaic uses [Apache Arrow](https://arrow.apache.org/) for efficient serialization of query results with no subsequent parsing overhead. While the socket and HTTP connectors also support JSON, this is more costly to serialize, results in larger payloads, and must be parsed on the client side. [Connectors API Reference](/api/core/connectors) ## Params *Params* support cross-component coordination. Params are reactive variables that hold scalar values (accessible via the `value` property) and broadcast updates upon changes. Params support `value` event listeners, corresponding to value changes. Params can parameterize Mosaic clients and may be updated by input widgets or other interactors. ```js import { hconcat, slider } from "@uwdata/vgplot"; import { Param } from "@uwdata/mosaic-core"; // create a new Param const param = Param.value(5); // bind two sliders (with different ranges!) to the param hconcat( slider({ label: 'Param', min: 0, max: 10, step: 1, as: param }), slider({ min: 0, max: 15, step: 1, as: param }) ) ``` [Param API Reference](/api/core/param) ## Selections A *selection* is a specialized param that manages one or more *predicates*: Boolean-valued query expressions. Selections expose a `predicate(client)` function that takes a client as input and returns a resolved predicate for filtering the client's data. Interaction components update selections by providing a *clause*, an object consisting of the *source* component providing the clause, a set of *clients* associated with the clause, a query *predicate* (e.g, the range predicate `column BETWEEN 0 AND 1`), a corresponding *value* (e.g., the range array `[0,1]`), and an optional *schema* providing clause metadata. Upon update, any prior clause with the same *source* is removed and the new, most recent clause (called the *active* clause) is added. Selections apply a *resolution* strategy to merge clauses into client-specific predicates: * The `single` strategy simply includes only the most recent clause. * The `union` strategy performs disjunction, combining all predicates via Boolean `OR`. * The `intersect` strategy performs conjunction via Boolean `AND`. In addition, selections can be *cross-filtered*, so that they affect views other than the one currently being interacted with. The strategies above are modified to omit clauses where the *clients* set includes the input argument to the `predicate()` function. ```js import { Selection } from "@uwdata/mosaic-core"; // Create a Selection with "single" resolution strategy Selection.single() // Create a Selection with "union" resolution strategy Selection.union() // Create a Selection with "intersect" resolution strategy Selection.intersect() // A shorthand for "intersect" with cross-filtering Selection.crossfilter() // A single Selection that applies cross-filtering Selection.single({ cross: true }) ``` Selections override the `Param.value` property to return the active clause *value*, making selections compatible where standard params are expected. Like params, selections support `value` event listeners, corresponding to value changes. Selections additionally support `activate` events, which provide a clause indicative of likely future updates. For example, a brush interactor may trigger an activation event when the cursor enters a brushable region, providing an example clause prior to any actual updates. Activation events are used to implement optimizations such as prefetching. [Selection API Reference](/api/core/selection) --- --- url: /mosaic/sql.md --- # Mosaic SQL The Mosaic `sql` package supports authoring of SQL queries. These utilities are used throughout Mosaic packages to build structured queries and perform query analysis. ## Query Use the `Query` class to build complete SQL queries. Upon string coercion, the resulting object produces a query string. ```js import { Query } from "@uwdata/mosaic-sql"; // SELECT foo AS a, bar AS b FROM table Query.from("table").select({ a: "foo", b: "bar" }) ``` The `Query` class supports a rich set of SQL features, including subqueries (by passing queries as arguments to `from()`) and [common table expressions](https://duckdb.org/docs/sql/query_syntax/with.html) (via the `with()` method). Here is a run down of the available methods: ```js Query .with(/* a map of named common table expression queries */) .select(/* column names or name -> expression maps */) .distinct(/* boolean to denote distinct values only */) .from(/* source table names or subqueries */) .sample(/* number of rows or % to sample */) .where(/* filter criteria */) .groupby(/* columns or expressions to group by */) .having(/* post-aggregation filter criteria */) .window(/* named window definitions */) .qualify(/* post-window filter criteria */) .orderby(/* columns or expressions to sort by */) .limit(/* max number of rows */) .offset(/* offset number of rows */) ``` Use `pivot()` to create DuckDB [`PIVOT`](https://duckdb.org/docs/sql/statements/pivot.html#simplified-pivot-syntax) queries using simplified syntax: ```js import { Query, sum } from "@uwdata/mosaic-sql"; // PIVOT "sales" ON "year" IN (2020, 2021) USING sum("amount") AS "total" GROUP BY "region" Query .pivot("sales") .on("year") .in(2020, 2021) .using({ total: sum("amount") }) .groupby("region") ``` [Query API Reference](/api/sql/queries) ## Operators The Mosaic SQL package includes operators for manipulating and comparing values: * Logical operators: `and`, `or`, `not` * Comparison operators: `eq`, `neq`, `lt`, `gt`, `lte`, `gte` * Range operators: `isBetween`, `isNotBetween` * Set operators: `isIn` * List operators: `listContains`, `listHasAll`, `listHasAny` * Null checks: `isNull`, `isNotNull` * Null-sensitive comparison: `isDistinct`, `isNotDistinct` * Arithmetic operators: `add`, `sub`, `mul`, `div`, `idiv`, `mod`, `pow` * Bitwise operators: `bitNot`, `bitAnd`, `bitOr`, `bitLeft`, `bitRight` * Conditionals: `cond` * Unnest: `unnest` When given a string input, an operator function interprets it as a column name. For example, to create a simple range query: ```js import { Query, and, count, isBetween } from "@uwdata/mosaic-sql"; Query .from("myTable") .select({ count: count() }) .where(and(isBetween("foo", [10, 50]), isBetween("bar", [-5, 10]))) ``` [Operator API Reference](/api/sql/operators) ## Aggregate Functions DuckDB-supported [aggregate functions](https://duckdb.org/docs/sql/aggregates.html), including `min`, `max`, `count`, `sum`, `avg`, `stddev`, `median`, `quantile`, `argmax`, `argmin`, `corr`, and others. ```js import { Query, max, min, quantile } from "@uwdata/mosaic-sql"; // get min/max, median, and interquartile range Query.select({ min: min("foo"), q25: quantile("foo", 0.25), q50: quantile("foo", 0.50), q75: quantile("foo", 0.75), max: max("foo"), }).from("myTable"); ``` [Aggregate Functions API Reference](/api/sql/aggregate-functions) ## Window Functions General purpose [window functions](https://duckdb.org/docs/sql/window_functions) include `row_number`, `rank`, `cume_dist`, `lag`, `lead`, *etc*. Aggregate functions become window operations (such as cumulative sums or moving averages) if you define the parameters `orderby`, `partitionby`, or the window frame specifiers `rows` or `range`. ```js import { Query, row_number, avg } from "@uwdata/mosaic-sql"; // 7-day moving average (previous and next 3 days) // and corresponding ordered row numbers Query.select({ avg: avg("foo").orderby("date").rows([3, 3]), num: row_number().orderby("date") }).from("myTable"); ``` [Window Functions API Reference](/api/sql/window-functions) ## SQL Expressions When deeper analysis is not needed, the `sql` template literal can be used to build individual SQL expressions using custom text. ```js import { Query, sql } from "@uwdata/mosaic-sql"; Query .select({ logFoo: sql`log(foo + 1)` }) .from("myTable"); ``` Interpolated values may include column references, nested expressions, or params. Referenced columns or params can later be extracted using SQL expression visitors. ```js import { Param } from "@uwdata/core"; import { collectColumns, collectParams, column, sql } from "@uwdata/mosaic-sql"; const col = column("foo"); const param = Param.value(Math.PI); const expr = sql`${col} * ${param}`; const cols = collectColumns(expr); // -> [ col ] const params = collectParams(expr): // -> [ param ] ``` [Expression API Reference](/api/sql/expressions) ## Data Loading Data loading helpers generate query strings for loading data from external CSV, JSON, or Parquet files: `loadCSV`, `loadJSON`, `loadParquet`. ```js import { loadCSV, loadParquet } from "@uwdata/mosaic-sql"; // Loads file.csv into the table "table1" with default options: // CREATE TABLE IF NOT EXISTS table1 AS // SELECT * // FROM read_csv('file.csv', auto_detect=true, sample_size=-1) const q1 = loadCSV("table1", "file.csv"); // Load named columns from a parquet file, filtered upon load: // CREATE TABLE IF NOT EXISTS table2 AS // SELECT foo, bar, value // FROM read_parquet('file.parquet') // WHERE value > 1 const q2 = loadParquet("table2", "file.parquet", { select: [ "foo", "bar", "value" ], where: "value > 1" }); ``` Meanwhile, the `loadObjects` method takes an array of JavaScript objects and generates a query to insert those values into a database table. ```js import { loadObjects } from "@uwdata/mosaic-sql"; // CREATE TABLE IF NOT EXISTS table3 AS // (SELECT 1 AS "foo", 2 AS "bar") UNION ALL // (SELECT 3 AS "foo", 4 AS "bar") UNION ALL ... const q = loadObjects("table3", [ { foo: 1, bar: 2 }, { foo: 3, bar: 4 }, ... ]); ``` [Data Loading API Reference](/api/sql/data-loading) --- --- url: /mosaic/inputs.md --- # Mosaic Inputs Inspired by [Observable Inputs](https://observablehq.com/@observablehq/inputs), the Mosaic `inputs` package includes a set of input widgets and a table viewer. Each input widget is a Mosaic client that uses params or selections for linked interactions. This example dashboard of Olympic athlete statistics uses `menu` and `search` inputs to filter the display, including the scrollable and sortable `table` below. The contents of the menus and the autocomplete options for the search box are populated from the backing database. Each of these widgets then populate a shared selection. *Scroll the table to load more data on demand.Click a column header to sort, or command-click to clear sort criteria.* ## Slider, Menu, and Search The [`menu`](/api/inputs/menu), [`search`](/api/inputs/search), and [`slider`](/api/inputs/slider) inputs support dual modes of operation: they can be manually configured or they can be backed by a database table. The `menu` and `search` components query for distinct column values, and use those to populate the menu or autocomplete options, respectively. If a backing table and column are specified, the `slider` queries for the minimum and maximum column values to parameterize the slider. This snippet defines the menus and search box in the example above: ```js import { hconcat, menu, search, Selection } from "@uwdata/vgplot"; const query = Selection.intersect(); hconcat( menu({ label: "Sport", as: query, from: "athletes", column: "sport" }), menu({ label: "Sex", as: query, from: "athletes", column: "sex" }), search({ label: "Name", as: query, from: "athletes", column: "name", type: "contains" }) ) ``` All input widgets can write updates to a provided param or selection. Param values are updated to match the input value. Selections are provided a predicate clause. This linking can be bidirectional: an input component will also subscribe to a param and track its value updates. Two-way linking is also supported for selections using *single* resolution, where there is no ambiguity regarding the value. * [Menu API Reference](/api/inputs/menu) * [Search API Reference](/api/inputs/search) * [Slider API Reference](/api/inputs/slider) ## Table The `table` component provides a sortable, scrollable table grid view. If backing columns are specified, the table first requests metadata for those columns. If no explicit columns are listed, the component will instead request *all* backing table columns. The returned metadata is used to populate the table header and guide formatting and alignment. This snippet shows how the table is defined in the example above. In this case, explicit column names and column pixel widths are provided. ```js import { table } from "@uwdata/vgplot"; table({ from: "athletes", filterBy: query, columns: [ "name", "nationality", "sex", "height", "weight" ,"sport" ], width: { "name": 180, "nationality": 100, "sex": 50, "height": 50, "weight": 50, "sport": 100 }, height: 250 }) ``` To avoid overwhelming the browser, the table query method requests rows in batches using SQL `LIMIT` and `OFFSET` clauses. As a user scrolls the table view, the component requests the next data batch with the proper offset. Table components are sortable: clicking a column header toggles ascending and descending order. When sort criteria change, the current data is dropped and a request is made to fetch a sorted data batch. As a user scrolls, these sort criteria persist. If provided, a `filterBy` Selection is used to filter table content. [Table API Reference](/api/inputs/table) --- --- url: /mosaic/vgplot.md --- **(begin JavaScript API)** A grammar of interactive graphics in which graphical marks are Mosaic clients. As the name suggests, `vgplot` combines concepts from existing tools such as Vega-Lite, ggplot2, and Observable Plot. Like Vega-Lite, vgplot supports rich interactions and declarative specification either using an API or standalone JSON/YAML specs (via the [`mosaic-spec`](/spec/) package). However, because vgplot is based on Mosaic, it interoperates with other Mosaic clients, such as the included [Mosaic Inputs](/inputs/). vgplot calls Observable Plot to render SVG output. This page provides an overview of vgplot. Skip to the [examples](/examples/) to dive right in. ::: tip `vgplot` re-exports much of the `mosaic-core`, `mosaic-sql`, `mosaic-plot`, and `mosaic-inputs` packages. For many applications, it is sufficient to import `@uwdata/vgplot` alone. ::: ## Plots A `plot` produces a single visualization as a Web element. A `plot` is defined as a list of directives defining plot [attributes](#attributes), [marks](#marks), [interactors](#interactors), or [legends](#legends). Similar to other grammars, a `plot` consists of *marks*—graphical primitives such as bars, areas, and lines—which serve as chart layers. We use the semantics of Observable Plot, such that each `plot` has a dedicated set of encoding *channels* with named *scale* mappings such as `x`, `y`, `color`, `opacity`, etc. Plots support faceting of the `x` and `y` dimensions, producing associated `fx` and `fy` scales. Plots are rendered to SVG output by marshalling a specification and passing it to Observable Plot. ::: code-group ```js [JavaScript] import { plot, lineY, from, width, height } from "@uwdata/vgplot"; plot( lineY(from("aapl"), { x: "Date", y: "Close" }), width(680), height(200) ) ``` ```yaml [YAML] plot: - mark: lineY data: { from: aapl } x: Date y: Close width: 680 height: 200 ``` ::: The stock chart above consists of three directives: 1. A `lineY` mark to visualize data from a backing data table named `"aapl"`. 2. A `width` attribute to set the chart width in pixels. 3. A `height` attribute to set the chart height in pixels. [Plot API Reference](/api/vgplot/plot) ## Attributes *Attributes* are plot-level settings such as `width`, `height`, margins, and scale options (e.g., `xDomain`, `colorRange`, `yTickFormat`). Attributes may be [`Param`](/core/#params)-valued, in which case a plot updates upon param changes. vgplot includes a special `Fixed` scale domain setting (e.g., `xDomain(Fixed)`), which instructs a plot to first calculate a scale domain in a data-driven manner, but then keep that domain fixed across subsequent updates. Fixed domains enable stable configurations without requiring a hard-wired domain to be known in advance, preventing disorienting scale domain "jumps" that hamper comparison across filter interactions. [Attributes API Reference](/api/vgplot/attributes) ## Marks *Marks* are graphical primitives, often with accompanying data transforms, that serve as chart layers. In vgplot, each mark is a Mosaic client that produces queries for needed data. Marks accept a data source definition and a set of supported options, including encoding *channels* (such as `x`, `y`, `fill`, and `stroke`) that can encode data *fields*. A data field may be a column reference or query expression, including dynamic param values. Common expressions include aggregates (`count`, `sum`, `avg`, `median`, *etc.*), window functions (such as [moving averages](/examples/moving-average)), date functions, and a `bin` transform. Most field expressions—including aggregate, window, and date functions—are specified using [Mosaic SQL](/sql/) builder methods. Marks support dual modes of operation: if an explicit array of data values is provided instead of a backing `from(tableName)` reference, vgplot will visualize that data without issuing any queries to the database. This functionality is particularly useful for adding manual annotations, such as custom rules or text labels. [Marks API Reference](/api/vgplot/marks) ::: warning Interactive filtering is not supported if you bypass the database and pass data directly to a mark. ::: ### Basic Marks Basic marks, such as `dot`, `bar`, `rect`, `cell`, `text`, `tick`, and `rule`, mirror their namesakes in [Observable Plot](https://observablehq.com/plot/). Variants such as `barX` and `rectY` indicate spatial orientation and data type assumptions. `barY` indicates vertical bars—continuous `y` over an ordinal `x` domain—whereas `rectY` indicates a continuous `x` domain. Basic marks follow a straightforward query construction process: * Iterate over all encoding channels to build a `SELECT` query. * If no aggregates are encountered, query all fields directly. * If aggregates are present, include non-aggregate fields as `GROUP BY` criteria. * If provided, map filtering criteria to a SQL `WHERE` clause. ### Connected Marks The `area` and `line` marks connect consecutive sample points. Connected marks are treated similarly to basic marks, with one notable addition: the queries for spatially oriented marks (`areaY`, `lineX`) can apply [M4 optimization](https://observablehq.com/@uwdata/m4-scalable-time-series-visualization). The query construction method uses plot width and data min/max information to determine the pixel resolution of the mark range. When the data points outnumber available pixels, M4 performs perceptually faithful pixel-aware binning of the series, limiting the number of drawn points. This optimization offers dramatic data reductions for both single and multiple series. Separately, vgplot includes a `regressionY` mark for linear regression fits. Regression calculations and associated statistics are performed in-database in a single aggregate query. The mark then draws the regression line and optional confidence interval area. ### Geography and Geometry The `geo` mark visualizes geometry data, such as geographic regions, in GeoJSON format. An array of GeoJSON features can be provided directly as data, or geographic data can be loaded and queried directly in database using the DuckDB `spatial` extension. ### Density Marks The `densityY` mark performs 1D kernel density estimation (KDE). The `densityY` mark defaults to areas, but supports a `type` option to instead use lines, points, or other basic marks. The generated query performs *linear binning*, an alternative to standard binning that proportionally distributes the weight of a point between adjacent bins to provide greater accuracy for density estimation. The query uses subqueries for the "left" and "right" bins, then aggregates the results. The query result is a 1D grid of binned values which are then smoothed. As smoothing is performed in the browser, interactive bandwidth updates are processed immediately. The `density`, `contour`, `heatmap`, and `raster` marks compute densities over a 2D domain using either linear (default) or standard binning. Smoothing again is performed in browser; setting the `bandwidth` option to zero disables smoothing. The `contour` mark then performs contour generation, whereas the `raster` mark generates a colored bitmap. The `heatmap` mark is a convenient shortcut for a `raster` that performs smoothing by default. Dynamic changes of bandwidth, contour thresholds, and color scales are handled immediately in browser. The `hexbin` mark pushes hexagonal binning and aggregation to the database. Color and size channels may be mapped to `count` or other aggregates. Hexagon plotting symbols can be replaced by other basic marks (such as `text`) via the `type` option. The `denseLine` mark creates a density map of line segments, rather than points. Line density estimation is pushed to the database. To ensure that steep lines are not over-represented, we approximate arc-length normalization for each segment by normalizing by the number of filled raster cells on a per-column basis. We then aggregate the resulting weights for all series to produce the line densities. ## Interactors *Interactors* imbue plots with interactive behavior. Most interactors listen to input events from rendered plot SVG elements to update bound [*selections*](/core/#selections). Interactors take facets into account to properly handle input events across subplots. The `toggle` interactor selects individual points (e.g., by click or shift-click) and generates a selection clause over specified fields of those points. Directives such as `toggleColor`, `toggleX`, and `toggleY` simplify specification of which channel fields are included in the resulting predicates. The `nearestX` and `nearestY` interactors select the nearest value along the `x` or `y` encoding channel. The `intervalX` and `intervalY` interactors create 1D interval brushes. The `intervalXY` interactor creates a 2D brush. Interval interactors accept a `pixelSize` parameter that sets the brush resolution: values may snap to a grid whose bins are larger than screen pixels and this can be leveraged to optimize query latency. The `panZoom` interactor produces interval selections over corresponding `x` or `y` scale domains. Setting these selections to a plot's `xDomain` and/or `yDomain` attributes will cause the plot to pan and zoom in response. The `highlight` interactor updates the rendered state of a visualization in response to a Selection. Non-selected points are set to translucent, neutral gray, or other specified visual properties. Selected points maintain normal encodings. We perform highlighting by querying the database for a selection bit vector and then modifying the rendered SVG. [Interactors API Reference](/api/vgplot/interactors) ## Legends *Legends* can be added to `plot` specifications or included as standalone elements. The `name` directive gives a `plot` a unique name. A standalone legend can reference a named plot (`colorLegend({ for: 'name' })`) to avoid respecifying scale domains and ranges. Legends also act as interactors, taking a bound Selection as a parameter. For example, discrete legends use the logic of the `toggle` interactor to enable point selections. Two-way binding is supported for Selections using *single* resolution, enabling legends and other interactors to share state. [Legends API Reference](/api/vgplot/legends) ## Layout Layout helpers combine elements such as [plots](#plots) and [inputs](/inputs/) into multi-view dashboard displays. vgplot includes `vconcat` (vertical concatenation) and `hconcat` (horizontal concatenation) methods for multi-view layout. These methods accept a list of elements and position them using CSS `flexbox` layout. Layout helpers can be used with plots, inputs, and arbitrary Web content such as images and videos. To ensure spacing, the `vspace` and `hspace` helpers add padding between elements in a layout. [Layout API Reference](/api/vgplot/layout) **(end JavaScript API)** **(begin Python API)** A grammar of interactive graphics in which graphical marks are Mosaic clients. In Python, `import vgplot as vg` gives you composable helpers for plots, attributes, marks, interactors, legends, and layout. Names use **`snake_case`**. Key Python-specific conventions: use `vg.source("table")` (not `from_`) to reference a named database table; interactors take `bind=` (not `as=`) for their selection; legends take `plot=` (not `for`) to reference a named plot. The interactive figure above is driven by the same [declarative specification](/spec/) used across Mosaic (YAML in the docs site). In notebooks you usually pass an equivalent structure as a dict—built with `vg.*` helpers, loaded from YAML/JSON, or produced by your own tooling—to [`MosaicWidget`](/jupyter/) as `spec`. More copy-paste examples live under [Examples](/examples/) (open the **Python** tab on each page). ::: tip The fastest path in Jupyter is often YAML or JSON plus `MosaicWidget(spec=..., data=...)`. Use `vgplot` when you want to assemble or adjust specs in code. Option names match the [specification format](/api/spec/format); builder helpers line up with those names in snake\_case. ::: ## Plots `vg.plot` takes a sequence of directives: [attributes](#attributes), [marks](#marks), [interactors](#interactors), and [legends](#legends). Each plot uses [Observable Plot](https://observablehq.com/plot/)–style *channels* (`x`, `y`, `fill`, `opacity`, …) and optional faceting scales `fx` and `fy`. The widget renders charts in the browser as SVG. ```python import vgplot as vg vg.plot( vg.line_y(vg.source("aapl"), x="Date", y="Close"), vg.width(680), vg.height(200) ) ``` This chart uses three directives: 1. A `line_y` mark with `vg.source("aapl")`. 2. `vg.width(680)`. 3. `vg.height(200)`. [Plot reference](/api/vgplot/plot) ## Attributes *Attributes* set plot-level options: size, margins, and scales (`x_domain`, `color_range`, `y_tick_format`, …) via helpers such as `vg.x_domain(...)`, `vg.color_range(...)`, `vg.y_tick_format(...)`. Param references like `"$point"` tie encodings to widget state. **`"Fixed"`** domains (e.g. `vg.x_domain("Fixed")`) compute an initial domain from data, then freeze it so filtered views do not rescale in a distracting way. [Attributes reference](/api/vgplot/attributes) ## Marks *Marks* are layers backed by Mosaic queries. They usually take a `vg.source("table")` reference (or a `DataDef` from `vg.parquet()`, `vg.csv()`, etc.) as the first argument, plus channel options. Fields may be columns, SQL fragments, or param strings. You can pass static rows instead of a database source for annotations; that path skips the database and does not participate in linked filtering. [Marks reference](/api/vgplot/marks) ::: warning Interactive filtering requires data that flows through the coordinator (via `vg.source()` / registered tables), not ad hoc Python lists alone. ::: ### Basic marks Primitives include `dot`, `bar`, `rect`, `cell`, `text`, `tick`, and `rule`, consistent with Observable Plot. Oriented variants appear as `bar_x`, `bar_y`, `rect_x`, `rect_y`, and so on—the YAML `mark` string (e.g. `barY`) corresponds to `vg.bar_y(...)`. Query planning walks channels to build `SELECT`, adds `GROUP BY` when aggregates appear, and applies `WHERE` for active selections. ### Connected marks `area` and `line` marks connect ordered samples (`vg.area_y`, `vg.line_y`, …). Large series can use M4-style pixel-aware downsampling so draw cost stays bounded. `regression_y` computes fits and optional intervals in the database, then draws the line and band. ### Geography and geometry `geo` draws GeoJSON geometry, either inlined or loaded through DuckDB (including the `spatial` extension). ### Density marks `density_y` is 1D KDE. `density`, `contour`, `heatmap`, and `raster` cover 2D surfaces; `hexbin` aggregates hex cells in SQL; `dense_line` estimates density along polylines. Bandwidth and smoothing options follow the declarative spec. ## Interactors *Interactors* connect pointer input to [*selections*](/core/#selections). Helpers include `toggle`, `toggle_color`, `toggle_x`, `toggle_y`, `nearest_x`, `nearest_y`, `interval_x`, `interval_y`, `interval_xy` (with `pixel_size` where applicable), `pan_zoom`, and `highlight`. Wiring `pan_zoom` selections into `x_domain` / `y_domain` (or equivalent scale bindings) implements pan and zoom. [Interactors reference](/api/vgplot/interactors) ## Legends Legends attach inside `vg.plot` or as separate elements. Naming a plot lets another legend reuse its scales, e.g. `vg.color_legend(plot="my_plot")`. Discrete color legends can drive the same toggle-style selection behavior as point interactors. [Legends reference](/api/vgplot/legends) ## Layout `vg.vconcat`, `vg.hconcat`, `vg.vspace`, and `vg.hspace` compose plots, [inputs](/inputs/), and spacing. The runtime lays out children with flexbox. Full apps often call `vg.spec(meta=..., data=..., params=..., view=...)` so the result is a single top-level spec object (the same shape as JSON/YAML on disk). [Layout reference](/api/vgplot/layout) ## Related documentation * [Mosaic spec](/spec/) — portable JSON/YAML format shared by Python and the docs examples. * [Specification format reference](/api/spec/format) — schema-oriented description of top-level keys and marks. * [vgplot under **API Reference**](/api/) — detailed plot, mark, interactor, and layout pages. Option names there appear in **camelCase** (e.g. `lineY`, `xDomain`); in Python, use **snake\_case** (`line_y`, `x_domain`). **(end Python API)** --- --- url: /mosaic/spec.md --- # Mosaic Declarative Specifications The `mosaic-spec` package enables declarative specification of Mosaic applications as JSON or YAML files. The package provides a specification parser, as well as generators to create either running applications or JavaScript code. For example, below is an example of a declarative specification, in either YAML or equivalent JSON, for a simple line chart. The JavaScript and Python tabs show equivalent code that builds the same specification using the [`vgplot`](/vgplot/) API in each language. ```py \[Python] import vgplot as vg aapl = vg.parquet("data/stocks.parquet", where="Symbol = 'AAPL'") view = vg.plot( vg.line_y(aapl, x="Date", y="Close"), vg.width(680), vg.height(200), ) ``` Using a declarative specification, we can describe an application in a standard file format, enabling portability across platforms. The same spec can be authored as YAML/JSON or built programmatically with the `vgplot` API in either JavaScript or Python (see the [Python API](/vgplot/?lang=python)). For example, the [Mosaic Jupyter widget](/jupyter/) uses this format to pass visualization and dashboard definitions from Python to the browser. ::: tip The [TypeScript types in the `@uwdata/mosaic-spec` package](https://github.com/uwdata/mosaic/tree/main/packages/vgplot/spec/src/spec) provide comprehensive documentation of Mosaic declarative specifications. ::: ## Specification Format Here is a slightly more complicated example, in which a dynamic `Param` value is added to the data before visualizing it. ```py \[Python] import vgplot as vg walk = vg.parquet("data/random-walk.parquet") point = vg.param(0) view = vg.vconcat( vg.slider(label="Bias", bind=point, min=0, max=1000, step=1), vg.plot( vg.area_y(walk, x="t", y=vg.sql("v + $point"), fill="steelblue"), vg.width(680), vg.height(200), ), ) ``` The example above includes descriptive metadata, `data` and `params` definitions, and nested components: an input `slider` and `plot` are positioned using a `vconcat` layout. The `plot` uses a SQL expression that includes a `Param` reference (`$point`) to define a dynamic `y` encoding channel. A declarative specification may include top-level definitions for: * `meta`: Metadata such as a title and description. * `config`: Configuration settings, such as database extensions to load. * `data`: Dataset definitions, such as files, queries, or inline data. * `params`: Param & Selection definitions. All later Param references use a `$` prefix. * `plotDefaults`: Default plot attributes to apply to all plot instances. The rest of the spec consists of component definitions supported by the [`vgplot`](/vgplot/) API, including plots, inputs, and layout components. For more, see the [Specification Format Reference](/api/spec/format). ## Parser & Generators Format The `parseSpec()` method parses a specification in JSON format into an *abstract syntax tree* (AST): a structured representation of the specification content that is more convenient to analyze and manipulate. Given a parsed AST, the generator method `astToDOM()` instantiates a running web application, returning Mosaic-backed Document Object Model (DOM) elements that can be added to a web page. Meanwhile, the `astToESM()` method instead generates JavaScript code, in the form of an ECMAScript Module (ESM), that uses the `vgplot` API. The JavaScript code listed in the examples above was generated using this method, and `astToPython()` similarly generates equivalent Python code for the [`vgplot` Python API](/vgplot/?lang=python). For more, see the [Specification Parser & Generators Reference](/api/spec/parser-generators). --- --- url: /mosaic/server.md --- # Mosaic DuckDB Server The Mosaic `duckdb-server` package provides a Python-based server that runs a local DuckDB instance and support queries over Web Sockets or HTTP, returning data in either [Apache Arrow](https://arrow.apache.org/) or JSON format. ::: tip This package provides a local DuckDB server. To instead use DuckDB-WASM in the browser, use the `wasmConnector` from the [`mosaic-core`](/core/) package. ::: ::: info DuckDB can also connect to and query other databases, such as PostgreSQL and MySQL. See the [multi-database support page](/api/core/multi-database-support) for examples. ::: ## Usage The server package is available on [PyPi](https://pypi.org/project/duckdb-server/). We recommend running the server in an isolated environment with [pipx](https://github.com/pypa/pipx). For example, to directly run the server, use: ```bash pipx run duckdb-server ``` Alternatively, you can install the server with `pip install duckdb-server`. Then you can start the server with `duckdb-server`. ## Developer Setup To run the server from the Mosaic repository and to run the server in development mode, follow the [instructions for the duckdb-server package](https://github.com/uwdata/mosaic/blob/main/packages/server/duckdb-server/README.md). --- --- url: /mosaic/jupyter.md --- # Mosaic Jupyter Widget The Mosaic `widget` package provides a Jupyter widget for creating interactive Mosaic plots over Pandas and Polars data frames or DuckDB connections. ## Installation Install the widget with `pip install mosaic-widget`. Then you can import it in Jupyter with `import mosaic_widget`. The PyPI package is at https://pypi.org/project/mosaic-widget/. The widget also works in [Google Colab](https://colab.research.google.com/drive/1Txy6L_of8_lJFImKEkhUCqZX70yKpYnv#scrollTo=leuzblN47K-T\&line=1\&uniqifier=1). ## Using the Widget After importing the widget with ```python from mosaic_widget import MosaicWidget ``` you can initialize and show the widget with ```python widget = MosaicWidget() widget ``` The widget constructor take three arguments which are all optional. * `spec`, a Mosaic specification as a dictionary. This argument is optional and can be set later via the `spec` traitlet. * `con`, a DuckDB connection. If `None`, the widget will create a connection to an in-memory database. * `data`, a dictionary of data frames that should be added to the database connection. The keys of the dictionary are the table names. A widget has a `spec` traitlet that can be used to set the Mosaic specification. A widget automatically updates when the specification changes. A widget also has a `params` traitlet, which updates automatically with params in the widget. The params are a dictionary from parameter name to the current `value` of the parameter and the `predicate` which can be used as the WHERE clause in a SQL query. ## Example In this example, we create a Mosaic plot over the Seattle weather dataset. This will render [an interactive view of Seattle’s weather, including maximum temperature, amount of precipitation, and type of weather](/examples/weather.html). You can try a live example on [Google Colab](https://colab.research.google.com/drive/1Txy6L_of8_lJFImKEkhUCqZX70yKpYnv#scrollTo=leuzblN47K-T\&line=1\&uniqifier=1). ### Building a spec with the vgplot Python API The [`vgplot` Python API](/vgplot/?lang=python) lets you build the specification programmatically instead of loading a YAML/JSON file. Load your data — a Polars or Pandas DataFrame (`pl.read_csv`), or a file source with `vg.csv(...)` / `vg.parquet(...)` — assign it to a variable, and pass that variable straight to a mark. It's picked up by its variable name (an in-memory DataFrame is registered as a table, a file source is inlined), so you can hand the view straight to `MosaicWidget` with no separate `data` argument: ```python import polars as pl import vgplot as vg from mosaic_widget import MosaicWidget weather = pl.read_csv( "https://uwdata.github.io/mosaic-datasets/data/seattle-weather.csv", try_parse_dates=True, ) view = vg.plot( vg.dot( weather, x=vg.date_month_day("date"), y="temp_max", fill="weather", r="precipitation", fill_opacity=0.7, ), vg.x_tick_format("%b"), vg.width(680), vg.height(300), ) MosaicWidget(view) ``` To register the data yourself instead, pass `data={"weather": weather}` to `MosaicWidget` and reference the table from a mark with `vg.source("weather")`. ### Loading a YAML/JSON spec Alternatively, load an existing declarative specification and pass it to the widget as a dictionary: ```python import polars as pl import yaml from mosaic_widget import MosaicWidget weather = pl.read_csv( "https://uwdata.github.io/mosaic-datasets/data/seattle-weather.csv", try_parse_dates=True, ) # Load weather spec, remove data key to ensure load from the DataFrame with open("weather.yaml") as f: spec = yaml.safe_load(f) spec.pop("data") MosaicWidget(spec, data={"weather": weather}) ``` ### Listening to parameter changes A widget's `params` traitlet updates automatically as the user interacts with the plot. Call `observe` on the widget to react to those changes. Here we build the spec with the vgplot API, add an interval selection to brush over, and print the params into an output widget: ```python from pprint import pprint import ipywidgets as widgets import polars as pl import vgplot as vg from mosaic_widget import MosaicWidget weather = pl.read_csv( "https://uwdata.github.io/mosaic-datasets/data/seattle-weather.csv", try_parse_dates=True, ) brush = vg.selection.intersect() view = vg.plot( vg.dot( weather, x=vg.date_month_day("date"), y="temp_max", fill="weather", select=vg.interval_x(bind=brush), ), vg.x_tick_format("%b"), vg.width(680), ) widget = MosaicWidget(view) output = widgets.Output() @output.capture(clear_output=True) def handle_change(change): pprint(change.new) widget.observe(handle_change, names=["params"]) widgets.VBox([widget, output]) ``` ## Reading the Filtered Data After the user interacts with the widget, you can read the current selections as SQL and fetch the filtered rows directly from Python: ```python widget.sql # 'SELECT * FROM "weather" WHERE ("weather" = \'sun\')' widget.data().df() # pandas DataFrame of the currently filtered rows ``` `widget.sql` combines the active selection predicates from `params` with `AND`. `widget.data()` returns the lazy [DuckDB relation](https://duckdb.org/docs/api/python/relational_api) for that query; materialize it with `.df()` (pandas), `.pl()` (Polars), `.arrow()`, or `.fetchall()`. `widget.data()` infers the source table from the spec's `data` entries and the `data` constructor argument. If those name more than one table, pass the table explicitly (`widget.sql` returns `None` in that case). The query applies every selection; pass `filter_by` with a selection name or a list of names to apply a subset: ```python widget.data("weather").df() # explicit source table widget.data("weather", filter_by="range").df() # apply only the "range" selection ``` Note that in a cross-filtered view each chart skips its own selection, but `widget.data()` applies all of them, so a chart may show more rows than `widget.data()` returns. --- --- url: /mosaic/web-clients.md --- # Clients for Web Frameworks [Clients](/core/#clients) are responsible for publishing their data needs and performing data processing tasks—such as rendering a visualization. The [`MosaicClient` class](/api/core/client.html) provides a base class for client implementation. Many applications are written in web frameworks such as [React](https://react.dev), [Svelte](https://svelte.dev), and [Vue](https://vuejs.org). These frameworks have their own state management and lifecycle management systems which make it difficult to use the `MosaicClient` class directly. Mosaic has a `makeClient` API that makes it easier to integrate with such frameworks. ## Svelte Example Here is an example `Count` component written in Svelte, with `$effect`: ```svelte {filteredCount} / {totalCount} {isPending ? "(pending)" : ""} {isError ? "(error)" : ""} ``` The `makeClient` API combined with `$effect` allows the component to update its client when the props changes. This includes: * Replacement of the `coordinator` instance. * Changes to the `table` name. * Replacement of the `selection` instance (i.e., when the `selection` is replaced with a new instance of `Selection`). ## React Example Here is the same example in React: ```jsx import { makeClient } from "@uwdata/mosaic-core"; import { count, Query } from "@uwdata/mosaic-sql"; import { useState, useEffect } from "react"; /** Show the number of rows in the table. * If a `selection` is provided, show the filtered number of rows as well. */ export function Count(props) { const { coordinator, table, selection } = props; const [totalCount, setTotalCount] = useState(null); const [filteredCount, setFilteredCount] = useState(null); const [isError, setIsError] = useState(false); const [isPending, setIsPending] = useState(false); useEffect(() => { // Note that the identity of `table` and `selection` is captured below. // If they are replaced with a new instances, the client will get recreated as well. const client = makeClient({ coordinator, selection, prepare: async () => { // Preparation work before the client starts. // Here we get the total number of rows in the table. const result = await coordinator.query( Query.from(table).select({ count: count() }) ); setTotalCount(result.get(0).count); }, query: (predicate) => { // Returns a query to retrieve the data. // The `predicate` is the selection's predicate for this client. // Here we use it to get the filtered count. return Query.from(table) .select({ count: count() }) .where(predicate); }, queryResult: (data) => { // The query result is available. setFilteredCount(data.get(0).count); setIsError(false); setIsPending(false); }, queryPending: () => { // The query is pending. setIsPending(true); setIsError(false); }, queryError: () => { // There is an error running the query. setIsPending(false); setIsError(true); }, }); return () => { // Destroy the client on effect cleanup. client.destroy(); }; }, [coordinator, table, selection]); return (
{filteredCount} / {totalCount} {isPending ? "(pending)" : ""} {isError ? "(error)" : ""}
); } ``` --- --- url: /mosaic/examples.md --- # Examples Mosaic-powered visualizations created with [vgplot](/vgplot/). These visualizations can be specified using a JavaScript API, or in a standalone YAML or JSON file. Each example includes code for all three specification formats. For example, here is a line chart of historical Apple stock prices: ```py \[Python] import vgplot as vg aapl = vg.parquet("data/stocks.parquet", where="Symbol = 'AAPL'") view = vg.plot( vg.line_y(aapl, x="Date", y="Close"), vg.width(680), vg.height(200), ) ``` ::: warning By default Mosaic connects to a DuckDB server. To use a different database connector (such as DuckDB-WASM in the browser), you must first configure the connector. For example: ```js import { coordinator, wasmConnector } from "@uwdata/vgplot"; coordinator().databaseConnector(wasmConnector()); ``` ::: ::: tip For greater scalability and performance, consider using a local [DuckDB data server](/duckdb/) or viewing examples in [Jupyter](/jupyter/). ::: --- --- url: /mosaic/api.md --- # API Reference Mosaic API Reference. ## Mosaic Core * [Client](/api/core/client) * [Coordinator](/api/core/coordinator) * [Connectors](/api/core/connectors) * [Param](/api/core/param) * [Selection](/api/core/selection) ## Mosaic SQL * [Queries](/api/sql/queries) * [Expressions](/api/sql/expressions) * [Operators](/api/sql/operators) * [Date Functions](/api/sql/date-functions) * [Aggregate Functions](/api/sql/aggregate-functions) * [Window Functions](/api/sql/window-functions) * [Data Loading](/api/sql/data-loading) ## Mosaic Inputs * [Menu](/api/inputs/menu) * [Search](/api/inputs/search) * [Slider](/api/inputs/slider) * [Table](/api/inputs/table) ## Mosaic vgplot * [Plot](/api/vgplot/plot) * [Attributes](/api/vgplot/attributes) * [Marks](/api/vgplot/marks) * [Interactors](/api/vgplot/interactors) * [Legends](/api/vgplot/legends) * [Layout](/api/vgplot/layout) * [API Context](/api/vgplot/context) ## Mosaic Spec * [Specification Format](/api/spec/format) * [Parser & Generators](/api/spec/parser-generators) ## Mosaic DuckDB * [DuckDB API](/api/duckdb/duckdb) * [Data Server](/api/duckdb/data-server) --- --- url: /mosaic/examples/mark-types.md --- # Mark Types A subset of supported mark types. * Row 1: `barY`, `lineY`, `text`, `tickY`, `areaY` * Row 2: `regressionY`, `hexbin`, `contour`, `heatmap`, `denseLine` ## Specification ```py \[Python] import vgplot as vg md = vg.json( [ {"i": 0, "u": "A", "v": 2}, {"i": 1, "u": "B", "v": 8}, {"i": 2, "u": "C", "v": 3}, {"i": 3, "u": "D", "v": 7}, {"i": 4, "u": "E", "v": 5}, {"i": 5, "u": "F", "v": 4}, {"i": 6, "u": "G", "v": 6}, {"i": 7, "u": "H", "v": 1}, ] ) view = vg.vconcat( vg.hconcat( vg.plot( vg.bar_y(md, x="u", y="v", fill="steelblue"), ), vg.plot( vg.line_y( md, x="u", y="v", stroke="steelblue", curve="monotone-x", marker="circle", ), ), vg.plot( vg.text(md, x="u", y="v", text="u", fill="steelblue"), ), vg.plot( vg.tick_y(md, x="u", y="v", stroke="steelblue"), ), vg.plot( vg.area_y(md, x="u", y="v", fill="steelblue"), ), ), vg.hconcat( vg.plot( vg.dot(md, x="i", y="v", fill="currentColor", r=1.5), vg.regression_y(md, x="i", y="v", stroke="steelblue"), vg.x_domain([-0.5, 7.5]), ), vg.plot( vg.hexgrid(stroke="#aaa", stroke_opacity=0.5), vg.hexbin(md, x="i", y="v", fill=vg.count()), vg.color_scheme("blues"), vg.x_domain([-1, 8]), ), vg.plot( vg.contour(md, x="i", y="v", stroke="steelblue", bandwidth=15), vg.x_domain([-1, 8]), ), vg.plot( vg.heatmap(md, x="i", y="v", fill="density", bandwidth=15), vg.color_scheme("blues"), vg.x_domain([-1, 8]), ), vg.plot( vg.dense_line(md, x="i", y="v", fill="density", bandwidth=2, pixel_size=1), vg.color_scheme("blues"), vg.x_domain([-1, 8]), ), ), plot_defaults={ "xAxis": None, "yAxis": None, "margins": {"left": 5, "top": 5, "right": 5, "bottom": 5}, "width": 160, "height": 100, "yDomain": [0, 9], }, ) ``` --- --- url: /mosaic/examples/symbols.md --- # Symbol Plots Two scatter plots with `dot` marks: one with stroked symbols, the other filled. Drop-down menus control which data table columns are plotted. ## Specification ```py \[Python] import vgplot as vg penguins = vg.parquet("data/penguins.parquet") x = vg.param("body_mass") y = vg.param("flipper_length") view = vg.vconcat( vg.hconcat( vg.menu( label="Y", options=["body_mass", "flipper_length", "bill_depth", "bill_length"], bind=y, ), vg.menu( label="X", options=["body_mass", "flipper_length", "bill_depth", "bill_length"], bind=x, ), ), vg.vspace(10), vg.hconcat( vg.plot( vg.dot( penguins, x=vg.column(x), y=vg.column(y), stroke="species", symbol="species", ), vg.name("stroked"), vg.grid(True), vg.x_label("Body mass (g) →"), vg.y_label("↑ Flipper length (mm)"), ), vg.symbol_legend(plot="stroked", columns=1), ), vg.vspace(20), vg.hconcat( vg.plot( vg.dot( penguins, x=vg.column(x), y=vg.column(y), fill="species", symbol="species", ), vg.name("filled"), vg.grid(True), vg.x_label("Body mass (g) →"), vg.y_label("↑ Flipper length (mm)"), ), vg.symbol_legend(plot="filled", columns=1), ), ) ``` --- --- url: /mosaic/examples/axes.md --- # Axes & Gridlines Customized axis and gridline marks can be used in addition to standard scale attributes such as `xAxis`, `yGrid`, etc. Just add data! ## Specification ```py \[Python] import vgplot as vg view = vg.plot( vg.grid_y(stroke_dasharray="0.75 2", stroke_opacity=1), vg.axis_y(anchor="left", tick_size=0, dx=38, dy=-4, line_anchor="bottom"), vg.axis_y( anchor="right", tick_size=0, tick_padding=5, label="y-axis", label_anchor="center", ), vg.axis_x(label="x-axis", label_anchor="center"), vg.grid_x(), vg.rule_y(data=[0]), vg.x_domain([0, 100]), vg.y_domain([0, 100]), vg.x_inset_left(36), vg.margin_left(0), vg.margin_right(35), vg.width(680), ) ``` --- --- url: /mosaic/examples/airline-travelers.md --- # Airline Travelers A labeled line chart comparing airport travelers in 2019 and 2020. **Credit**: Adapted from an [Observable Plot example](https://observablehq.com/@observablehq/plot-labeled-line-chart). ## Specification ```py \[Python] import vgplot as vg travelers = vg.parquet("data/travelers.parquet") endpoint = vg.table("SELECT * FROM travelers ORDER BY date DESC LIMIT 1") view = vg.plot( vg.rule_y(data=[0]), vg.line_y(travelers, x="date", y="previous", stroke_opacity=0.35), vg.line_y(travelers, x="date", y="current"), vg.text( endpoint, x="date", y="previous", text=["2019"], fill_opacity=0.5, line_anchor="bottom", dy=-6, ), vg.text(endpoint, x="date", y="current", text=["2020"], line_anchor="top", dy=6), vg.y_grid(True), vg.y_label("↑ Travelers per day"), vg.y_tick_format("s"), ) ``` --- --- url: /mosaic/examples/aeromagnetic-survey.md --- # Aeromagnetic Survey A raster visualization of the 1955 [Great Britain aeromagnetic survey](https://www.bgs.ac.uk/datasets/gb-aeromagnetic-survey/), which measured the Earth’s magnetic field by plane. Each sample recorded the longitude and latitude alongside the strength of the [IGRF](https://www.ncei.noaa.gov/products/international-geomagnetic-reference-field) in [nanoteslas](https://en.wikipedia.org/wiki/Tesla_\(unit\)). This example demonstrates both raster interpolation and smoothing (blur) options. **Credit**: Adapted from an [Observable Plot example](https://observablehq.com/@observablehq/plot-igfr90-raster). ## Specification ```py \[Python] import vgplot as vg ca55 = vg.parquet("data/ca55-south.parquet") interp = vg.param("random-walk") blur = vg.param(0) view = vg.vconcat( vg.hconcat( vg.menu( label="Interpolation Method", options=["none", "nearest", "barycentric", "random-walk"], bind=interp, ), vg.hspace("1em"), vg.slider(label="Blur", min=0, max=100, bind=blur), ), vg.vspace("1em"), vg.plot( vg.raster( ca55, x="LONGITUDE", y="LATITUDE", fill=vg.max("MAG_IGRF90"), interpolate=interp, bandwidth=blur, ), vg.color_scale("diverging"), vg.color_domain("Fixed"), ), ) ``` --- --- url: /mosaic/examples/athlete-birth-waffle.md --- # Athlete Birth Waffle Waffle chart counting Olympic athletes based on which half-decade they were born. The inputs enable adjustment of waffle mark design options. **Credit**: Adapted from an [Observable Plot example](https://observablehq.com/@observablehq/plot-waffle-unit). ## Specification ```py \[Python] import vgplot as vg athletes = vg.parquet("data/athletes.parquet") unit = vg.param(10) round = vg.param(False) gap = vg.param(1) radius = vg.param(0) view = vg.vconcat( vg.hconcat( vg.menu(bind=unit, options=[1, 2, 5, 10, 25, 50, 100], label="Unit"), vg.menu(bind=round, options=[True, False], label="Round"), vg.menu(bind=gap, options=[0, 1, 2, 3, 4, 5], label="Gap"), vg.slider(bind=radius, min=0, max=10, step=0.1, label="Radius"), ), vg.vspace(10), vg.plot( vg.waffle_y( athletes, unit=unit, round=round, gap=gap, rx=radius, x=vg.sql('5 * floor(year("date_of_birth") / 5)'), y=vg.count(), ), vg.x_label(None), vg.x_tick_size(0), vg.x_tick_format("d"), ), ) ``` --- --- url: /mosaic/examples/driving-shifts.md --- # Driving Shifts into Reverse A connected scatter plot of miles driven vs. gas prices. **Credit**: Adapted from an [Observable Plot example](https://observablehq.com/@observablehq/plot-connected-scatterplot), which in turn adapts Hannah Fairfield's [New York Times article](http://www.nytimes.com/imagepages/2010/05/02/business/02metrics.html). ## Specification ```py \[Python] import vgplot as vg driving = vg.parquet("data/driving.parquet") view = vg.plot( vg.line(driving, x="miles", y="gas", curve="catmull-rom", marker=True), vg.text( driving, x="miles", y="gas", text=vg.sql("year::VARCHAR"), dy=-6, line_anchor="bottom", filter=vg.sql("year % 5 = 0"), ), vg.inset(10), vg.grid(True), vg.x_label("Miles driven (per person-year)"), vg.y_label("Cost of gasoline ($ per gallon)"), ) ``` --- --- url: /mosaic/examples/population-arrows.md --- # Population Change Arrows An `arrow` connects the positions in 1980 and 2015 of each city on this population × inequality chart. Color encodes variation. **Credit**: Adapted from an [Observable Plot example](https://observablehq.com/@observablehq/plot-arrow-variation-chart). ## Specification ```py \[Python] import vgplot as vg metros = vg.parquet("data/metros.parquet") bend = vg.param(True) view = vg.vconcat( vg.color_legend(plot="arrows", label="Change in inequality from 1980 to 2015"), vg.plot( vg.arrow( metros, x1="POP_1980", y1="R90_10_1980", x2="POP_2015", y2="R90_10_2015", bend=bend, stroke=vg.sql("R90_10_2015 - R90_10_1980"), ), vg.text( metros, x="POP_2015", y="R90_10_2015", filter="highlight", text="nyt_display", fill="currentColor", dy=-6, ), vg.name("arrows"), vg.grid(True), vg.inset(10), vg.x_scale("log"), vg.x_label("Population →"), vg.y_label("↑ Inequality"), vg.y_ticks(4), vg.color_scheme("BuRd"), vg.color_tick_format("+f"), ), vg.menu(label="Bend Arrows?", options=[True, False], bind=bend), ) ``` --- --- url: /mosaic/examples/presidential-opinion.md --- # Presidential Opinion Opinion poll data on historical U.S. presidents. Image marks are used to show presidential pictures. The dropdown menu toggles the opinion metric shown. **Credit**: Adapted from an [Observable Plot example](https://observablehq.com/@observablehq/plot-image-medals). ## Specification ```py \[Python] import vgplot as vg presidents = vg.parquet("data/us-president-favorability.parquet") sign = vg.param(1) view = vg.vconcat( vg.plot( vg.rule_y(data=[0]), vg.image( presidents, x="First Inauguration Date", y=vg.sql( '"Very Favorable %" + "Somewhat Favorable %" + $sign * ("Very Unfavorable %" + "Somewhat Unfavorable %")' ), src="Portrait URL", r=20, preserve_aspect_ratio="xMidYMin slice", title="Name", ), vg.x_inset(20), vg.x_label("First inauguration date →"), vg.y_inset_top(4), vg.y_grid(True), vg.y_label("↑ Opinion (%)"), vg.y_tick_format("+f"), ), vg.menu( label="Opinion Metric", options=[ vg.option("Any Opinion", value=1), vg.option("Net Favorability", value=-1), ], bind=sign, ), ) ``` --- --- url: /mosaic/examples/voronoi.md --- # Voronoi Diagram The `voronoi` mark shows the regions closest to each point. It is [constructed from its dual](https://observablehq.com/@mbostock/the-delaunays-dual), a Delaunay triangle mesh. Reveal triangulations or convex hulls using the dropdowns. **Credit**: Adapted from an [Observable Plot example](https://observablehq.com/@observablehq/plot-voronoi-scatterplot). ## Specification ```py \[Python] import vgplot as vg penguins = vg.parquet("data/penguins.parquet") mesh = vg.param(0) hull = vg.param(0) view = vg.vconcat( vg.plot( vg.voronoi( penguins, x="bill_length", y="bill_depth", stroke="white", stroke_width=1, stroke_opacity=0.5, fill="species", fill_opacity=0.2, ), vg.hull( penguins, x="bill_length", y="bill_depth", stroke="species", stroke_opacity=hull, stroke_width=1.5, ), vg.delaunay_mesh( penguins, x="bill_length", y="bill_depth", z="species", stroke="species", stroke_opacity=mesh, stroke_width=1, ), vg.dot(penguins, x="bill_length", y="bill_depth", fill="species", r=2), vg.frame(), vg.inset(10), vg.width(680), ), vg.hconcat( vg.menu( label="Delaunay Mesh", options=[vg.option("Hide", value=0), vg.option("Show", value=0.5)], bind=mesh, ), vg.hspace(5), vg.menu( label="Convex Hull", options=[vg.option("Hide", value=0), vg.option("Show", value=1)], bind=hull, ), ), ) ``` --- --- url: /mosaic/examples/seattle-temp.md --- # Seattle Temperatures Historical monthly temperatures in Seattle, WA. The gray range shows the minimum and maximum recorded temperatures. The blue range shows the average lows and highs. ## Specification ```py \[Python] import vgplot as vg weather = vg.parquet("data/seattle-weather.parquet") view = vg.plot( vg.area_y( weather, x=vg.date_month("date"), y1=vg.max("temp_max"), y2=vg.min("temp_min"), fill="#ccc", fill_opacity=0.25, curve="monotone-x", ), vg.area_y( weather, x=vg.date_month("date"), y1=vg.avg("temp_max"), y2=vg.avg("temp_min"), fill="steelblue", fill_opacity=0.75, curve="monotone-x", ), vg.rule_y(data=[15], stroke_opacity=0.5, stroke_dasharray="5 5"), vg.x_tick_format("%b"), vg.y_label("Temperature Range (°C)"), vg.width(680), vg.height(300), ) ``` --- --- url: /mosaic/examples/sorted-bars.md --- # Sorted Bars Sort and limit an aggregate bar chart of gold medals by country. ## Specification ```py \[Python] import vgplot as vg athletes = vg.parquet("data/athletes.parquet") query = vg.selection.intersect() view = vg.vconcat( vg.menu( label="Sport", bind=query, source=athletes, column="sport", value="aquatics" ), vg.vspace(10), vg.plot( vg.bar_x( data=athletes, filter_by=query, x=vg.sum("gold"), y="nationality", fill="steelblue", sort=vg.sort(y="-x", limit=10), ), vg.x_label("Gold Medals"), vg.y_label("Nationality"), vg.y_label_anchor("top"), vg.margin_top(15), ), ) ``` --- --- url: /mosaic/examples/table.md --- # Sortable Table A sortable, "infinite scroll" `table` view over a backing database table. Click column headers to sort, or command-click to reset the order. Data is queried as needed as the table is sorted or scrolled. ## Specification ```py \[Python] import vgplot as vg flights = vg.parquet("data/flights-200k.parquet") view = vg.table_input(source=flights, height=300) ``` --- --- url: /mosaic/examples/athlete-height.md --- # Athlete Height Intervals Confidence intervals of Olympic athlete heights, in meters. Data are batched into groups of 10 samples per sport. Use the samples slider to see how the intervals update as the sample size increases (as in [online aggregation](https://en.wikipedia.org/wiki/Online_aggregation)). For each sport, the numbers on the right show the maximum number of athletes in the full dataset. ## Specification ```py \[Python] import vgplot as vg athletesBatched = vg.parquet( "data/athletes.parquet", select=["*", "10 * CEIL(ROW_NUMBER() OVER (PARTITION BY sport) / 10) AS batch"], where="height IS NOT NULL", ) ci = vg.param(0.95) query = vg.selection.single() view = vg.hconcat( vg.vconcat( vg.hconcat( vg.slider( select="interval", bind=query, column="batch", source=athletesBatched, step=10, value=20, label="Max Samples", ), vg.slider(bind=ci, min=0.5, max=0.999, step=0.001, label="Conf. Level"), ), vg.plot( vg.errorbar_x( data=athletesBatched, filter_by=query, ci=ci, x="height", y="sport", stroke="sex", stroke_width=1, marker="tick", sort=vg.sort(y="-x"), ), vg.text( athletesBatched, frame_anchor="right", font_size=8, fill="#999", dx=25, text=vg.count(), y="sport", ), vg.name("heights"), vg.x_domain([1.5, 2.1]), vg.y_domain("Fixed"), vg.y_grid(True), vg.y_label(None), vg.margin_top(5), vg.margin_left(105), vg.margin_right(30), vg.height(420), ), vg.color_legend(plot="heights"), ), ) ``` --- --- url: /mosaic/examples/bias.md --- # Bias Parameter Dynamically adjust queried values by adding a Param value. The SQL expression is re-computed in the database upon updates. ## Specification ```py \[Python] import vgplot as vg walk = vg.parquet("data/random-walk.parquet") point = vg.param(0) view = vg.vconcat( vg.slider(label="Bias", bind=point, min=0, max=1000, step=1), vg.plot( vg.area_y(walk, x="t", y=vg.sql("v + $point"), fill="steelblue"), vg.width(680), vg.height(200), ), ) ``` --- --- url: /mosaic/examples/linear-regression.md --- # Linear Regression A linear regression plot predicting athletes' heights based on their weights. Regression computation is performed in the database. The area around a regression line shows a 95% confidence interval. Select a region to view regression results for a data subset. ## Specification ```py \[Python] import vgplot as vg athletes = vg.parquet("data/athletes.parquet") query = vg.selection.intersect() view = vg.plot( vg.dot(athletes, x="weight", y="height", fill="sex", r=2, opacity=0.05), vg.regression_y( data=athletes, filter_by=query, x="weight", y="height", stroke="sex" ), vg.interval_xy(bind=query, brush=vg.brush(fill_opacity=0, stroke="currentColor")), vg.xy_domain("Fixed"), vg.color_domain("Fixed"), ) ``` --- --- url: /mosaic/examples/linear-regression-10m.md --- # Linear Regression 10M A linear regression plot predicting flight arrival delay based on the time of departure, over 10 million flight records. Regression computation is performed in the database, with optimized selection updates using pre-aggregated materialized views. The area around a regression line shows a 95% confidence interval. Select a region to view regression results for a data subset. ## Specification ```py \[Python] import vgplot as vg flights10m = vg.table( "SELECT GREATEST(-60, LEAST(ARR_DELAY, 180))::DOUBLE AS delay, DISTANCE AS distance, DEP_TIME AS time FROM 'https://pub-1da360b43ceb401c809f68ca37c7f8a4.r2.dev/data/flights-10m.parquet'" ) flights10p = vg.table("SELECT * FROM flights10m USING SAMPLE 10%") flights5p = vg.table("SELECT * FROM flights10m USING SAMPLE 5%") flights1p = vg.table("SELECT * FROM flights10m USING SAMPLE 1%") data = vg.param("flights10m") query = vg.selection.intersect() view = vg.vconcat( vg.menu( label="Sample", bind=data, options=[ vg.option("Full Data", value="flights10m"), vg.option("10% Sample", value="flights10p"), vg.option("5% Sample", value="flights5p"), vg.option("1% Sample", value="flights1p"), ], ), vg.vspace(10), vg.plot( vg.raster( data=data, x="time", y="delay", pixel_size=4, pad=0, image_rendering="pixelated", ), vg.regression_y(data=data, x="time", y="delay", stroke="gray"), vg.regression_y( data=data, filter_by=query, x="time", y="delay", stroke="firebrick" ), vg.interval_xy( bind=query, brush=vg.brush(fill_opacity=0, stroke="currentColor") ), vg.x_domain([0, 24]), vg.y_domain([-60, 180]), vg.color_scale("symlog"), vg.color_scheme("blues"), vg.color_domain("Fixed"), ), ) ``` --- --- url: /mosaic/examples/moving-average.md --- # Moving Average This plot shows daily reported COVID-19 cases from March 3 (day 1) to May 5, 2020 (day 64) in Berlin, Germany, as reported by the [Robert Koch Institute](https://www.rki.de/DE/Content/InfAZ/N/Neuartiges_Coronavirus/nCoV.html). We can smooth the raw counts using a moving average over various choices of window query frames. **Credit**: Adapted from the [Arquero window query tutorial](https://observablehq.com/@uwdata/working-with-window-queries). ## Specification ```py \[Python] import vgplot as vg cases = vg.parquet("data/berlin-covid.parquet") frame = vg.param([-6, 0]) view = vg.vconcat( vg.plot( vg.rect_y( cases, x1="day", x2=vg.sql("day + 1"), inset=1, y="cases", fill="steelblue" ), vg.line_y( cases, x=vg.sql("day + 0.5"), y=vg.avg("cases", orderby="day", rows=frame), curve="monotone-x", stroke="currentColor", ), vg.x_label("day"), vg.width(680), vg.height(300), ), vg.menu( label="Window Frame", bind=frame, options=[ vg.option( "7-day moving average, with prior 6 days: [-6, 0]", value=[-6, 0] ), vg.option( "7-day moving average, centered at current day: [-3, 3]", value=[-3, 3] ), vg.option("Moving average, with all prior days [-∞, 0]", value=[None, 0]), vg.option("Global average [-∞, +∞]", value=[None, None]), ], ), ) ``` --- --- url: /mosaic/examples/line-multi-series.md --- # Line Multi-Series This line chart shows the unemployment rate of various U.S. metro divisions from 2000 through 2013. On hover, the closest data point to the pointer and its associated series is highlighted. Highlighting of series is performed using `nearestX` and `highlight` interactors. Point and text annotations instead use the mark `select` filter option. **Credit**: Adapted from a [D3 example](https://observablehq.com/@d3/multi-line-chart/2). Data from the [Bureau of Labor Statistics](https://www.bls.gov/). ## Specification ```py \[Python] import vgplot as vg bls_unemp = vg.parquet("data/bls-metro-unemployment.parquet") curr = vg.selection.intersect() view = vg.plot( vg.rule_y(data=[0]), vg.line_y( data=bls_unemp, optimize=False, x="date", y="unemployment", z="division", stroke="steelblue", stroke_opacity=0.9, curve="monotone-x", ), vg.nearest_x(channels=["z"], bind=curr), vg.highlight(by=curr), vg.dot( bls_unemp, x="date", y="unemployment", z="division", r=2, fill="currentColor", select="nearestX", ), vg.text( bls_unemp, x="date", y="unemployment", text="division", fill="currentColor", dy=-8, select="nearestX", ), vg.margin_left(24), vg.x_label(None), vg.x_ticks(10), vg.y_label("Unemployment (%)"), vg.y_grid(True), vg.style("overflow: visible;"), vg.width(680), ) ``` --- --- url: /mosaic/examples/normalize.md --- # Normalized Stock Prices What is the return on investment for different days? Hover over the chart to normalize the stock prices for the percentage return on a given day. A `nearestX` interactor selects the nearest date, and parameterized expressions reactively update in response. ## Specification ```py \[Python] from datetime import date import vgplot as vg stocks = vg.parquet("data/stocks.parquet") labels = vg.table( "SELECT MAX(Date) as Date, ARGMAX(Close, Date) AS Close, Symbol FROM stocks GROUP BY Symbol" ) point = vg.param(date(2013, 5, 13)) view = vg.plot( vg.rule_x(x=point), vg.text_x(x=point, text=point, frame_anchor="top", line_anchor="bottom", dy=-7), vg.text( labels, x="Date", y=vg.sql( "Close / (SELECT max(Close) FROM stocks WHERE Symbol = source.Symbol AND Date = $point)" ), dx=2, text="Symbol", fill="Symbol", text_anchor="start", ), vg.line_y( stocks, x="Date", y=vg.sql( "Close / (SELECT max(Close) FROM stocks WHERE Symbol = source.Symbol AND Date = $point)" ), stroke="Symbol", ), vg.nearest_x(bind=point), vg.y_scale("log"), vg.y_domain([0.2, 6]), vg.y_grid(True), vg.x_label(None), vg.y_label(None), vg.y_tick_format("%"), vg.width(680), vg.height(400), vg.margin_right(35), ) ``` --- --- url: /mosaic/examples/seattle-weather-pivot.md --- # Seattle Weather Pivot A DuckDB `PIVOT` query reshapes Seattle's daily weather observations into a cross-tab: one row per year, with a column counting the days of each weather type. The pivoted result is shown in a sortable `table` view. Click a column header to sort. ## Specification ```py \[Python] import vgplot as vg seattle_weather = vg.parquet("data/seattle-weather.parquet") weatherByYear = vg.table( "PIVOT (SELECT *, year(date) AS year FROM seattle_weather) ON weather IN ('drizzle', 'fog', 'rain', 'snow', 'sun') USING count(*) GROUP BY year ORDER BY year" ) view = vg.table_input( source=weatherByYear, align={"year": "left"}, width={"year": 80}, height=180 ) ``` --- --- url: /mosaic/examples/overview-detail.md --- # Overview + Detail Select the top "overview" series to zoom the "focus" view below. An `intervalX` interactor updates a selection that filters the focus view. The `line` and `area` marks can apply [M4](https://observablehq.com/@uwdata/m4-scalable-time-series-visualization) optimization to reduce the number of data points returned: rather than draw all points, a dramatically smaller subset can still faithfully represent these area charts. ## Specification ```py \[Python] import vgplot as vg walk = vg.parquet("data/random-walk.parquet") brush = vg.selection.intersect() view = vg.vconcat( vg.plot( vg.area_y(walk, x="t", y="v", fill="steelblue"), vg.interval_x(bind=brush), vg.width(680), vg.height(200), ), vg.plot( vg.area_y(data=walk, filter_by=brush, x="t", y="v", fill="steelblue"), vg.y_domain("Fixed"), vg.width(680), vg.height(200), ), ) ``` --- --- url: /mosaic/examples/wind-map.md --- # Wind Map `vector` marks on a grid show both direction and intensity—here, the speed of winds. Expressions for `rotate`, `length`, and `stroke` values are evaluated in the database. Both the legend and map support interactive selections to highlight values. **Credit**: Adapted from an [Observable Plot example](https://observablehq.com/@observablehq/plot-wind-map). ## Specification ```py \[Python] import vgplot as vg wind = vg.parquet("data/wind.parquet", select=["*", "row_number() over () as id"]) selected = vg.selection.union() length = vg.param(2) view = vg.vconcat( vg.color_legend(plot="wind-map", label="Speed (m/s)", bind=selected), vg.plot( vg.vector( wind, x="longitude", y="latitude", rotate=vg.sql("degrees(atan2(u, v))"), length=vg.sql("$length * sqrt(u * u + v * v)"), stroke=vg.sql("sqrt(u * u + v * v)"), channels=vg.channels(id="id"), ), vg.region(bind=selected, channels=["id"]), vg.highlight(by=selected), vg.name("wind-map"), vg.length_scale("identity"), vg.color_zero(True), vg.inset(10), vg.aspect_ratio(1), vg.width(680), ), vg.slider(min=1, max=7, step=0.1, bind=length, label="Vector Length"), ) ``` --- --- url: /mosaic/examples/wnba-shots.md --- # WNBA Shot Chart Every field goal attempt in the 2023 WNBA regular season. Shots are grouped into hexagonal bins, with color indicating shot potency (average score) and size indicating the total count of shots per location. The menu filters isolate shots by team or athlete. **Credit**: Data from [Wehoop](https://wehoop.sportsdataverse.org/). Design inspired by [Kirk Goldsberry](https://en.wikipedia.org/wiki/Kirk_Goldsberry) and a [UW CSE 512](https://courses.cs.washington.edu/courses/cse512/24sp/) project by Mackenzie Pitts and Madeline Brown. ## Specification ```py \[Python] import vgplot as vg shots = vg.parquet( "data/wnba-shots-2023.parquet", where="NOT starts_with(type, 'Free Throw') AND season_type = 2", ) court = vg.parquet("data/wnba-half-court.parquet") filter = vg.selection.crossfilter() binWidth = vg.param(18) view = vg.vconcat( vg.hconcat( vg.menu(source=shots, column="team_name", bind=filter, label="Team"), vg.menu( source=shots, column="athlete_name", filter_by=filter, bind=filter, label="Athlete", ), ), vg.vspace(5), vg.plot( vg.frame(stroke_opacity=0.5), vg.hexgrid(bin_width=binWidth, stroke_opacity=0.05), vg.hexbin( data=shots, filter_by=filter, bin_width=binWidth, x="x_position", y="y_position", fill=vg.avg("score_value"), r=vg.count(), tip={"format": {"x": False, "y": False}}, ), vg.line(court, stroke_linecap="butt", stroke_opacity=0.5, x="x", y="y", z="z"), vg.name("shot-chart"), vg.x_axis(None), vg.y_axis(None), vg.margin(5), vg.x_domain([0, 50]), vg.y_domain([0, 40]), vg.color_domain("Fixed"), vg.color_scheme("YlOrRd"), vg.color_scale("linear"), vg.color_label("Avg. Shot Value"), vg.r_scale("log"), vg.r_range([3, 9]), vg.r_label("Shot Count"), vg.aspect_ratio(1), vg.width(510), ), vg.color_legend(plot="shot-chart"), ) ``` --- --- url: /mosaic/examples/earthquakes-feed.md --- # Earthquakes Feed Earthquake data from the USGS live feed. To show land masses, this example loads and parses TopoJSON data in the database. Requires the DuckDB `spatial` extension. **Credit**: Adapted from an [Observable Plot example](https://observablehq.com/@observablehq/plot-live-earthquake-map). ## Specification ```py \[Python] import vgplot as vg feed = vg.spatial("data/usgs-feed.geojson") world = vg.spatial("data/countries-110m.json", layer="land") view = vg.plot( vg.geo(world, fill="currentColor", fill_opacity=0.2), vg.sphere(stroke_width=0.5), vg.geo( feed, r=vg.sql("POW(10, mag)"), stroke="red", fill="red", fill_opacity=0.2, title="title", href="url", target="_blank", ), vg.margin(2), vg.projection_type("equirectangular"), ) ``` --- --- url: /mosaic/examples/earthquakes-globe.md --- # Earthquakes Globe A rotatable globe of earthquake activity. To show land masses, this example loads and parses TopoJSON data in the database. Requires the DuckDB `spatial` extension. **Credit**: Adapted from an [Observable Plot example](https://observablehq.com/@observablehq/plot-earthquake-globe). ## Specification ```py \[Python] import vgplot as vg earthquakes = vg.parquet("data/earthquakes.parquet") land = vg.spatial("data/countries-110m.json", layer="land") longitude = vg.param(-180) latitude = vg.param(-30) rotate = vg.param([longitude, latitude]) view = vg.vconcat( vg.hconcat( vg.slider(label="Longitude", bind=longitude, min=-180, max=180, step=1), vg.slider(label="Latitude", bind=latitude, min=-90, max=90, step=1), ), vg.plot( vg.geo( land, geometry=vg.geojson("geom"), fill="currentColor", fill_opacity=0.2 ), vg.sphere(), vg.dot( earthquakes, x="longitude", y="latitude", r=vg.sql("POW(10, magnitude)"), stroke="red", fill="red", fill_opacity=0.2, ), vg.margin(10), vg.style("overflow: visible;"), vg.projection_type("orthographic"), vg.projection_rotate(rotate), ), ) ``` --- --- url: /mosaic/examples/us-state-map.md --- # U.S. States A map of U.S. states overlaid with computed centroids. Requires the DuckDB `spatial` extension. **Credit**: Adapted from an [Observable Plot example](https://observablehq.com/@observablehq/plot-state-centroids). ## Specification ```py \[Python] import vgplot as vg states = vg.spatial("data/us-counties-10m.json", layer="states") view = vg.plot( vg.geo(states, stroke="currentColor", stroke_width=1), vg.dot( states, x=vg.centroid_x("geom"), y=vg.centroid_y("geom"), r=2, fill="steelblue", tip=True, title="name", ), vg.margin(0), vg.projection_type("albers"), ) ``` --- --- url: /mosaic/examples/us-county-map.md --- # U.S. Counties A map of U.S. counties. County name tooltips are anchored to invisible centroid dot marks. Requires the DuckDB `spatial` extension. ## Specification ```py \[Python] import vgplot as vg counties = vg.spatial("data/us-counties-10m.json", layer="counties") states = vg.spatial("data/us-counties-10m.json", layer="states") view = vg.plot( vg.geo(counties, stroke="currentColor", stroke_width=0.25), vg.geo(states, stroke="currentColor", stroke_width=1), vg.dot( counties, x=vg.centroid_x("geom"), y=vg.centroid_y("geom"), r=2, fill="transparent", tip=True, title="name", ), vg.margin(0), vg.projection_type("albers"), ) ``` --- --- url: /mosaic/examples/unemployment.md --- # U.S. Unemployment A choropleth map of unemployment rates for U.S. counties. Requires the DuckDB `spatial` extension. **Credit**: Adapted from an [Observable Plot example](https://observablehq.com/@observablehq/plot-us-choropleth). ## Specification ```py \[Python] import vgplot as vg counties = vg.spatial("data/us-counties-10m.json", layer="counties") rates = vg.parquet("data/us-county-unemployment.parquet") combined = vg.table( "SELECT a.geom AS geom, b.rate AS rate FROM counties AS a, rates AS b WHERE a.id = b.id" ) view = vg.vconcat( vg.color_legend(plot="county-map", label="Unemployment (%)"), vg.plot( vg.geo(combined, fill="rate", title=vg.sql("concat(rate, '%')")), vg.name("county-map"), vg.margin(0), vg.color_scale("quantile"), vg.color_n(9), vg.color_scheme("blues"), vg.projection_type("albers-usa"), ), ) ``` --- --- url: /mosaic/examples/walmart-openings.md --- # Walmart Openings Maps showing Walmart store openings per decade. Requires the DuckDB `spatial` extension. **Credit**: Adapted from an [Observable Plot example](https://observablehq.com/@observablehq/plot-map-large-multiples). ## Specification ```py \[Python] import vgplot as vg states = vg.spatial("data/us-counties-10m.json", layer="states") nation = vg.spatial("data/us-counties-10m.json", layer="nation") walmarts = vg.parquet("data/walmarts.parquet") view = vg.vconcat( vg.plot( vg.geo(states, stroke="#aaa", stroke_width=1), vg.geo(nation, stroke="currentColor"), vg.dot( walmarts, x="longitude", y="latitude", fy=vg.sql("10 * decade(date)"), r=1.5, fill="blue", ), vg.axis_fy(frame_anchor="top", dy=30, tick_format="d"), vg.margin(0), vg.fy_label(None), vg.projection_type("albers"), ), ) ``` --- --- url: /mosaic/examples/nyc-taxi-rides.md --- # NYC Taxi Rides Pickup and dropoff points for 1M NYC taxi rides on Jan 1-3, 2010. This example projects lon/lat coordinates in the database upon load. Select a region in one plot to filter the other. What spatial patterns can you find? Requires the DuckDB `spatial` extension. *You may need to wait a few seconds for the dataset to load.* ## Specification ```py \[Python] import vgplot as vg rides = vg.parquet( "https://pub-1da360b43ceb401c809f68ca37c7f8a4.r2.dev/data/nyc-rides-2010.parquet", select=[ "pickup_datetime::TIMESTAMP AS datetime", "ST_Transform(ST_Point(pickup_latitude, pickup_longitude), 'EPSG:4326', 'ESRI:102718') AS pick", "ST_Transform(ST_Point(dropoff_latitude, dropoff_longitude), 'EPSG:4326', 'ESRI:102718') AS drop", ], ) trips = vg.table( "SELECT\n (HOUR(datetime) + MINUTE(datetime)/60) AS time,\n ST_X(pick) AS px, ST_Y(pick) AS py,\n ST_X(drop) AS dx, ST_Y(drop) AS dy\nFROM rides" ) filter = vg.selection.crossfilter() view = vg.vconcat( vg.hconcat( vg.plot( vg.raster(data=trips, filter_by=filter, x="px", y="py", bandwidth=0), vg.interval_xy(bind=filter), vg.text( data=[ {"label": "Taxi Pickups"}, ], dx=10, dy=10, text="label", fill="black", font_size="1.2em", frame_anchor="top-left", ), vg.width(335), vg.height(550), vg.margin(0), vg.x_axis(None), vg.y_axis(None), vg.x_domain([975000, 1005000]), vg.y_domain([190000, 240000]), vg.color_scale("symlog"), vg.color_scheme("blues"), ), vg.hspace(10), vg.plot( vg.raster(data=trips, filter_by=filter, x="dx", y="dy", bandwidth=0), vg.interval_xy(bind=filter), vg.text( data=[ {"label": "Taxi Dropoffs"}, ], dx=10, dy=10, text="label", fill="black", font_size="1.2em", frame_anchor="top-left", ), vg.width(335), vg.height(550), vg.margin(0), vg.x_axis(None), vg.y_axis(None), vg.x_domain([975000, 1005000]), vg.y_domain([190000, 240000]), vg.color_scale("symlog"), vg.color_scheme("oranges"), ), ), vg.vspace(10), vg.plot( vg.rect_y(trips, x=vg.bin("time"), y=vg.count(), fill="steelblue", inset=0.5), vg.interval_x(bind=filter), vg.y_tick_format("s"), vg.x_label("Pickup Hour →"), vg.width(680), vg.height(100), ), config={"extensions": "spatial"}, ) ``` --- --- url: /mosaic/examples/flights-200k.md --- # Cross-Filter Flights (200k) Histograms showing arrival delay, departure time, and distance flown for over 200,000 flights. Select a histogram region to cross-filter the charts. Each plot uses an `intervalX` interactor to populate a shared Selection with `crossfilter` resolution. ## Specification ```py \[Python] import vgplot as vg flights = vg.parquet("data/flights-200k.parquet") brush = vg.selection.crossfilter() view = vg.vconcat( vg.plot( vg.rect_y( data=flights, filter_by=brush, x=vg.bin("delay"), y=vg.count(), fill="steelblue", inset_left=0.5, inset_right=0.5, ), vg.interval_x(bind=brush), vg.x_domain("Fixed"), vg.x_label("Arrival Delay (min)"), vg.y_tick_format("s"), vg.width(600), vg.height(200), ), vg.plot( vg.rect_y( data=flights, filter_by=brush, x=vg.bin("time"), y=vg.count(), fill="steelblue", inset_left=0.5, inset_right=0.5, ), vg.interval_x(bind=brush), vg.x_domain("Fixed"), vg.x_label("Departure Time (hour)"), vg.y_tick_format("s"), vg.width(600), vg.height(200), ), vg.plot( vg.rect_y( data=flights, filter_by=brush, x=vg.bin("distance"), y=vg.count(), fill="steelblue", inset_left=0.5, inset_right=0.5, ), vg.interval_x(bind=brush), vg.x_domain("Fixed"), vg.x_label("Flight Distance (miles)"), vg.y_tick_format("s"), vg.width(600), vg.height(200), ), ) ``` --- --- url: /mosaic/examples/flights-10m.md --- # Cross-Filter Flights (10M) Histograms showing arrival delay, departure time, and distance flown for 10 million flights. Once loaded, automatic pre-aggregation optimizations enable efficient cross-filtered selections. *You may need to wait a few seconds for the dataset to load.* ## Specification ```py \[Python] import vgplot as vg flights10m = vg.table( "SELECT GREATEST(-60, LEAST(ARR_DELAY, 180))::DOUBLE AS delay, DISTANCE AS distance, DEP_TIME AS time FROM 'https://pub-1da360b43ceb401c809f68ca37c7f8a4.r2.dev/data/flights-10m.parquet'" ) brush = vg.selection.crossfilter() view = vg.vconcat( vg.plot( vg.rect_y( data=flights10m, filter_by=brush, x=vg.bin("delay"), y=vg.count(), fill="steelblue", inset_left=0.5, inset_right=0.5, ), vg.interval_x(bind=brush), vg.x_domain("Fixed"), vg.x_label("Arrival Delay (min)"), vg.y_tick_format("s"), vg.width(600), vg.height(200), ), vg.plot( vg.rect_y( data=flights10m, filter_by=brush, x=vg.bin("time"), y=vg.count(), fill="steelblue", inset_left=0.5, inset_right=0.5, ), vg.interval_x(bind=brush), vg.x_domain("Fixed"), vg.x_label("Departure Time (hour)"), vg.y_tick_format("s"), vg.width(600), vg.height(200), ), vg.plot( vg.rect_y( data=flights10m, filter_by=brush, x=vg.bin("distance"), y=vg.count(), fill="steelblue", inset_left=0.5, inset_right=0.5, ), vg.interval_x(bind=brush), vg.x_domain("Fixed"), vg.x_label("Flight Distance (miles)"), vg.y_tick_format("s"), vg.width(600), vg.height(200), ), ) ``` --- --- url: /mosaic/examples/gaia.md --- # Gaia Star Catalog A 5M row sample of the 1.8B element Gaia star catalog. A `raster` sky map reveals our Milky Way galaxy. Select high parallax stars in the histogram to reveal a [Hertzsprung-Russel diagram](https://en.wikipedia.org/wiki/Hertzsprung%E2%80%93Russell_diagram) in the plot of stellar color vs. magnitude on the right. *You may need to wait a few seconds for the dataset to load.* ## Specification ```py \[Python] import vgplot as vg gaia = vg.table( "-- compute u and v with natural earth projection\nWITH prep AS (\n SELECT\n radians((-l + 540) % 360 - 180) AS lambda,\n radians(b) AS phi,\n asin(sqrt(3)/2 * sin(phi)) AS t,\n t^2 AS t2,\n t2^3 AS t6,\n *\n FROM 'https://pub-1da360b43ceb401c809f68ca37c7f8a4.r2.dev/data/gaia-5m.parquet'\n WHERE parallax BETWEEN -5 AND 20 AND phot_g_mean_mag IS NOT NULL AND bp_rp IS NOT NULL\n)\nSELECT\n (1.340264 * \"lambda\" * cos(t)) / (sqrt(3)/2 * (1.340264 + (-0.081106 * 3 * t2) + (t6 * (0.000893 * 7 + 0.003796 * 9 * t2)))) AS u,\n t * (1.340264 + (-0.081106 * t2) + (t6 * (0.000893 + 0.003796 * t2))) AS v,\n * EXCLUDE('t', 't2', 't6')\nFROM prep" ) brush = vg.selection.crossfilter() bandwidth = vg.param(0) pixelSize = vg.param(2) scaleType = vg.param("sqrt") view = vg.hconcat( vg.vconcat( vg.plot( vg.raster( data=gaia, filter_by=brush, x="u", y="v", fill="density", bandwidth=bandwidth, pixel_size=pixelSize, ), vg.interval_xy(pixel_size=2, bind=brush), vg.xy_domain("Fixed"), vg.color_scale(scaleType), vg.color_scheme("viridis"), vg.width(440), vg.height(250), vg.margin_left(25), vg.margin_top(20), vg.margin_right(1), ), vg.hconcat( vg.plot( vg.rect_y( data=gaia, filter_by=brush, x=vg.bin("phot_g_mean_mag"), y=vg.count(), fill="steelblue", inset=0.5, ), vg.interval_x(bind=brush), vg.x_domain("Fixed"), vg.y_scale(scaleType), vg.y_grid(True), vg.width(220), vg.height(120), vg.margin_left(65), ), vg.plot( vg.rect_y( data=gaia, filter_by=brush, x=vg.bin("parallax"), y=vg.count(), fill="steelblue", inset=0.5, ), vg.interval_x(bind=brush), vg.x_domain("Fixed"), vg.y_scale(scaleType), vg.y_grid(True), vg.width(220), vg.height(120), vg.margin_left(65), ), ), ), vg.hspace(10), vg.plot( vg.raster( data=gaia, filter_by=brush, x="bp_rp", y="phot_g_mean_mag", fill="density", bandwidth=bandwidth, pixel_size=pixelSize, ), vg.interval_xy(pixel_size=2, bind=brush), vg.xy_domain("Fixed"), vg.color_scale(scaleType), vg.color_scheme("viridis"), vg.y_reverse(True), vg.width(230), vg.height(370), vg.margin_left(25), vg.margin_top(20), vg.margin_right(1), ), ) ``` --- --- url: /mosaic/examples/observable-latency.md --- # Observable Latency Web request latency on Observable.com. Each pixel in the heatmap shows the most common route (URL pattern) at a given response latency within a time interval. Use the bar chart of most-requested routes to filter the heatmap and isolate specific patterns. Or, select a range in the heatmap to show the corresponding most-requested routes. *You may need to wait a few seconds for the dataset to load.* **Credit**: Adapted from an [Observable Framework example](https://observablehq.com/framework/examples/api/). ## Specification ```py \[Python] import vgplot as vg latency = vg.parquet( "https://pub-1da360b43ceb401c809f68ca37c7f8a4.r2.dev/data/observable-latency.parquet" ) filter = vg.selection.crossfilter() highlight = vg.selection.intersect() view = vg.vconcat( vg.plot( vg.frame(fill="black"), vg.raster( data=latency, filter_by=filter, x="time", y="latency", fill=vg.argmax("route", "count"), fill_opacity=vg.sum("count"), width=2016, height=500, image_rendering="pixelated", ), vg.interval_xy(bind=filter), vg.color_domain("Fixed"), vg.color_scheme("observable10"), vg.opacity_domain([0, 25]), vg.opacity_clamp(True), vg.y_scale("log"), vg.y_label("↑ Duration (ms)"), vg.y_domain([0.5, 10000]), vg.y_tick_format("s"), vg.x_scale("utc"), vg.x_label(None), vg.x_domain([1706227200000, 1706832000000]), vg.width(680), vg.height(300), vg.margins(left=35, top=20, bottom=30, right=20), ), vg.plot( vg.bar_x( data=latency, filter_by=filter, x=vg.sum("count"), y="route", fill="route", sort=vg.sort(y="-x", limit=15), ), vg.toggle_y(bind=filter), vg.toggle_y(bind=highlight), vg.highlight(by=highlight), vg.color_domain("Fixed"), vg.x_label("Routes by Total Requests"), vg.x_tick_format("s"), vg.y_label(None), vg.width(680), vg.height(300), vg.margin_top(5), vg.margin_left(220), vg.margin_bottom(35), ), ) ``` --- --- url: /mosaic/examples/athletes.md --- # Olympic Athletes An interactive dashboard of athlete statistics. The menus and searchbox filter the display and are automatically populated by backing data columns. ## Specification ```py \[Python] import vgplot as vg athletes = vg.parquet("data/athletes.parquet") category = vg.selection.intersect() query = vg.selection.intersect(include=[category]) hover = vg.selection.intersect(empty=True) view = vg.hconcat( vg.vconcat( vg.hconcat( vg.menu(label="Sport", bind=category, source=athletes, column="sport"), vg.menu(label="Sex", bind=category, source=athletes, column="sex"), vg.search( label="Name", filter_by=category, bind=query, source=athletes, column="name", type="contains", ), ), vg.vspace(10), vg.plot( vg.dot( data=athletes, filter_by=query, x="weight", y="height", fill="sex", r=2, opacity=0.1, ), vg.regression_y( data=athletes, filter_by=query, x="weight", y="height", stroke="sex" ), vg.interval_xy(bind=query, brush=vg.brush(fill_opacity=0, stroke="black")), vg.dot( data=athletes, filter_by=hover, x="weight", y="height", fill="sex", stroke="currentColor", stroke_width=1, r=3, ), vg.xy_domain("Fixed"), vg.color_domain("Fixed"), vg.margins(left=35, top=20, right=1), vg.width(570), vg.height(350), ), vg.vspace(5), vg.table_input( source=athletes, max_width=570, height=250, filter_by=query, bind=hover, columns=["name", "nationality", "sex", "height", "weight", "sport"], width={ "name": 180, "nationality": 100, "sex": 50, "height": 50, "weight": 50, "sport": 100, }, ), ), ) ``` --- --- url: /mosaic/examples/protein-design.md --- # Protein Design Explorer Explore synthesized proteins generated via [RFDiffusion](https://www.bakerlab.org/2023/07/11/diffusion-model-for-protein-design/). "Minibinders" are small proteins that bind to a specific protein target. When designing a minibinder, a researcher inputs the structure of the target protein and other parameters into the AI diffusion model. Often, a single, promising (parent) *version* can be run through the model again to produce additional, similar designs to better sample the design space. The pipeline generates tens of thousands of protein designs. The metric *pAE* (predicted alignment error) measures how accurate a model was at predicting the minibinder shape, whereas *pLDDT* (predicted local distance difference test) measures a model's confidence in minibinder structure prediction. For *pAE* lower is better, for *pLDDT* higher is better. Additional parameters include *partial t* to set the time steps used by the model, *noise* to create more diversity of designs, *gradient decay function* and *gradient scale* to guide prioritizing different positions at different time points, and *movement* to denote whether the minibinder was left in its original position ("og") or moved to a desirable position ("moved"). The dashboard below enables exploration of the results to identify promising protein designs and assess the effects of process parameters. **Credit**: Adapted from a [UW CSE 512](https://courses.cs.washington.edu/courses/cse512/24sp/) project by Christina Savvides, Alexander Shida, Riti Biswas, and Nora McNamara-Bordewick. Data from the [UW Institute for Protein Design](https://www.ipd.uw.edu/). ## Specification ```py \[Python] import vgplot as vg proteins = vg.parquet("data/protein-design.parquet") query = vg.selection.crossfilter() point = vg.selection.intersect(empty=True) plddt_domain = vg.param([67, 94.5]) pae_domain = vg.param([5, 29]) scheme = vg.param("observable10") view = vg.vconcat( vg.hconcat( vg.menu(source=proteins, column="partial_t", label="Partial t", bind=query), vg.menu(source=proteins, column="noise", label="Noise", bind=query), vg.menu( source=proteins, column="gradient_decay_function", label="Gradient Decay", bind=query, ), vg.menu( source=proteins, column="gradient_scale", label="Gradient Scale", bind=query ), ), vg.vspace("1.5em"), vg.hconcat( vg.plot( vg.rect_y( data=proteins, filter_by=query, x=vg.bin("plddt_total", steps=60), y=vg.count(), z="version", fill="version", order="z", reverse=True, inset_left=0.5, inset_right=0.5, ), vg.width(600), vg.height(55), vg.x_axis(None), vg.y_axis(None), vg.x_domain(plddt_domain), vg.color_domain("Fixed"), vg.color_scheme(scheme), vg.margin_left(40), vg.margin_right(0), vg.margin_top(0), vg.margin_bottom(0), ), vg.hspace(5), vg.color_legend(plot="scatter", columns=1, bind=query), ), vg.hconcat( vg.plot( vg.frame(stroke="#ccc"), vg.raster( data=proteins, filter_by=query, x="plddt_total", y="pae_interaction", fill="version", pad=0, ), vg.interval_xy( bind=query, brush=vg.brush(stroke="currentColor", fill="transparent") ), vg.dot( data=proteins, filter_by=point, x="plddt_total", y="pae_interaction", fill="version", stroke="currentColor", stroke_width=0.5, ), vg.name("scatter"), vg.opacity_domain([0, 2]), vg.opacity_clamp(True), vg.color_domain("Fixed"), vg.color_scheme(scheme), vg.x_domain(plddt_domain), vg.y_domain(pae_domain), vg.x_label_anchor("center"), vg.y_label_anchor("center"), vg.margin_top(0), vg.margin_left(40), vg.margin_right(0), vg.width(600), vg.height(450), ), vg.plot( vg.rect_x( data=proteins, filter_by=query, x=vg.count(), y=vg.bin("pae_interaction", steps=60), z="version", fill="version", order="z", reverse=True, inset_top=0.5, inset_bottom=0.5, ), vg.width(55), vg.height(450), vg.x_axis(None), vg.y_axis(None), vg.margin_top(0), vg.margin_left(0), vg.margin_right(0), vg.y_domain(pae_domain), vg.color_domain("Fixed"), vg.color_scheme(scheme), ), ), vg.vspace("1em"), vg.table_input( bind=point, filter_by=query, source=proteins, columns=[ "version", "pae_interaction", "plddt_total", "noise", "gradient_decay_function", "gradient_scale", "movement", ], width=680, height=215, ), ) ``` --- --- url: /mosaic/examples/pan-zoom.md --- # Pan & Zoom Linked panning and zooming across plots: drag to pan, scroll to zoom. `panZoom` interactors update a set of bound selections, one per unique axis. ## Specification ```py \[Python] import vgplot as vg penguins = vg.parquet("data/penguins.parquet") xs = vg.selection.intersect() ys = vg.selection.intersect() zs = vg.selection.intersect() ws = vg.selection.intersect() view = vg.hconcat( vg.vconcat( vg.plot( vg.frame(), vg.dot( penguins, x="bill_length", y="bill_depth", fill="species", r=2, clip=True, ), vg.pan_zoom(x=xs, y=ys), vg.width(320), vg.height(240), ), vg.vspace(10), vg.plot( vg.frame(), vg.dot( penguins, x="bill_length", y="flipper_length", fill="species", r=2, clip=True, ), vg.pan_zoom(x=xs, y=zs), vg.width(320), vg.height(240), ), ), vg.hspace(10), vg.vconcat( vg.plot( vg.frame(), vg.dot( penguins, x="body_mass", y="bill_depth", fill="species", r=2, clip=True ), vg.pan_zoom(x=ws, y=ys), vg.width(320), vg.height(240), ), vg.vspace(10), vg.plot( vg.frame(), vg.dot( penguins, x="body_mass", y="flipper_length", fill="species", r=2, clip=True, ), vg.pan_zoom(x=ws, y=zs), vg.width(320), vg.height(240), ), ), ) ``` --- --- url: /mosaic/examples/splom.md --- # Scatter Plot Matrix (SPLOM) A scatter plot matrix enables inspection of pairwise bivariate distributions. Do points cluster or separate in some dimensions but not others? Select a region to highlight corresponding points across all plots. ## Specification ```py \[Python] import vgplot as vg penguins = vg.parquet("data/penguins.parquet") brush = vg.selection.single() view = vg.vconcat( vg.hconcat( vg.plot( vg.frame(stroke="#ccc"), vg.dot(penguins, x="bill_length", y="body_mass", fill="species", r=2), vg.interval_xy(bind=brush), vg.highlight(by=brush, opacity=0.1), vg.y_axis("left"), vg.margin_left(45), vg.width(185), ), vg.plot( vg.frame(stroke="#ccc"), vg.dot(penguins, x="bill_depth", y="body_mass", fill="species", r=2), vg.interval_xy(bind=brush), vg.highlight(by=brush, opacity=0.1), ), vg.plot( vg.frame(stroke="#ccc"), vg.dot(penguins, x="flipper_length", y="body_mass", fill="species", r=2), vg.interval_xy(bind=brush), vg.highlight(by=brush, opacity=0.1), ), vg.plot( vg.frame(stroke="#ccc"), vg.dot(penguins, x="body_mass", y="body_mass", fill="species", r=2), vg.interval_xy(bind=brush), vg.highlight(by=brush, opacity=0.1), ), ), vg.hconcat( vg.plot( vg.frame(stroke="#ccc"), vg.dot(penguins, x="bill_length", y="flipper_length", fill="species", r=2), vg.interval_xy(bind=brush), vg.highlight(by=brush, opacity=0.1), vg.y_axis("left"), vg.margin_left(45), vg.width(185), ), vg.plot( vg.frame(stroke="#ccc"), vg.dot(penguins, x="bill_depth", y="flipper_length", fill="species", r=2), vg.interval_xy(bind=brush), vg.highlight(by=brush, opacity=0.1), ), vg.plot( vg.frame(stroke="#ccc"), vg.dot( penguins, x="flipper_length", y="flipper_length", fill="species", r=2 ), vg.interval_xy(bind=brush), vg.highlight(by=brush, opacity=0.1), ), vg.plot( vg.frame(stroke="#ccc"), vg.dot(penguins, x="body_mass", y="flipper_length", fill="species", r=2), vg.interval_xy(bind=brush), vg.highlight(by=brush, opacity=0.1), ), ), vg.hconcat( vg.plot( vg.frame(stroke="#ccc"), vg.dot(penguins, x="bill_length", y="bill_depth", fill="species", r=2), vg.interval_xy(bind=brush), vg.highlight(by=brush, opacity=0.1), vg.y_axis("left"), vg.margin_left(45), vg.width(185), ), vg.plot( vg.frame(stroke="#ccc"), vg.dot(penguins, x="bill_depth", y="bill_depth", fill="species", r=2), vg.interval_xy(bind=brush), vg.highlight(by=brush, opacity=0.1), ), vg.plot( vg.frame(stroke="#ccc"), vg.dot(penguins, x="flipper_length", y="bill_depth", fill="species", r=2), vg.interval_xy(bind=brush), vg.highlight(by=brush, opacity=0.1), ), vg.plot( vg.frame(stroke="#ccc"), vg.dot(penguins, x="body_mass", y="bill_depth", fill="species", r=2), vg.interval_xy(bind=brush), vg.highlight(by=brush, opacity=0.1), ), ), vg.hconcat( vg.plot( vg.frame(stroke="#ccc"), vg.dot(penguins, x="bill_length", y="bill_length", fill="species", r=2), vg.interval_xy(bind=brush), vg.highlight(by=brush, opacity=0.1), vg.y_axis("left"), vg.x_axis("bottom"), vg.margin_left(45), vg.margin_bottom(35), vg.width(185), vg.height(175), ), vg.plot( vg.frame(stroke="#ccc"), vg.dot(penguins, x="bill_depth", y="bill_length", fill="species", r=2), vg.interval_xy(bind=brush), vg.highlight(by=brush, opacity=0.1), vg.x_axis("bottom"), vg.height(175), vg.margin_bottom(35), ), vg.plot( vg.frame(stroke="#ccc"), vg.dot(penguins, x="flipper_length", y="bill_length", fill="species", r=2), vg.interval_xy(bind=brush), vg.highlight(by=brush, opacity=0.1), vg.x_axis("bottom"), vg.height(175), vg.margin_bottom(35), ), vg.plot( vg.frame(stroke="#ccc"), vg.dot(penguins, x="body_mass", y="bill_length", fill="species", r=2), vg.interval_xy(bind=brush), vg.highlight(by=brush, opacity=0.1), vg.x_axis("bottom"), vg.height(175), vg.margin_bottom(35), ), ), plot_defaults={ "xTicks": 3, "yTicks": 4, "xDomain": "Fixed", "yDomain": "Fixed", "colorDomain": "Fixed", "marginTop": 5, "marginBottom": 10, "marginLeft": 10, "marginRight": 5, "xAxis": None, "yAxis": None, "xLabelAnchor": "center", "yLabelAnchor": "center", "xTickFormat": "s", "yTickFormat": "s", "width": 150, "height": 150, }, ) ``` --- --- url: /mosaic/examples/weather.md --- # Seattle Weather An interactive view of Seattle's weather, including maximum temperature, amount of precipitation, and type of weather. By dragging on the scatter plot, you can see the proportion of days in that range that have sun, fog, drizzle, rain, or snow. **Credit**: Based on a [Vega-Lite/Altair example](https://vega.github.io/vega-lite/examples/interactive_seattle_weather.html) by Jake Vanderplas. ## Specification ```py \[Python] import vgplot as vg weather = vg.parquet("data/seattle-weather.parquet") click = vg.selection.single() domain = vg.param(["sun", "fog", "drizzle", "rain", "snow"]) colors = vg.param(["#e7ba52", "#a7a7a7", "#aec7e8", "#1f77b4", "#9467bd"]) range = vg.selection.intersect() view = vg.vconcat( vg.hconcat( vg.plot( vg.dot( data=weather, filter_by=click, x=vg.date_month_day("date"), y="temp_max", fill="weather", r="precipitation", fill_opacity=0.7, ), vg.interval_x(bind=range, brush=vg.brush(fill="none", stroke="#888")), vg.highlight(by=range, fill="#ccc", fill_opacity=0.2), vg.color_legend(bind=click, columns=1), vg.xy_domain("Fixed"), vg.x_tick_format("%b"), vg.color_domain(domain), vg.color_range(colors), vg.r_domain("Fixed"), vg.r_range([2, 10]), vg.width(680), vg.height(300), ), ), vg.plot( vg.bar_x(weather, x=vg.count(), y="weather", fill="#ccc", fill_opacity=0.2), vg.bar_x( data=weather, filter_by=range, x=vg.count(), y="weather", fill="weather" ), vg.toggle_y(bind=click), vg.highlight(by=click), vg.x_domain("Fixed"), vg.y_domain(domain), vg.y_label(None), vg.color_domain(domain), vg.color_range(colors), vg.width(680), ), ) ``` --- --- url: /mosaic/examples/contours.md --- # Contour Plot Here `heatmap` and `contour` marks visualize the density of data points in a scatter plot of penguin measurments. Setting the `fill` color to `"species"` subdivides the data into three sets of densities. ## Specification ```py \[Python] import vgplot as vg penguins = vg.parquet("data/penguins.parquet") bandwidth = vg.param(40) thresholds = vg.param(10) view = vg.vconcat( vg.hconcat( vg.slider(label="Bandwidth (σ)", bind=bandwidth, min=1, max=100), vg.slider(label="Thresholds", bind=thresholds, min=2, max=20), ), vg.plot( vg.heatmap( penguins, x="bill_length", y="bill_depth", fill="species", bandwidth=bandwidth, ), vg.contour( penguins, x="bill_length", y="bill_depth", stroke="species", bandwidth=bandwidth, thresholds=thresholds, ), vg.dot(penguins, x="bill_length", y="bill_depth", fill="currentColor", r=1), vg.x_axis("bottom"), vg.x_label_anchor("center"), vg.y_axis("right"), vg.y_label_anchor("center"), vg.margins(top=5, bottom=30, left=5, right=50), vg.width(700), vg.height(480), ), ) ``` --- --- url: /mosaic/examples/density-groups.md --- # Density Groups Density plots of penguin bill depths, grouped by species. The normalize parameter supports different forms of comparison, controlling if an individual density estimate is scaled by total point mass or normalized by the sum or max of the point mass. The stack and offset parameters control stacking of density areas. ## Specification ```py \[Python] import vgplot as vg penguins = vg.parquet("data/penguins.parquet") bandwidth = vg.param(20) normalize = vg.param("none") stack = vg.param(False) offset = vg.param(None) view = vg.vconcat( vg.hconcat( vg.menu(label="Normalize", bind=normalize, options=["none", "sum", "max"]), vg.menu(label="Stack", bind=stack, options=[False, True]), vg.menu( label="Offset", bind=offset, options=[vg.option("none", value=None), "normalize", "center"], ), ), vg.plot( vg.density_y( penguins, x="bill_depth", fill="species", fill_opacity=0.4, bandwidth=bandwidth, normalize=normalize, stack=stack, offset=offset, ), vg.margin_left(50), vg.height(200), ), ) ``` --- --- url: /mosaic/examples/density1d.md --- # Density 1D Density plots (`densityY` mark) for over 200,000 flights, created using kernel density estimation. Binning is performned in-database, subsequent smoothing in-browser. The distance density uses a log-scaled domain. To change the amount of smoothing, use the slider to set the kernel bandwidth. ## Specification ```py \[Python] import vgplot as vg flights = vg.parquet("data/flights-200k.parquet") brush = vg.selection.crossfilter() bandwidth = vg.param(20) view = vg.vconcat( vg.slider(label="Bandwidth (σ)", bind=bandwidth, min=0.1, max=100, step=0.1), vg.plot( vg.density_y( data=flights, filter_by=brush, x="delay", fill="#888", fill_opacity=0.5, bandwidth=bandwidth, ), vg.interval_x(bind=brush), vg.y_axis(None), vg.x_domain("Fixed"), vg.width(600), vg.margin_left(10), vg.height(200), ), vg.plot( vg.density_y( data=flights, filter_by=brush, x="distance", fill="#888", fill_opacity=0.5, bandwidth=bandwidth, ), vg.interval_x(bind=brush), vg.y_axis(None), vg.x_scale("log"), vg.x_domain("Fixed"), vg.width(600), vg.margin_left(10), vg.height(200), ), ) ``` --- --- url: /mosaic/examples/density2d.md --- # Density 2D A 2D `density` plot in which circle size indicates the point density. The data is divided by fill color into three sets of densities. To change the amount of smoothing, use the slider to set the kernel bandwidth. ## Specification ```py \[Python] import vgplot as vg penguins = vg.parquet("data/penguins.parquet") bandwidth = vg.param(20) bins = vg.param(20) view = vg.vconcat( vg.hconcat( vg.slider(label="Bandwidth (σ)", bind=bandwidth, min=1, max=100), vg.slider(label="Bins", bind=bins, min=10, max=60), ), vg.plot( vg.density( penguins, x="bill_length", y="bill_depth", r="density", fill="species", fill_opacity=0.5, width=bins, height=bins, bandwidth=bandwidth, ), vg.dot(penguins, x="bill_length", y="bill_depth", fill="currentColor", r=1), vg.r_range([0, 16]), vg.x_axis("bottom"), vg.x_label_anchor("center"), vg.y_axis("right"), vg.y_label_anchor("center"), vg.margins(top=5, bottom=30, left=5, right=50), vg.width(700), vg.height(480), ), ) ``` --- --- url: /mosaic/examples/flights-density.md --- # Flights Density Density `heatmap` and `contour` lines for 200,000+ flights by departure hour and arrival delay. The sliders adjust the smoothing (bandwidth) and number of contour thresholds. ## Specification ```py \[Python] import vgplot as vg flights = vg.parquet("data/flights-200k.parquet") bandwidth = vg.param(7) thresholds = vg.param(10) view = vg.vconcat( vg.hconcat( vg.slider(label="Bandwidth (σ)", bind=bandwidth, min=1, max=100), vg.slider(label="Thresholds", bind=thresholds, min=2, max=20), ), vg.plot( vg.heatmap(flights, x="time", y="delay", fill="density", bandwidth=bandwidth), vg.contour( flights, x="time", y="delay", stroke="white", stroke_opacity=0.5, bandwidth=bandwidth, thresholds=thresholds, ), vg.color_scale("symlog"), vg.color_scheme("ylgnbu"), vg.x_axis("top"), vg.x_label_anchor("center"), vg.x_zero(True), vg.y_axis("right"), vg.y_label_anchor("center"), vg.margin_top(30), vg.margin_left(5), vg.margin_right(40), vg.width(700), vg.height(500), ), ) ``` --- --- url: /mosaic/examples/flights-hexbin.md --- # Flights Hexbin Hexagonal bins show the density of over 200,000 flights by departure time and arrival delay. Select regions in the marginal histograms to filter the density display. ## Specification ```py \[Python] import vgplot as vg flights = vg.parquet("data/flights-200k.parquet") scale = vg.param("log") query = vg.selection.intersect() view = vg.vconcat( vg.hconcat( vg.menu(label="Color Scale", bind=scale, options=["log", "linear", "sqrt"]), vg.hspace(10), vg.color_legend(plot="hexbins"), ), vg.hconcat( vg.plot( vg.rect_y( flights, x=vg.bin("time"), y=vg.count(), fill="steelblue", inset=0.5 ), vg.interval_x(bind=query), vg.margins(left=5, right=5, top=30, bottom=0), vg.x_domain("Fixed"), vg.x_axis("top"), vg.y_axis(None), vg.x_label_anchor("center"), vg.width(605), vg.height(70), ), vg.hspace(80), ), vg.hconcat( vg.plot( vg.hexbin( data=flights, filter_by=query, x="time", y="delay", fill=vg.count(), bin_width=10, ), vg.hexgrid(bin_width=10), vg.name("hexbins"), vg.color_scheme("ylgnbu"), vg.color_scale(scale), vg.margins(left=5, right=0, top=0, bottom=5), vg.x_axis(None), vg.y_axis(None), vg.xy_domain("Fixed"), vg.width(600), vg.height(455), ), vg.plot( vg.rect_x( flights, x=vg.count(), y=vg.bin("delay"), fill="steelblue", inset=0.5 ), vg.interval_y(bind=query), vg.margins(left=0, right=50, top=4, bottom=5), vg.y_domain([-60, 180]), vg.x_axis(None), vg.y_axis("right"), vg.y_label_anchor("center"), vg.width(80), vg.height(455), ), ), ) ``` --- --- url: /mosaic/examples/line-density.md --- # Line Density The `denseLine` mark shows the densities of line series, here for a collection of stock prices. The top plot normalizes by arc length to remove the vertical artifacts visible in the unnormalized plot below. Select a region in the lower plot to zoom the upper plot. The bandwidth slider smooths the data, while the pixel size menu adjusts the raster resolution. ## Specification ```py \[Python] import vgplot as vg stocks_after_2006 = vg.parquet( "data/stocks_after_2006.parquet", select=["Symbol", "Close", "Date"], where="Close < 100", ) brush = vg.selection.intersect() bandwidth = vg.param(0) pixelSize = vg.param(2) schemeColor = vg.param("pubugn") scaleColor = vg.param("sqrt") view = vg.vconcat( vg.hconcat( vg.slider(label="Bandwidth (σ)", bind=bandwidth, min=0, max=10, step=0.1), vg.menu(label="Pixel Size", bind=pixelSize, options=[0.5, 1, 2]), ), vg.vspace(10), vg.plot( vg.dense_line( data=stocks_after_2006, filter_by=brush, x="Date", y="Close", z="Symbol", fill="density", bandwidth=bandwidth, pixel_size=pixelSize, ), vg.color_scheme(schemeColor), vg.color_scale(scaleColor), vg.y_label("Close (Normalized) ↑"), vg.y_nice(True), vg.margins(left=30, top=20, right=0), vg.width(680), vg.height(240), ), vg.plot( vg.dense_line( stocks_after_2006, x="Date", y="Close", z="Symbol", fill="density", normalize=False, bandwidth=bandwidth, pixel_size=pixelSize, ), vg.interval_xy(bind=brush), vg.color_scheme(schemeColor), vg.color_scale(scaleColor), vg.y_label("Close (Unnormalized) ↑"), vg.y_nice(True), vg.margins(left=30, top=20, right=0), vg.width(680), vg.height(240), ), ) ``` --- --- url: /mosaic/api/core/client.md --- # Client The `MosaicClient` class provides a base class for client implementation. Clients are responsible for publishing their data needs and performing data processing tasks—such as rendering a visualization—once data is provided by the [coordinator](./coordinator). If you are interested in creating your own Mosaic clients, see the [Mosaic GitHub repository](https://github.com/uwdata/mosaic). For concrete examples, start with the source code of [Mosaic inputs](https://github.com/uwdata/mosaic/tree/main/packages/vgplot/inputs/src). If you are creating clients for web frameworks such as React, Svelte, or Vue, see the [web clients](/web-clients/) documentation. ## constructor `new MosaicClient(filterSelection)` Create a new client instance. If provided, the [Selection](./selection)-valued *filterSelection* argument will be exposed as the client's [`filterBy`](#filterby) property. ## filterBy `client.filterBy` Property getter for the Selection that should filter this client. The [coordinator](./coordinator) uses this property to provide automatic updates to the client upon selection changes. ## filterStable `client.filterStable` Property getter for a Boolean value indicating if the client query can be safely optimized using a pre-aggregated materialized view. This property should return true if changes to the `filterBy` selection do not change the groupby (e.g., binning) values of the client query. The `MosaicClient` base class will always return `true`. Subclasses should override the property getter to provide more nuanced results as needed. ## fields `client.fields()` Return an array of field requests, called by the [coordinator](./coordinator) when the client is first connected. Each field request should be an object with `table` and `column` properties. The coordinator will then return column metadata via the client [`fieldInfo()`](#fieldinfo) method. The `MosaicClient` base class will always return `null`, indicating no field metadata is needed. Subclasses should override this method to provide more nuanced results as needed. ## fieldInfo `client.fieldInfo(info)` Called by the [coordinator](./coordinator) to set the field information for this client. The *info* argument will be an array of objects with the table name, column name, and type information. The `MosaicClient` base class does nothing here. Subclasses should override this method to process and retain field information as needed. ## query `client.query(filter)` Return a query specifying the data needed by this client, incorporating any requested *filter* criteria. If provided, the *filter* argument should consist of Boolean-valued SQL predicates, suitable for inclusion in a `WHERE` clause. The `MosaicClient` base class simply returns `null`. Subclasses should override this method to provide a query, typically constructed using [Mosaic SQL builder](/sql/) utilities. ## queryPending `client.queryPending()` Called by the [coordinator](./coordinator) to inform the client that a query is pending. The *info* argument will be an array of objects with the table name, column name, and type information. This method should return the current client instance. The `MosaicClient` base class does nothing here. Subclasses should override this method as needed. ## queryResult `client.queryResult(data)` Called by the [coordinator](./coordinator) to return query results in the form of a *data* table. This method should return the current client instance. The `MosaicClient` base class does nothing here. Subclasses should override this method as needed. ## queryError `client.queryError(error)` Called by the [coordinator](./coordinator) to report that an *error* occurred during query processing. This method should return the current client instance. The `MosaicClient` base class reports the error to `console.error`. Subclasses should override this method as needed. ## update `client.update()` Requests that a client update using its current data, for example to (re-)render an interface component, and returns the current client instance. Called by the [coordinator](./coordinator) after returning data via the [`queryResult`](#queryresult) method. The `MosaicClient` base class does nothing here. Subclasses should override this method as needed. ## requestQuery `client.requestQuery(query)` Requests that the [coordinator](./coordinator) execute a query for this client, and returns a Promise that resolves upon query completion or error. If an explicit query is not provided, the client [`query`](#query) method will be called, filtered by the current [`filterBy`](#filterby) selection. ## requestUpdate `client.requestUpdate()` Request that the [coordinator](./coordinator) perform a throttled update of this client using the default query provided by the [`query`](#query) method. Unlike [`requestQuery`](#requestquery), for which every call will result in an executed query, multiple calls to `requestUpdate` may be consolidated. --- --- url: /mosaic/api/core/coordinator.md --- # Coordinator The Mosaic coordinator manages queries for Mosaic clients. Internally, the coordinator includes a query manager that maintains a queue of query requests that are issued through a database [connector](./connectors). The coordinator also manages *filter groups*: collections of clients that share the same [`filterBy`](./client#filterby) selection. The coordinator responds to selection changes and provides coordinated updates to all linked clients. Where possible, the coordinator also applies optimizations, such as caching and building optimized indices for filter groups involving supported aggregation queries. ## coordinator {#coordinator-global} `coordinator()` Get the default global coordinator instance. ## constructor `new Coordinator(connector, options)` Create a new Mosaic Coordinator to manage all database communication for clients and handle selection updates. Accepts a database *connector* and an *options* object: * *logger*: The logger to use, defaults to `console`. * *cache*: Boolean flag to enable/disable query caching (default `true`). * *consolidate* Boolean flag to enable/disable query consolidation (default `true`). * *preagg*: Pre-aggregation options object. The *enabled* flag (default `true`) determines if pre-aggregation optimizations should be used when possible. The *schema* option (default `'mosaic'`) indicates the database schema in which materialized view tables should be created for pre-aggregated data. ## databaseConnector `coordinator.databaseConnector(connector)` Get or set the [*connector*](./connectors) used by the coordinator to issue queries to a backing data source. ## connect `coordinator.connect(client)` Connect a [*client*](./client) to this coordinator. Upon connection, the [client lifecycle](/core/) will initiate. If the client exposes a `filterBy` selection, the coordinator will handle updates to the client when the selection updates. ## disconnect `coordinator.disconnect(client)` Disconnect the [*client*](./client) from the coordinator and remove all update handling. ## logger `coordinator.logger(logger)` Get or set the coordinator's logger. The logger defaults to the standard JavaScript `console`. A logger instance must support `log`, `info`, `warn`, and `error` methods. If set to `null`, logging will be suppressed. ## clear `coordinator.clear(options)` Resets the state of the coordinator. Supports the following *options*: * *clients*: A Boolean flag (default `true`) indicating if all current clients should be disconnected. * *cache*: A Boolean flag (default `true`) indicating if the query cache should be cleared. ## exec `coordinator.exec(query, options)` Request a *query* and return a request Promise that resolves when the query is complete. No query result will be returned. The input *query* should produce a SQL query upon string coercion. The supported *options* are: * *priority*: A value indicating the query priority, one of: `Priority.High`, `Priority.Normal` (the default), or `Priority.Low`. ## query `coordinator.query(query, options)` Request a *query* and return a request Promise that resolves when the query is complete. A query result table will be returned, with format determined by the *type* options. The input *query* should produce a SQL query upon string coercion. The supported *options* are: * *type*: The return format type. One of `"arrow"` (default) or `"json"`. * *cache*: A Boolean flag (default `true`) indicating if the query result should be cached. * *priority*: A value indicating the query priority, one of: `Priority.High`, `Priority.Normal` (the default), or `Priority.Low`. Any additional options will be passed through to the backing database. For example, the Mosaic [data server](../duckdb/data-server) will respect a *persist* option to cache the result on the server's local file system. ## prefetch `coordinator.prefetch(query, options)` Request a *query* to prefetch the results for later use, and return a request Promise that resolves when the query is complete. This method accepts the same *options* as [`query()`](#query), except that the *cache* flag will always be true and the *priority* flag will always be `Priority.Low`. If prefetch requests are no longer needed, the [`cancel`](#cancel) method can be used to drop any queued but not yet issued queries. ## cancel `coordinator.cancel(requests)` Cancel the provided query *requests*, a list of one or more request Promise instances returned by earlier `exec`, `query`, or `prefetch` calls. ## updateClient `coordinator.updateClient(client, query, priority)` Initiate a *client* update for a given *query* and *priority* (default `Priority.Normal`), and return a Promise that resolves when the query is complete. The [`client.queryPending()`](./client#querypending) method will be invoked, followed by [`client.queryResult()`](./client#queryresult) or [`client.queryError()`](./client#queryerror) upon completion. ::: warning This method is used internally, application code should *not* call this method directly. ::: ## requestQuery `coordinator.requestQuery(client, query)` Request a query update for the provided *client*. If the *query* argument is provided, [`updateClient()`](#updateclient) is invoked. Otherwise, the client [`update()`](./client#update) method is called immediately. ::: warning This method is used internally, application code should *not* call this method directly. ::: --- --- url: /mosaic/api/core/connectors.md --- # Connectors Database connectors issue query requests to a backing data source. A connector instance should expose a `query(query)` method that returns a Promise. The *query* argument is an object that may include the following properties: * *sql*: The SQL query to evaluate. * *type*: The query format type, such as `"exec"` (no return value), `"arrow"`, and `"json"`. * Any additional connector-specific options. Once instantiated, register a connector with the coordinator using the [`coordinator.databaseConnector()`](coordinator#databaseconnector) method. ## socketConnector `socketConnector(uri)` Create a new Web Socket connector to a DuckDB [data server](../duckdb/data-server) at the given *uri* (default `"ws://localhost:3000/"`). ## restConnector `restConnector(uri)` Create a new HTTP rest connector to a DuckDB [data server](../duckdb/data-server) at the given *uri* (default `"http://localhost:3000/"`). ## wasmConnector `wasmConnector(options)` Create a new DuckDB-WASM connector with the given *options*. This method will instantiate a new DuckDB instance in-browser using Web Assembly. If no existing DuckDB-WASM instance is provided as an option, a new instance is created lazily upon first access. The supported options are: * *duckdb*: An existing DuckDB-WASM instance to query. If unspecified, a new instance is created. * *connection*: An existing connection to a DuckDB-WASM instance to use. If unspecified, a new connection is created. * *log*: A Boolean flag (default `false`) that indicates if DuckDB-WASM logs should be written to the browser console. This option is ignored when an existing *duckdb* instance option is provided. --- --- url: /mosaic/api/core/param.md --- # Param A `Param` is a reactive variable for an individual value. ## isParam `isParam(value)` Returns `true` if the input value is a `Param`, false otherwise. ## Param.value `Param.value(value)` Create a new Param with the given initial *value*. ## Param.array `Param.array(values)` Create a new Param over an array of initial *values*, which may contain nested Params. ## value `param.value` Retrieves the current value of a Param instance. ## update `param.update(value, options)` Update the Param with a new *value*. The *options* object may include a *force* flag indicating if the Param should emit a 'value' event even if the internal value is unchanged. ## addEventListener `param.addEventListener(type, callback)` Add an event listener *callback* function for the specified event *type*. Params support `"value"` type events only. ## removeEventListener `param.removeEventListener(type, callback)` Remove an event listener *callback* function for the specified event *type*. --- --- url: /mosaic/api/core/selection.md --- # Selection A `Selection` is a specialized [`Param`](./param) that manages a collection of Boolean-valued predicates that can be used to interactively filter a data source. Selections apply a *resolution* strategy to merge clauses into client-specific predicates: * The `single` strategy simply includes only the most recent clause. * The `union` strategy performs disjunction, combining all predicates via Boolean `OR`. * The `intersect` strategy performs conjunction via Boolean `AND`. In addition, selections can be *cross-filtered*, so that they affect views other than the one currently being interacted with. The strategies above are modified to omit clauses where the *clients* set includes the input argument to the `predicate()` function. By default, a selection without any clauses selects all records. To instead select no records, set the *empty* option to `true`. A Selection can `include` the clauses of one or more upstream selections. New clauses or activations published to those selections will be relayed to any selections that include them. Beyond these relays, the selections act independently and so may apply different resolution strategies. ## isSelection `isSelection(value)` Returns `true` if the input value is a `Selection`, false otherwise. ## Selection.intersect `Selection.intersect(options)` Create a new Selection instance with an intersect (conjunction) resolution strategy. The *options* object may include: * A Boolean *cross* flag (default `false`) indicating cross-filtered resolution. If true, selection clauses will not be applied to the clients they are associated with. * An *empty* flag (default `false`) indicates whether a selection without any clauses should select an empty set with no records (`true`) or select all records (`false`). * An *include* option (default `[]`) indicating one or more selections whose clauses should be included as part of this selection. The option value can be either a single `Selection` instance or an array of `Selection` instances. ## Selection.union `Selection.union(options)` Create a new Selection instance with a union (disjunction) resolution strategy. The *options* object may include: * A Boolean *cross* flag (default `false`) indicating cross-filtered resolution. If true, selection clauses will not be applied to the clients they are associated with. * An *empty* flag (default `false`) indicates whether a selection without any clauses should select an empty set with no records (`true`) or select all records (`false`). * An *include* option (default `[]`) indicating one or more selections whose clauses should be included as part of this selection. The option value can be either a single `Selection` instance or an array of `Selection` instances. ## Selection.single `Selection.single(options)` Create a new Selection instance with a singular resolution strategy that keeps only the most recent selection clause. The *options* object may include: * A Boolean *cross* flag (default `false`) indicating cross-filtered resolution. If true, selection clauses will not be applied to the clients they are associated with. * An *empty* flag (default `false`) indicates whether a selection without any clauses should select an empty set with no records (`true`) or select all records (`false`). * An *include* option (default `[]`) indicating one or more selections whose clauses should be included as part of this selection. The option value can be either a single `Selection` instance or an array of `Selection` instances. ## Selection.crossfilter `Selection.crossfilter()` Create a new Selection instance with a cross-filtered intersect resolution strategy. This is a convenience method for `Selection.intersect({ cross: true })`. ## clone `selection.clone()` Create a cloned copy of this Selection instance. ## remove `selection.remove(source)` Create a clone of this Selection with clauses corresponding to the provided *source* removed. ## active `selection.active` Property getter for the current active (most recently updated) selection clause. ## value `selection.value` The value corresponding to the current active selection clause. Selections override the [`Param.value`](./param#value) property to return the active clause *value*, making selections compatible where standard params are expected. ## valueFor `selection.valueFor(source)` The value corresponding to a given clause *source*. Returns `undefined` if this selection does not include a clause from this source. ## clauses `selection.clauses` The current array of selection clauses. ## activate `selection.activate(clause)` Emit an `activate` event with the given selection clause. These `activate` events provide a clause indicative of likely future updates. For example, a brush interactor may trigger an activation event when the cursor enters a brushable region, providing an example clause prior to any actual updates. Activation events can be used to implement optimizations such as prefetching. ## update `selection.update(clause)` Update the selection with a new selection *clause*. A *clause* is an object consisting of: * the *source* component (such as a client or interactor) providing the clause, * a set of *clients* associated with the clause, indicating the clients that should be skipped in the case of cross-filtering, * a query *predicate* (e.g, the range predicate `column BETWEEN 0 AND 1`), * a corresponding *value* (e.g., the range array `[0,1]`), and * an optional *schema* providing clause metadata. Upon update, any prior clause with the same *source* is removed and the new, most recent clause (called the *active* clause) is added. ## predicate `selection.predicate(client)` Return a selection query predicate for the given Mosaic *client*. The resulting predicate can be used as part of a SQL `WHERE` clause. ## addEventListener `selection.addEventListener(type, callback)` Add an event listener *callback* function for the specified event *type*. Selections support both `"value"` and `"activate"` type events. ## removeEventListener `selection.removeEventListener(type, callback)` Remove an event listener *callback* function for the specified event *type*. ## pending `selection.pending(type)` Returns a promise that resolves when any pending updates complete for the event of the given type currently being processed. The Promise will resolve immediately if the queue for the given event type is empty. --- --- url: /mosaic/api/core/multi-database-support.md --- # Multi-Database Support Mosaic uses DuckDB, which [supports multiple databases](https://duckdb.org/2024/01/26/multi-database-support-in-duckdb.html) such as MySQL, PostgreSQL, and SQLite, via [DuckDB extensions](https://duckdb.org/docs/extensions/overview.html). This capability allows data to be read into DuckDB and transferred between systems, enabling flexible and interoperable data management. Mosaic can take advantage of these features to visualize data stored in alternative databases. As shown in the examples below, database configuration can be performed via direct DuckDB queries. Once configured, Mosaic can be used in a normal fashion. ## Connect to PostgreSQL ```js import * as vg from "@uwdata/vgplot"; // database configuration info // replace values with your specific configuration const config = { dbname: "YOUR_DATABASE_NAME", user: "postgres", password: "YOUR_PASSWORD", host: "YOUR_HOST_IP" }; // map configuration info to a connection string const postgres_connection_string = Object.entries(config) .map([key, value] => `${key}=${value}`) .join(" "); await vg.coordinator().exec([ // attach and use a PostgreSQL database `ATTACH '${postgres_connection_string}' AS postgres_db (TYPE POSTGRES)`, "USE postgres_db", vg.loadParquet("ca55", "data/ca55-south.parquet") // load a dataset ]); // create interactive visualizations for your dataset as usual! // here we've copied the aeromagnetic-survey example... const $interp = vg.Param.value("random-walk"); const $blur = vg.Param.value(0); export default vg.vconcat( vg.hconcat( vg.menu({ label: "Interpolation Method", options: ["none", "nearest", "barycentric", "random-walk"], as: $interp }), vg.hspace("1em"), vg.slider({label: "Blur", min: 0, max: 100, as: $blur}) ), vg.vspace("1em"), vg.plot( vg.raster( vg.from("ca55"), { x: "LONGITUDE", y: "LATITUDE", fill: vg.max("MAG_IGRF90"), interpolate: $interp, bandwidth: $blur } ), vg.colorScale("diverging"), vg.colorDomain(vg.Fixed) ) ); ``` ## Connect to MySQL ```js import * as vg from "@uwdata/vgplot"; // database configuration info // replace values with your specific configuration const config = { database: "YOUR_DATABASE_NAME", user: "root", password: "YOUR_PASSWORD", host: "YOUR_HOST_IP", port: "YOUR_PORT" }; // map configuration info to a connection string const mysql_connection_string = Object.entries(config) .map([key, value] => `${key}=${value}`) .join(" "); await vg.coordinator().exec([ // attach and use a MySQL database `ATTACH '${mysql_connection_string}' AS mysqldb (TYPE MYSQL)`, "USE mysqldb", vg.loadParquet("ca55", "data/ca55-south.parquet") // load a dataset ]); // now add Mosaic specification code as usual! ``` ## Connect to SQLite ```js import * as vg from "@uwdata/vgplot"; await vg.coordinator().exec([ // attach and use a SQLite database `ATTACH 'sakila.db' (TYPE SQLITE)`, "USE sakila", vg.loadParquet("ca55", "data/ca55-south.parquet") // load the dataset ]); // now add Mosaic specification code as usual! ``` --- --- url: /mosaic/api/sql/queries.md --- # Queries SQL query builders. These utilities build structured representations of queries that are easier to create, manipulate, and analyze. For example, here is a basic group-by aggregation query that counts the number of records and adds up values by category: ```js import { Query, count, gt, sum } from "@uwdata/mosaic-sql"; // SELECT "column", count() AS "count", sum("value") AS "value" // FROM "table" WHERE "value" > 0 GROUP BY "column" Query .from("table") .select("category", { count: count(), sum: sum("value") }) .groupby("category") .where(gt("value", 0)) ``` Here is an overview of available methods: ```js Query .with(/* a map of named common table expression queries */) .select(/* column names or name -> expression maps */) .distinct(/* boolean to denote distinct values only */) .from(/* source table names or subqueries */) .sample(/* number of rows or % to sample */) .where(/* filter criteria */) .groupby(/* columns or expressions to group by */) .having(/* post-aggregation filter criteria */) .window(/* named window definitions */) .qualify(/* post-window filter criteria */) .orderby(/* columns or expressions to sort by */) .limit(/* max number of rows */) .offset(/* offet number of rows */) ``` To learn more about the anatomy of a query, take a look at the [DuckDB Select statement documentation](https://duckdb.org/docs/sql/statements/select). ## Query The top-level `Query` class, along with its concrete `SelectQuery` and `SetOperation` subclasses, provide structured representations of SQL queries. The `Query.pivot()` static method additionally returns `PivotQuery` instances for DuckDB simplified `PIVOT` queries. Upon string coercion, these objects produce a complete SQL query string. The following static methods create a new `SelectQuery` and invoke the corresponding method: * `Query.select()`: See the [`select`](#select) method below. * `Query.from()`: See the [`from`](#from) method below. The following static method creates a new `PivotQuery`: * `Query.pivot(source)`: See the [`PivotQuery`](#pivotquery) section below. In addition, the following static methods take multiple queries as input and return `SetOperation` instances: * `Query.union(...queries)`: Union results with de-duplication of rows. * `Query.unionByName(...queries)`: Union results with de-duplication of rows, combining rows from different tables by name, instead of by position. * `Query.unionAll(...queries)`: Union results with no de-duplication of rows. * `Query.unionAllByName(...queries)`: Union results with no de-duplication of rows, combining rows from different tables by name, instead of by position. * `Query.intersect(...queries)`: Query for distinct rows that are output by both the left and right input queries. * `Query.intersectAll(...queries)`: Query for all rows that are output by both the left and right input queries using bag semantics, so duplicates are returned. * `Query.except(...queries)`: Query for distinct rows from the left input query that aren't output by the right input query. * `Query.exceptAll(...queries)`: Query for all rows from the left input query that aren't output by the right input query using bag semantics, so duplicates are returned. Common table expressions can be applied via static method * `Query.with()`: See the [`with`](#with) method below. Each of the methods described above can also be utilized in conjunction with a WITH clause. For example, `Query.with().select()` results in a `SelectQuery`, whereas `Query.with().union()` will produce a `SetOperation`. To instead create a query for metadata (column names and types), pass a query to the static `describe` method: * `Query.describe(query)`: Request a description of the columns that a query will produce, with one row per selected column. ## PivotQuery `Query.pivot(source)` Create a DuckDB [`PIVOT`](https://duckdb.org/docs/sql/statements/pivot.html#simplified-pivot-syntax) query using simplified syntax over *source* and return a `PivotQuery`. The *source* may be a table name string, a table name path such as `["schema", "table"]`, or a SQL node such as a query or [`sql`](./expressions#sql) expression. Use `PivotQuery` methods to add `ON`, `IN`, `USING`, and `GROUP BY` clauses. ```js import { Query, sum } from "@uwdata/mosaic-sql"; // PIVOT "sales" ON "year" IN (2020, 2021) USING sum("amount") AS "total" GROUP BY "region" Query .pivot("sales") .on("year") .in(2020, 2021) .using({ total: sum("amount") }) .groupby("region") ``` This method produces DuckDB's simplified `PIVOT` syntax, not the SQL-standard `SELECT ... FROM dataset PIVOT (...)` form. DuckDB expects at least one of the `ON`, `USING`, or `GROUP BY` clauses when executing a `PIVOT`. A `PivotQuery` also supports the shared `Query` methods `with`, `orderby`, `setOrderby`, `limit`, `limitPercent`, and `offset`, and may be passed to `from` as a subquery. ### on `PivotQuery.on(...expressions)` Add `ON` expressions whose values determine pivot output columns and return this query instance. The *expressions* may be column name strings, [`column`](./expressions#column) references, or other SQL expressions. This method is additive: any previously defined `ON` expressions will still remain. ### in `PivotQuery.in(...values)` Add `IN` values associated with the `ON` clause and return this query instance. The values constrain and order pivot output columns, and are only meaningful when an `ON` clause is present. Non-node values are rendered as SQL literals, so string values become SQL string literals. At least one value is required. This method is additive: any previously defined `IN` values will still remain. ### using `PivotQuery.using(...expressions)` Add `USING` aggregate expressions that populate pivot output cells and return this query instance. The *expressions* may be aggregate expressions or maps from aliases to aggregate expressions. At least one expression is required when calling `using`. If `using` is not called, the `USING` clause is omitted and DuckDB defaults to `count(*)`. This method is additive: any previously defined `USING` expressions will still remain. ### groupby `PivotQuery.groupby(...expressions)` Add `GROUP BY` expressions that define pivot row groups and return this query instance. DuckDB's simplified `PIVOT` expects column names in `GROUP BY`. This method is additive: any previously defined `GROUP BY` expressions will still remain. ### setGroupby `PivotQuery.setGroupby(...expressions)` Set `GROUP BY` expressions, replacing any prior pivot group by criteria, and return this query instance. ## isPivotQuery `isPivotQuery(value)` Return true if *value* is a `PivotQuery` instance. ## clone `Query.clone()` Return a new query that is a shallow copy of the current instance. ## subqueries `Query.subqueries` The `subqueries` getter property returns an array of subquery instances, or an empty array if there are no subqueries. For selection queries, the subqueries may include common table expressions within `WITH` or nested queries within `FROM`. For set operations, the subqueries are the set operation arguments. ## toString `Query.toString()` Coerce this query object to a SQL query string. ## select `SelectQuery.select(...expressions)` Select columns and return this query instance. The *expressions* argument may include column name strings, [`column` references](./expressions#column), and maps from column names to expressions (either as JavaScript `object` values or nested key-value arrays as produced by `Object.entries`). ## from `SelectQuery.from(...tables)` Indicate the tables to draw records from and return this query instance. The *tables* may be table name strings, queries or subquery expressions, and maps from table names to expressions (either as JavaScript `object` values or nested key-value arrays as produced by `Object.entries`). ## with `Query.with(...expressions)` Provide a set of named subqueries in the form of [common table expressions (CTEs)](https://duckdb.org/docs/sql/query_syntax/with.html) and return this query instance. The input *expressions* should consist of one or more maps (as JavaScript `object` values) from subquery names to query expressions and/or CTE instances produced by the `cte` method. ## distinct `SelectQuery.distinct(value = true)` Update the query to require `DISTINCT` values and return this query instance. ## sample `SelectQuery.sample(size, method)` Update the query to sample a subset of *rows* and return this query instance. If *size* is a number between 0 and 1, it is interpreted as a percentage of the full dataset to sample. Otherwise, it is interpreted as the number of rows to sample. The *method* argument is a string indicating the sample method, such as `"reservoir"`, `"bernoulli"` and `"system"`. See the [DuckDB Sample documentation](https://duckdb.org/docs/sql/samples) for more. ## where `SelectQuery.where(...expressions)` Update the query to additionally filter by the provided predicate *expressions* and return this query instance. This method is additive: any previously defined filter criteria will still remain. ## groupby `SelectQuery.groupby(...expressions)` Update the query to additionally group by the provided *expressions* and return this query instance. This method is additive: any previously defined group by criteria will still remain. ## having `SelectQuery.having(...expressions)` Update the query to additionally filter aggregate results by the provided predicate *expressions* and return this query instance. Unlike `where` criteria, which are applied before an aggregation, the `having` criteria are applied to aggregated results. This method is additive: any previously defined filter criteria will still remain. ## window `SelectQuery.window(...expressions)` Update the query with named window frame definitions and return this query instance. The *expressions* arguments should be JavaScript `object` values that map from window names to window frame definitions. This method is additive: any previously defined windows will still remain. ## qualify `SelectQuery.qualify(...expressions)` Update the query to additionally filter windowed results by the provided predicate *expressions* and return this query instance. Use this method instead of `where` to filter the results of window operations. This method is additive: any previously defined filter criteria will still remain. ## orderby `Query.orderby(...expressions)` Update the query to additionally order results by the provided *expressions* and return this query instance. This method is additive: any previously defined sort criteria will still remain. ## limit `Query.limit(rows)` Update the query to limit results to the specified number of *rows* and return this query instance. ## offset `Query.offset(rows)` Update the query to offset the results by the specified number of *rows* and return this query instance. --- --- url: /mosaic/api/sql/expressions.md --- # SQL Expressions SQL expression builders. All SQL expressions are represented in the form of an abstract syntax tree (AST). Helper methods and functions build out this tree. ## column `column(name)` Create an expression AST node that references a column by *name*. Upon string coercion, the column name will be properly quoted. ## cte `cte(name, query, materialized)` Create an AST node for a Common Table Expression (CTE) to be used within a SQL `WITH` clause. The resulting node can be passed as an argument to the `Query.with()` method. The string-valued *name* and Query-valued *query* arguments are required. The optional boolean-valued *materialized* argument indicates if the CTE should be materialized during query execution; if unspecified, it is left to the backing database to decide. ## literal `literal(value)` Create an expression AST node that references a literal *value*. Upon string coercion, an appropriate SQL value will be produced. For example, string literals will be properly quoted and JavaScript `Date` objects that match an exact UTC date will be converted to the SQL Date definitions. The supported primitive types are: boolean, null, number, string, regexp, and Date (maps to SQL Date or Timestamp depending on the value). ## sql ``sql`...` `` A template tag for arbitrary SQL expressions that do not require deep analysis. Creates an expression AST node with only a partially structured form consisting of unstructured text and interpolated values. Interpolated values may be strings, other SQL expressions (such as [`column` references](#column) or [operators](./operators)), or [`Param`](../core/param) values. The snippet below creates a dynamic expression that adds a Param value to a column. Contained column references can be extracted using the `collectColumns` method. Contained Param values can be extracted using the `collectParams` method. ```js const param = Param.value(5); sql`${column("foo")} + ${param}` ``` SQL expressions may be nested, in which case all nested column dependencies and parameter updates are still extractable via the collection visitors. --- --- url: /mosaic/api/sql/operators.md --- # Operators SQL comparison operator expressions. ## and `and(...clauses)` Returns an expression for the logical `AND` of the provided *clauses*. The *clauses* array will be flattened and any `null` entries will be ignored. ## or `or(...clauses)` Returns an expression for the logical `OR` of the provided *clauses*. The *clauses* array will be flattened and any `null` entries will be ignored. ## not `not(expression)` Returns an expression for the logical `NOT` of the provided *expression*. ## eq `eq(a, b)` Returns an expression testing if expression *a* is equal to expression *b*. In SQL semantics, two `NULL` values are not considered equal. Use `isNotDistinct` to compare values with `NULL` equality. ## neq `neq(a, b)` Returns an expression testing if expression *a* is not equal to expression *b*. In SQL semantics, two `NULL` values are not considered equal. Use `isDistinct` to compare values with `NULL` equality. ## lt `lt(a, b)` Returns an expression testing if expression *a* is less than expression *b*. ## gt `gt(a, b)` Returns an expression testing if expression *a* is greater than expression *b*. ## lte `lte(a, b)` Returns an expression testing if expression *a* is less than or equal to expression *b*. ## gte `gte(a, b)` Returns an expression testing if expression *a* is greater than or equal to expression *b*. ## isNull `isNull(expression)` Returns an expression testing if the input *expression* is a `NULL` value. ## isNotNull `isNotNull(expression)` Returns an expression testing if the input *expression* is not a `NULL` value. ## isDistinct `isDistinct(a, b)` Returns an expression testing if expression *a* is distinct from expression *b*. Unlike normal SQL equality checks, here `NULL` values are not considered distinct. ## isNotDistinct Returns an expression testing if expression *a* is not distinct from expression *b*. Unlike normal SQL equality checks, here `NULL` values are not considered distinct. ## isBetween `isBetween(expression, [lo, hi])` Returns an expression testing if the input *expression* lies between the values *lo* and *hi*, provided as a two-element array. Equivalent to `lo <= expression AND expression <= hi`. ## isNotBetween `isNotBetween(expression, [lo, hi])` Returns an expression testing if the input *expression* does not lie between the values *lo* and *hi*, provided as a two-element array. Equivalent to `NOT(lo <= expression AND expression <= hi)`. ## isIn `isIn(expression, values)` Returns an expression testing if the input *expression* matches any of the entries in the *values* array. Maps to `expression IN (...values)`. ## listContains `listContains(expression, value)` Returns an expression testing if the input *value* exists in the *expression* list. Maps to `list_contains(expression, value)`. ## listHasAny `listHasAny(expression, values)` Returns an expression testing if any of the input *values* exist in the *expression* list. Maps to `list_has_any(expression, values)`. ## listHasAll `listHasAll(expression, values)` Returns an expression testing if all the input *values* exist in the *expression* list. Maps to `list_has_all(expression, values)`. ## unnest `unnest(expression)` Returns an expression that unnests the *expression* list or struct. Maps to `UNNEST(expression)`. --- --- url: /mosaic/api/sql/date-functions.md --- # Date Functions SQL date function expressions. ## epoch\_ms `epoch_ms(expression)` Returns a function expression that maps the input date or datetime *expression* to the number of milliseconds since the UNIX epoch (Jan 1, 1970 UTC). ## dateBin `dateBin(expression, interval, steps = 1)` Returns a function expression that bins the input date or datetime *expression* to the given [date/time *interval*](https://duckdb.org/docs/sql/functions/datepart.html) such as `hour`, `day`, or `month`. The optional *steps* argument indicates an integer bin step size in terms of intervals, such as every 1 day or every 2 days. ## dateMonth `dateMonth(expression)` Returns a function expression that maps the input date or datetime *expression* to the first day of the corresponding month in the year 2012. This function is useful to map dates across varied years to a shared frame for cyclic comparison while maintaining a temporal data type. The year 2012 is a convenient target as it is a leap year that starts on a Sunday. ## dateMonthDay `dateMonthDay(expression)` Returns a function expression that maps the input date or datetime *expression* to the corresponding month and day in the year 2012. This function is useful to map dates across varied years to a shared frame for cyclic comparison while maintaining a temporal data type. The year 2012 is a convenient target as it is a leap year that starts on a Sunday. ## dateDay `dateDay(expression)` Returns a function expression that maps the input date or datetime *expression* to the corresponding day of the month in January 2012. This function is useful to map dates across varied years to a shared frame for cyclic comparison while maintaining a temporal data type. The year 2012 is a convenient target as it is a leap year that starts on a Sunday. --- --- url: /mosaic/api/sql/aggregate-functions.md --- # Aggregate Functions SQL aggregate function expressions. ## AggregateNode {#aggregate-node} The `AggregateNode` class represents a SQL AST node for an aggregate function call. Users should not need to instantiate `AggregateNode` instances directly, but instead should use aggregate function methods such as [`count()`](#count), [`sum()`](#sum), *etc*. ### distinct `AggregateNode.distinct()` Returns a new AggregateNode instance that applies the aggregation over distinct values only. ### where `AggregateNode.where(filter)` Returns a new AggregateNode instance filtered according to a Boolean-valied *filter* expression. ### window `AggregateNode.window()` Returns a windowed version of this aggregate function as a new [WindowNode](./window-functions#window-node) instance. ### partitionby `AggregateNode.partitionby(...expressions)` Provide one or more *expressions* by which to partition a windowed version of this aggregate function and returns a new [WindowNode](./window-functions#window-node) instance. ### orderby `AggregateNode.orderby(...expressions)` Provide one or more *expressions* by which to sort a windowed version of this aggregate function and returns a new [WindowNode](./window-functions#window-node) instance. ### rows `AggregateNode.rows(expression)` Provide a window "rows" frame specification as an array or array-valued *expression* and returns a windowed version of this aggregate function as a new [WindowNode](./window-functions#window-node) instance. A "rows" window frame is insensitive to peer rows (those that are tied according to the [orderby](#orderby) criteria). The frame expression should evaluate to a two-element array indicating the number of preceding or following rows. A zero value (`0`) indicates the current row. A non-finite value (including `null` and `undefined`) indicates either unbounded preceding row (for the first array entry) or unbounded following rows (for the second array entry). ### range `AggregateNode.range(expression)` Provide a window "range" frame specification as an array or array-valued *expression* and returns a windowed version of this aggregate function as a new [WindowNode](./window-functions#window-node) instance. A "range" window grows to include peer rows (those that are tied according to the [orderby](#orderby) criteria). The frame expression should evaluate to a two-element array indicating the number of preceding or following rows. A zero value (`0`) indicates the current row. A non-finite value (including `null` and `undefined`) indicates either unbounded preceding row (for the first array entry) or unbounded following rows (for the second array entry). ## count `count()` Create an aggregate function that counts the number of records. ## avg `avg(expression)` Create an aggregate function that calculates the average of the input *expression*. ## mad `mad(expression)` Create an aggregate function that calculates the median absolute deviation (MAD) of the input *expression*. ## max `max(expression)` Create an aggregate function that calculates the maximum of the input *expression*. ## min `min(expression)` Create an aggregate function that calculates the minimum of the input *expression*. ## sum `sum(expression)` Create an aggregate function that calculates the sum of the input *expression*. ## product `product(expression)` Create an aggregate function that calculates the product of the input *expression*. ## geomean `geomean(expression)` Create an aggregate function that calculates the geometric mean of the input *expression*. ## median `median(expression)` Create an aggregate function that calculates the average of the input *expression*. ## quantile `quantile(expression, p)` Create an aggregate function that calculates the *p*-th quantile of the input *expression*. For example, *p* = 0.5 computes the median, while 0.25 computes the lower inter-quartile range boundary. ## mode `mode(expression)` Create an aggregate function that calculates the mode of the input *expression*. ## variance `variance(expression)` Create an aggregate function that calculates the sample variance of the input *expression*. ## stddev `stddev(expression)` Create an aggregate function that calculates the sample standard deviation of the input *expression*. ## skewness `skewness(expression)` Create an aggregate function that calculates the skewness of the input *expression*. ## kurtosis `kurtosis(expression)` Create an aggregate function that calculates the kurtosis of the input *expression*. ## entropy `entropy(expression)` Create an aggregate function that calculates the entropy of the input *expression*. ## varPop `varPop(expression)` Create an aggregate function that calculates the population variance of the input *expression*. ## stddevPop `stddevPop(expression)` Create an aggregate function that calculates the population standard deviation of the input *expression*. ## corr `corr(a, b)` Create an aggregate function that calculates the correlation between the input expressions *a* and *b*. ## covarPop `covarPop(a, b)` Create an aggregate function that calculates the population covariance between the input expressions *a* and *b*. ## regrIntercept `regrIntercept(y, x)` Create an aggregate function that returns the intercept of the fitted linear regression model that predicts the target expression *y* based on the predictor expression *x*. ## regrSlope `regrSlope(y, x)` Create an aggregate function that returns the slope of the fitted linear regression model that predicts the target expression *y* based on the predictor expression *x*. ## regrCount `regrCount(y, x)` Create an aggregate function that returns the count of non-null values used to fit the linear regression model that predicts the target expression *y* based on the predictor expression *x*. ## regrR2 `regrR2(y, x)` Create an aggregate function that returns the R^2 value of the fitted linear regression model that predicts the target expression *y* based on the predictor expression *x*. ## regrSXX `regrSXX(y, x)` Create an aggregate function that returns the SXX value (`regrCount(y, x) * varPop(x)`) of the fitted linear regression model that predicts the target expression *y* based on the predictor expression *x*. ## regrSYY `regrSYY(y, x)` Create an aggregate function that returns the SYY value (`regrCount(y, x) * varPop(y)`) of the fitted linear regression model that predicts the target expression *y* based on the predictor expression *x*. ## regrSXY `regrSXY(y, x)` Create an aggregate function that returns the SXY (`regrCount(y, x) * covarPop(y, x)`) value of the fitted linear regression model that predicts the target expression *y* based on the predictor expression *x*. ## regrAvgX `regrAvgX(y, x)` Create an aggregate function that returns the average x value of the data used to fit the linear regression model that predicts the target expression *y* based on the predictor expression *x*. ## regrAvgY `regrAvgY(y, x)` Create an aggregate function that returns the average x value of the data used to fit the linear regression model that predicts the target expression *y* based on the predictor expression *x*. ## first `first(expression)` Create an aggregate function that calculates the first observed value of the input *expression*. ## last `last(expression)` Create an aggregate function that calculates the last observed value of the input *expression*. ## argmax `argmax(arg, value)` Create an aggregate function that returns the expression *arg* corresponding to the maximum value of the expression *value*. ## argmin `argmin(arg, value)` Create an aggregate function that returns the expression *arg* corresponding to the minimum value of the expression *value*. ## stringAgg `stringAgg(expression)` Create an aggregate function that returns the string concatenation of the input *expression* values. ## arrayAgg `arrayAgg(expression)` Create an aggregate function that returns a list of the input *expression* values. --- --- url: /mosaic/api/sql/window-functions.md --- # Window Functions SQL window function expressions. ## WindowNode {#window-node} The `WindowNode` class represents a window function. It includes a non-null `window` property indicating a window expression. Users should not need to instantiate `WindowNode` instances directly, but instead should use window function methods such as [`row_number()`](#row_number), [`lag()`](#lag), *etc*. ### over `WindowNode.over(name)` Provide the *name* of a window definition for this function and returns a new WindowNode instance. The window should be defined separately in an issued query, for example using the [Query.window](./queries#window) method. ### partitionby `WindowNode.partitionby(...expressions)` Provide one or more *expressions* by which to partition this window function and returns a new WindowFunction instance. ### orderby `WindowNode.orderby(...expressions)` Provide one or more *expressions* by which to sort this window function and returns a new WindowFunction instance. ### rows `WindowNode.rows(expression)` Provide a window "rows" frame specification as an array or array-valued *expression* and returns a new WindowNode instance. A "rows" window frame is insensitive to peer rows (those that are tied according to the [orderby](#orderby) criteria). The frame expression should evaluate to a two-element array indicating the number of preceding or following rows. A zero value (`0`) indicates the current row. A non-finite value (including `null` and `undefined`) indicates either unbounded preceding row (for the first array entry) or unbounded following rows (for the second array entry). ### range `WindowNode.range(expression)` Provide a window "range" frame specification as an array or array-valued *expression* and returns a new WindowNode instance. A "range" window grows to include peer rows (those that are tied according to the [orderby](#orderby) criteria). The frame expression should evaluate to a two-element array indicating the number of preceding or following rows. A zero value (`0`) indicates the current row. A non-finite value (including `null` and `undefined`) indicates either unbounded preceding row (for the first array entry) or unbounded following rows (for the second array entry). ## row\_number {#row\_number} `row_number()` Create a window function that returns the number of the current row within the partition, counting from 1. ## rank `rank()` Create a window function that returns the rank of the current row with gaps. This is the same as the row\_number of its first peer. ## dense\_rank {#dense\_rank} `dense_rank()` Create a window function that returns the rank of the current row without gaps, The function counts peer groups. ## percent\_rank {#percent\_rank} `percent_rank()` Create a window function that returns the relative rank of the current row. Equal to (rank() - 1) / (total partition rows - 1). ## cume\_dist {#cume\_dist} `cume_dist()` Create a window function that returns the cumulative distribution. (number of preceding or peer partition rows) / total partition rows. ## ntile `ntile(num_buckets)` Create a window function that r an integer ranging from 1 to *num\_buckets*, dividing the partition as equally as possible. ## lag `lag(expression, offset, default)` Create a window function that returns the *expression* evaluated at the row that is *offset* rows before the current row within the partition. If there is no such row, instead return *default* (which must be of the same type as the expression). Both offset and default are evaluated with respect to the current row. If omitted, offset defaults to 1 and default to null. ## lead `lead(expression, offset, default)` Create a window function that returns the *expression* evaluated at the row that is *offset* rows after the current row within the partition. If there is no such row, instead return *default* (which must be of the same type as the expression). Both offset and default are evaluated with respect to the current row. If omitted, offset defaults to 1 and default to null. ## first\_value {#first\_value} `first_value(expression)` Create a window function that returns the *expression* evaluated at the row that is the first row of the window frame. ## last\_value {#last\_value} `last_value(expression)` Create a window function that returns the *expression* evaluated at the row that is the last row of the window frame. ## nth\_value {#nth\_value} `nth_value(expression, nth)` Create a window function that returns the *expression* evaluated at the *nth* row of the window frame (counting from 1), or null if no such row. --- --- url: /mosaic/api/sql/data-loading.md --- # Data Loading SQL data loading utilities. These methods generate queries that create tables and load data into DuckDB. ## createTable `createTable(name, query, options)` Create a `CREATE TABLE` or `CREATE VIEW` query. The *options* object supports *replace* (use `OR REPLACE`), *temp* (temporary table/view), and *view* (create a view instead of a table). ## createSchema `createSchema(name, options)` Create a `CREATE SCHEMA` query. Set *strict* to `true` to omit `IF NOT EXISTS`. ## loadExtension `loadExtension(extensionName)` Generates a query to install and load a named DuckDB extension. For example, `vg.loadExtension("spatial")` will load the [`spatial` extension](https://duckdb.org/docs/extensions/spatial.html). ## loadCSV `loadCSV(tableName, file, options)` Generate a SQL query to create a table containing the values of a CSV *file*. The *file* argument may be a URL or a local filesystem path (if running DuckDB locally, *not* via WebAssembly). The supported *options* are: * *select*: An optional list of column expressions to select. If not specified, all columns are included. * *where*: An optional filter predicate (`WHERE` clause) to filter the data on load. * *view*: A boolean flag (default `false`) indicating if a `VIEW` should be created over the file, rather than a `TABLE`. * *temp*: A boolean flag (default `true`) indicating if the created table or view should be a temporary instance that should not persist beyond the current session. * *replace*: A boolean flag (default `false`) indicating that the file contents should replace any existing table or view with the same name. The default behavior is to do nothing if a name conflict exists. * Additional CSV-specific options, see the [DuckDB CSV documentation](https://duckdb.org/docs/data/csv/overview). ```js // Loads file.csv into the table "table1" with default options: // CREATE TABLE IF NOT EXISTS table1 AS // SELECT * // FROM read_csv('file.csv', auto_detect=true, sample_size=-1) loadCSV("table1", "file.csv"); ``` ## loadJSON `loadJSON(tableName, file, options)` Generate a SQL query to create a table containing the values of a JSON *file*. The *file* argument may be a URL or a local filesystem path (if running DuckDB locally, *not* via WebAssembly). The supported *options* are: * *select*: An optional list of column expressions to select. If not specified, all columns are included. * *where*: An optional filter predicate (`WHERE` clause) to filter the data on load. * *view*: A boolean flag (default `false`) indicating if a `VIEW` should be created over the file, rather than a `TABLE`. * *temp*: A boolean flag (default `true`) indicating if the created table or view should be a temporary instance that should not persist beyond the current session. * *replace*: A boolean flag (default `false`) indicating that the file contents should replace any existing table or view with the same name. The default behavior is to do nothing if a name conflict exists. * Additional JSON-specific options. See the [DuckDB JSON documentation](https://duckdb.org/docs/data/json/overview). ```js // Loads file.json into the table "table1" with default options: // CREATE TABLE IF NOT EXISTS table1 AS // SELECT * // FROM read_json('file.json', auto_detect=true, json_format='auto') loadJSON("table1", "file.json"); ``` ## loadParquet `loadParquet(tableName, file, options)` Generate a SQL query to create a table containing the values of a Parquet *file*. The *file* argument may be a URL or a local filesystem path (if running DuckDB locally, *not* via WebAssembly). The supported *options* are: * *select*: An optional list of column expressions to select. If not specified, all columns are included. * *where*: An optional filter predicate (`WHERE` clause) to filter the data on load. * *view*: A boolean flag (default `false`) indicating if a `VIEW` should be created over the file, rather than a `TABLE`. * *temp*: A boolean flag (default `true`) indicating if the created table or view should be a temporary instance that should not persist beyond the current session. * *replace*: A boolean flag (default `false`) indicating that the file contents should replace any existing table or view with the same name. The default behavior is to do nothing if a name conflict exists. * Additional Parquet-specific options. See the [DuckDB Parquet documentation](https://duckdb.org/docs/data/parquet/overview). ```js // Load named columns from a parquet file, filtered upon load: // CREATE TABLE IF NOT EXISTS table1 AS // SELECT foo, bar, value // FROM read_parquet('file.parquet') // WHERE value > 1 loadParquet("table1", "file.parquet", { select: [ "foo", "bar", "value" ], where: "value > 1" }); ``` ## loadObjects `loadObjects(tableName, objects, options)` Generate a SQL query to create a table containing the values of the provided JavaScript *objects*. The supported *options* are: * *select*: An optional list of column expressions to select. If not specified, all columns are included. * *view*: A boolean flag (default `false`) indicating if a `VIEW` should be created over the file, rather than a `TABLE`. * *temp*: A boolean flag (default `true`) indicating if the created table or view should be a temporary instance that should not persist beyond the current session. * *replace*: A boolean flag (default `false`) indicating that the file contents should replace any existing table or view with the same name. The default behavior is to do nothing if a name conflict exists. ```js // CREATE TABLE IF NOT EXISTS table3 AS // (SELECT 1 AS "foo", 2 AS "bar") UNION ALL // (SELECT 3 AS "foo", 4 AS "bar") UNION ALL ... const q = loadObjects("table3", [ { foo: 1, bar: 2 }, { foo: 3, bar: 4 }, ... ]); ``` ## loadSpatial `loadSpatial(tableName, file, options)` Generate a SQL query to create a table containing the values of a spatial data file by calling the [`ST_Read` function](https://duckdb.org/docs/extensions/spatial.html#st_read---read-spatial-data-from-files) of the DuckDB `spatial` extension. The *file* argument may be a URL or a local filesystem path (if running DuckDB locally, *not* via WebAssembly). The supported *options* are: * *select*: An optional list of column expressions to select. If not specified, all columns are included. * *where*: An optional filter predicate (`WHERE` clause) to filter the data on load. * *view*: A boolean flag (default `false`) indicating if a `VIEW` should be created over the file, rather than a `TABLE`. * *temp*: A boolean flag (default `true`) indicating if the created table or view should be a temporary instance that should not persist beyond the current session. * *replace*: A boolean flag (default `false`) indicating that the file contents should replace any existing table or view with the same name. The default behavior is to do nothing if a name conflict exists. * *layer*: The layer to extract from a multi-layer file. For example, for TopoJSON data this indicates which named object to extract. * Additional spatial-specific options. See the [DuckDB spatial documentation](https://duckdb.org/docs/extensions/spatial.html). ```js // Loads us-states.json into the table "table1": // CREATE TABLE IF NOT EXISTS table1 AS // SELECT * // FROM st_read('us-states.json', layer="states") loadSpatial("table1", "us-states.json", "states"); ``` --- --- url: /mosaic/api/inputs/menu.md --- # Menu A dropdown menu input widget. ## menu {#menu-method} `menu(options)` Return a new menu component with the provided *options*. Creates an instance of the [`Menu`](#menu-class) class, connects it to [`coordinator`](../core/coordinator), and returns the corresponding HTML element. The supported options are: * *as*: A `Param` or `Selection` that this menu should update. For a `Param`, the selected menu value is set to be the new param value. For a `Selection`, a predicate of the form `column = value` will be added to the selection. * *field*: The database column name to use within generated selection clause predicates. Defaults to the *column* option. * *filterBy*: An optional selection by which to filter the content of the menu, if drawn from a backing table. * *from*: The name of a backing database table to use as a data source of menu options. Used in conjunction with the *column* option. * *column*: The name of a backing database column from which to pull menu options. The unique column values are used as menu options. Used in conjunction with the *from* option. * *label*: A text label for the menu input. If unspecified, the *column* name (if provided) will be used by default. * *format*: A format function that takes an option value as input and generates a string label. The format function is not applied when an explicit label is provided in an option object. * *options*: An array of menu options, as literal values or option objects. Option objects have a `value` property and an optional `label` property. If no label or *format* function is provided, the string-coerced value is used. * *value*: The initial selected menu value. * *element*: The parent DOM element in which to place the menu elements. If undefined, a new `div` element is created. ### Examples Create a new menu with options pulled from `table.foo` in the backing database: ```js menu({ from: "table", column: "foo", as: param }) ``` Create a new menu with options provided explicitly: ```js menu({ as: selection, options: [ { label: "label1", value: "value1" }, { label: "label2", value: "value2" }, ... ] }) ``` ## Menu {#menu-class} `new Menu(options)` Class definition for a menu input that extends [`MosaicClient`](../core/client). The constructor accepts the same options as the [`menu`](#menu-method) method. ### element `menu.element` The HTML element containing the menu input. --- --- url: /mosaic/api/inputs/search.md --- # Search A text searchbox input widget. ## search {#search-method} `search(options)` Return a new search component with the provided *options*. Creates an instance of the [`Search`](#search-class) class, connects it to [`coordinator`](../core/coordinator), and returns the corresponding HTML element. The supported options are: * *as*: A `Param` or `Selection` that this search box should update. If a `Param`, simply sets the param to the input query string. If a `Selection`, adds a predicate that searches for the input text value, as determined by the *type* option. * *field*: The database column name to use within generated selection clause predicates. Defaults to the *column* option. * *type*: The type of text search query to perform. One of: * `"contains"` (default): the query string may appear anywhere in the text * `"prefix"`: the query string must appear at the start of the text * `"suffix"`: the query string must appear at the end of the text * `"regexp"`: the query string is a regular expression the text must match * *filterBy*: A selection to filter the database table indicated by the *from* option. * *from*: The name of a backing database table to use as an autocomplete data source for this widget. Used in conjunction with the *column* option. * *column*: The name of a database column from which to pull valid search results. The unique column values are used as search autocomplete values. Used in conjunction with the *from* option. * *label*: A text label for this input. * *element*: The parent DOM element in which to place the search elements. If undefined, a new `div` element is created. ### Examples Create a new search box with autocomplete values pulled from `table.foo` in the backing database: ```js search({ from: "table", column: "foo", as: selection }) ``` ## Search {#search-class} `new Search(options)` Class definition for a search box input that extends [`MosaicClient`](../core/client). The constructor accepts the same options as the [`search`](#search-method) method. ### element `search.element` The HTML element containing the search box input. --- --- url: /mosaic/api/inputs/slider.md --- # Slider A slider input widget. ## slider {#slider-method} `slider(options)` Return a new slider component with the provided *options*. Creates an instance of the [`Slider`](#slider-class) class, connects it to [`coordinator`](../core/coordinator), and returns the corresponding HTML element. The supported options are: * *as*: A `Param` or `Selection` that this slider should update. For a `Param`, the selected slider value is set to be the new param value. For a `Selection`, a selection clause will be added to the selection. * *field*: The database column name to use within generated selection clause predicates. Defaults to the *column* option. * *select*: The type of selection clause predicate to generate if the *as* option is a Selection. If `'point'` (the default), the selection predicate is an equality check for the slider value. If `'interval'`, the predicate checks an interval from the minimum to the current slider value. * *filterBy*: A selection to filter the database table indicated by the *from* option. * *from*: The name of a database table to use as a data source for this widget. Used in conjunction with the *column* option. The minimum and maximum values of the column determine the slider range. * *column*: The name of a database column whose values determine the slider range. Used in conjunction with the *from* option. The minimum and maximum values of the column determine the slider range. * *label*: A text label for the slider input. If unspecified, the *column* name (if provided) is used by default. * *min*: The minimum slider value. * *max*: The maximum slider value. * *step*: The slider step, the amount to increment between consecutive values. * *value*: The initial value of the slider. Defaults to the value of a param provided via the *as* option. * *width*: The width of the slider in pixels. * *element*: The parent DOM element in which to place the slider elements. If undefined, a new `div` element is created. ### Examples Create a new slider with options pulled from `table.foo` in the backing database: ```js slider({ from: "table", column: "foo", as: param }) ``` Create a new slider with options provided explicitly: ```js slider({ as: selection, min: 0, max: 10, step: 1 }) ``` ## Slider {#slider-class} `new Slider(options)` Class definition for a slider input that extends [`MosaicClient`](../core/client). The constructor accepts the same options as the [`slider`](#slider-method) method. ### element `slider.element` The HTML element containing the slider input. --- --- url: /mosaic/api/inputs/table.md --- # Table A sortable, scrollable table component that loads data on demand from a backing database table. ## table {#table-method} `table(options)` Return a new table component with the provided *options*. Creates an instance of the [`Table`](#table-class) class, connects it to [`coordinator`](../core/coordinator), and returns the corresponding HTML element. The supported options are: * *as*: The output selection. A selection clause is added for the currently selected table row. * *filterBy*: An optional selection by which to filter the contents of the table view. * *from*: The name of the backing database table or view. * *columns*: An ordered array of columns to include. If unspecified, all columns will be included. * *align*: An object providing optional column -> alignment mappings. The supported alignment values are `"left"`, `"center"`, and `"right"`. If a column's alignment is not specified, a default alignment is chosen based on the data type. * *format*: An object providing optional column -> format function mappings. If provided, a format function will be invoked with the column value to produce a string to display. If a column's formatting is not provided, a default format is chosen based on the data type. * *width*: If a number, sets the width of the table view in pixels. If an object, provides a column name -> pixel width mapping for individual columns. * *maxWidth*: The maximum width of the full table view in pixels. * *height*: The height of the table view in pixels (default 500). * *rowBatch*: The number of additional rows to query upon scroll updates (default 100). * *element*: The container DOM element. If unspecified, a new `div` is created. ## Table {#table-class} `new Table(options)` Class definition for a table component that extends [`MosaicClient`](../core/client). The constructor accepts the same options as the [`table`](#table-method) method. ### element `table.element` The HTML element containing the table view. --- --- url: /mosaic/api/vgplot/plot.md --- # Plot {#plot-page} A `Plot` is defined using a set of directives that specify [*attributes*](./attributes), graphical [*marks*](./marks), [*interactors*](./interactors), and [*legends*](./legends). **(begin JavaScript API)** ```js plot( width(500), // attribute rectY(from("table"), { x1: "u", x2: "v", y: "w", fill: "c" }), // mark intervalX({ as: selection }), // interactor colorLegend() // legend ) ``` **(end JavaScript API)** **(begin Python API)** ```python import vgplot as vg vg.plot( vg.width(500), # attribute vg.rect_y(vg.source("table"), x1="u", x2="v", y="w", fill="c"), # mark vg.interval_x(bind=selection), # interactor vg.color_legend(), # legend ) ``` **(end Python API)** ## plot **(begin JavaScript API)** `plot(...directives)` Create a new `Plot` instance based on the provided *directives* and return the corresponding HTML element. **(end JavaScript API)** **(begin Python API)** `vg.plot(...directives)` Build a plot specification from the provided *directives* for use with Mosaic widgets or other consumers. **(end Python API)** ## Plot {#plot-class} **(begin JavaScript API)** `new Plot(element)` Class definition for a `Plot`. If provided, the input *element* will be used as the container for the plot, otherwise a new `div` element will be generated. ### element `plot.element` The HTML element containing the plot. ### margins `plot.margins()` Return the specified margins of the plot as an object of the form `{left, right, top, bottom}`. ### innerWidth `plot.innerWidth()` Return the "inner" width of the plot, which is the `width` attribute value minus the `leftMargin` and `rightMargin` values. ### innerHeight `plot.innerHeight()` Return the "inner" height of the plot, which is the `height` attribute value minus the `topMargin` and `bottomMargin` values. ### pending `plot.pending(mark)` Called by a [`Mark`](./marks) instance to inform this parent plot that the mark has a pending data update. ### update `plot.update(mark)` Called by a [`Mark`](./marks) instance to inform this parent plot that the mark has completed an update. ### render `plot.render()` Renders this plot within its container element. ### getAttribute `plot.getAttribute(name)` Returns the attribute value for the given attribute *name*. Called by [attribute directives](./attributes.md). ### setAttribute `plot.setAttribute(name, value, options)` Sets the attribute value for the given attribute *name*. Returns `true` if the attribute is updated to a new value, `false` otherwise. The *options* hash may include a *silent* flag to suppress listener updates. Called by [attribute directives](./attributes.md). ### addAttributeListener `plot.addAttributeListener(name, callback)` Adds an event listener *callback* that is invoked when the attribute with the given *name* is updated. ### removeAttributeListener `plot.removeAttributeListener(name, callback)` Removes an event listener *callback* associated with the given attribute *name*. ### addParams `plot.addParams(mark, paramSet)` Register a set of [Params](../core/param) associated with a *mark* to coordinate updates. Called by child [`Mark`](./marks) instances. ### addMark `plot.addMark(mark)` Add a [`Mark`](./marks) instance to this plot. Called by [mark directives](./marks). ### markSet `plot.markSet` Property getter that returns a [`Set`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) containing this plot's marks. ### addInteractor `plot.addInteractor(interactor)` Add an interactor to this plot. Called by [interactor directives](./interactors). ### addLegend `plot.addLegend(legend, include)` Add a *legend* associated with this plot. The *include* flag (default `true`) indicates if the legend should be included within the same container element as the plot. Called by [legend directives](./legends). **(end JavaScript API)** **(begin Python API)** The `Plot` class is a JavaScript runtime concept for embedding plots in the browser. In Python, [`vg.plot(...)`](#plot) returns a serializable specification rather than a live plot object, so there is no `Plot` class or instance methods. **(end Python API)** --- --- url: /mosaic/api/vgplot/attributes.md --- # Attributes Plot attributes configure plot layout and scales, including resulting axes and legends. Attributes are included as plot directives, in the form of functions that take either a literal attribute value or a [`Param`](../core/param) as input. **(begin JavaScript API)** In addition to value arrays, scale domain attributes accept the `Fixed` symbol. **(end JavaScript API)** **(begin Python API)** In addition to value arrays, scale domain attributes accept the string `"Fixed"` for a fixed domain (for example `vg.x_domain("Fixed")`). **(end Python API)** This setting indicates that the scale domain should first be determined by the data, but should then be held fixed across subsequent data updates. A fixed domain will remain stable, preventing "jumps" in a display that might hamper interpretation of changes. For additional documentation of scale attributes, see the corresponding [Observable Plot documentation](https://observablehq.com/plot/features/scales#scale-options). **(begin JavaScript API)** Attributes are passed as directives to `plot`, together with marks, interactors, and legends: ```js plot( width(640), height(400), marginLeft(48), xDomain(Fixed), colorScheme("blues") ) ``` **(end JavaScript API)** **(begin Python API)** Attributes are passed as directives to `vg.plot`, together with marks, interactors, and legends: ```python import vgplot as vg vg.plot( vg.width(640), vg.height(400), vg.margin_left(48), vg.x_domain("Fixed"), vg.color_scheme("blues"), ) ``` **(end Python API)** ## Plot Attributes **(begin JavaScript API)** * `name(value)`: Set a globally unique name by which to refer to the plot. * `style(value)`: Set CSS styles to apply to the plot output. * `width(value)`: Set the plot width in pixels, including margins. * `height(value)`: Set the plot height in pixels, including margins. * `margin(value)`: Sets all margins to the same value in pixels. * `marginLeft(value)`: Set the left plot margin in pixels. * `marginRight(value)`: Set the right plot margin in pixels. * `marginTop(value)`: Set the top plot margin in pixels. * `marginBottom(value)`: Set the bottom plot margin in pixels. * `margins(value)`: Set plot margins in pixels, using an object of the form `{left, right, top, bottom}`. Margins omitted from the object are not set. * `align(value)`: Set the plot alignment. * `aspectRatio(value)`: Set the plot aspect ratio. * `inset(value)`: Set the plot insets in pixels. * `axis(value)`: Set a global setting for including axes. * `grid(value)`: Set a global setting for including grid lines. * `label(value)`: Set a global setting for axis labels. * `padding(value)`: Set the axis padding across all axes. * `round(value)`: Set axis roundings across all axes. ## x Scale Attributes * `xScale(value)`: Set the scale type, such as `"linear"`, `"log"`, etc. * `xDomain(value)`: Set the scale domain. * `xRange(value)`: Set the scale range. * `xNice(value)`: Set if the scale domain should have "nice" (human-friendly) end points. * `xInset(value)`: Set the scale insets in pixels. * `xInsetLeft(value)`: Set the left inset in pixels. * `xInsetRight(value)`: Set the right inset in pixels. * `xClamp(value)`: Set if the scale should clamp out-of-domain values. * `xRound(value)`: Set if the scale should round output values to the nearest pixel. * `xAlign(value)`: Set the axis alignment: where to distribute points or bands (0 = at start, 0.5 = at middle, 1 = at end). * `xPadding(value)`: Set the axis padding (for `band` or `point` scales). * `xPaddingInner(value)`: Set the axis inner padding (for `band` or `point` scales). * `xPaddingOuter(value)`: Set the axis outer padding (for `band` or `point` scales). * `xAxis(value)`: Set the axis position (`"top"` or `"bottom"`) or hide the axis (`null`). * `xTicks(value)`: Set the approximate number of ticks to generate, or interval, or array of values. * `xTickSize(value)`: Set the axis tick size. * `xTickSpacing(value)`: Set the approximate number of pixels between ticks (if xTicks is not specified). * `xTickPadding(value)`: Set the axis tick padding. * `xTickFormat(value)`: Set the axis tick format. * `xTickRotate(value)`: Set the axis tick rotation. * `xGrid(value)`: Set if the axis should include grid lines. * `xLine(value)`: Set if the axis should include a line on the plot edge. * `xLabel(value)`: Set the axis label. * `xLabelAnchor(value)`: Set the axis label anchor (`"left"`, `"center"`, `"right"`). * `xLabelOffset(value)`: Set the axis label offset in pixels. * `xFontVariant(value)`: Set the axis label font variant. * `xAriaLabel(value)`: Set the axis ARIA label for accessibility. * `xAriaDescription(value)`: Set the axis ARIA description for accessibility. * `xReverse(value)`: Set if the range should be reversed. * `xZero(value)`: Set the domain to always include zero. ## y Scale Attributes * `yScale(value)`: Set the scale type, such as `"linear"`, `"log"`, etc. * `yDomain(value)`: Set the scale domain. * `yRange(value)`: Set the scale range. * `yNice(value)`: Set if the scale domain should have "nice" (human-friendly) end points. * `yInset(value)`: Set the scale insets in pixels. * `yInsetTop(value)`: Set the top inset in pixels. * `yInsetBottom(value)`: Set the bottom inset in pixels. * `yClamp(value)`: Set if the scale should clamp out-of-domain values. * `yRound(value)`: Set if the scale should round output values to the nearest pixel. * `yAlign(value)`: Set the axis alignment: where to distribute points or bands (0 = at start, 0.5 = at middle, 1 = at end). * `yPadding(value)`: Set the axis padding (for `band` or `point` scales). * `yPaddingInner(value)`: Set the axis inner padding (for `band` or `point` scales). * `yPaddingOuter(value)`: Set the axis outer padding (for `band` or `point` scales). * `yAxis(value)`: Set the axis position (`"left"` or `"right"`) or hide the axis (`null`). * `yTicks(value)`: Set the approximate number of ticks to generate, or interval, or array of values. * `yTickSize(value)`: Set the axis tick size. * `yTickSpacing(value)`: Set the approximate number of pixels between ticks (if yTicks is not specified). * `yTickPadding(value)`: Set the axis tick padding. * `yTickFormat(value)`: Set the axis tick format. * `yTickRotate(value)`: Set the axis tick rotation. * `yGrid(value)`: Set if the axis should include grid lines. * `yLine(value)`: Set if the axis should include a line on the plot edge. * `yLabel(value)`: Set the axis label. * `yLabelAnchor(value)`: Set the axis label anchor (`"top"`, `"middle"`, `"bottom"`). * `yLabelOffset(value)`: Set the axis label offset in pixels. * `yFontVariant(value)`: Set the axis label font variant. * `yAriaLabel(value)`: Set the axis ARIA label for accessibility. * `yAriaDescription(value)`: Set the axis ARIA description for accessibility. * `yReverse(value)`: Set if the range should be reversed. * `yZero(value)`: Set the domain to always include zero. ## color Scale Attributes * `colorScale(value)`: Set the scale type, such as `"linear"`, `"log"`, etc. * `colorDomain(value)`: Set the scale domain. * `colorRange(value)`: Set the scale range. * `colorClamp(value)`: Set if the scale should clamp out-of-domain values. * `colorNice(value)`: Set if the scale domain should have "nice" (human-friendly) end points. * `colorScheme(value)`: Set the named color scheme to use. * `colorInterpolate(value)`: Set a custom color interpolation function. * `colorPivot(value)`: Set the pivot value for diverging `color` scales. * `colorSymmetric(value)`: Set the domain to be symmetric around a pivot. * `colorLabel(value)`: Set the scale label. * `colorReverse(value)`: Set if the range should be reversed. * `colorZero(value)`: Set the domain to always include zero. * `colorTickFormat(value)`: Set the legend tick format. ## opacity Scale Attributes * `opacityScale(value)`: Set the scale type, such as `"linear"`, `"log"`, etc. * `opacityDomain(value)`: Set the scale domain. * `opacityRange(value)`: Set the scale range. * `opacityClamp(value)`: Set if the scale should clamp out-of-domain values. * `opacityNice(value)`: Set if the scale domain should have "nice" (human-friendly) end points. * `opacityLabel(value)`: Set the scale label. * `opacityReverse(value)`: Set if the range should be reversed. * `opacityZero(value)`: Set the domain to always include zero. * `opacityTickFormat(value)`: Set the legend tick format. ## r Scale Attributes * `rScale(value)`: Set the scale type, such as `"linear"`, `"log"`, etc. * `rDomain(value)`: Set the scale domain. * `rRange(value)`: Set the scale range. * `rClamp(value)`: Set if the scale should clamp out-of-domain values. * `rNice(value)`: Set if the scale domain should have "nice" (human-friendly) end points. * `rLabel(value)`: Set the scale label. * `rZero(value)`: Set the domain to always include zero. ## length Scale Attributes * `lengthScale(value)`: Set the scale type, such as `"linear"`, `"log"`, etc. * `lengthDomain(value)`: Set the scale domain. * `lengthRange(value)`: Set the scale range. * `lengthClamp(value)`: Set if the scale should clamp out-of-domain values. * `lengthNice(value)`: Set if the scale domain should have "nice" (human-friendly) end points. * `lengthZero(value)`: Set the domain to always include zero. ## fx Scale Attributes * `fxDomain(value)`: Set the scale domain. * `fxRange(value)`: Set the scale range. * `fxInset(value)`: Set the scale insets in pixels. * `fxInsetLeft(value)`: Set the left inset in pixels. * `fxInsetRight(value)`: Set the right inset in pixels. * `fxRound(value)`: Set if the scale should round output values to the nearest pixel. * `fxAlign(value)`: Set the axis alignment: where to distribute points or bands (0 = at start, 0.5 = at middle, 1 = at end). * `fxPadding(value)`: Set the axis padding (for `band` or `point` scales). * `fxPaddingInner(value)`: Set the axis inner padding (for `band` or `point` scales). * `fxPaddingOuter(value)`: Set the axis outer padding (for `band` or `point` scales). * `fxAxis(value)`: Set the axis position (`"top"` or `"bottom"`) or hide the axis (`null`). * `fxTickSize(value)`: Set the axis tick size. * `fxTickPadding(value)`: Set the axis tick padding. * `fxTickFormat(value)`: Set the axis tick format. * `fxTickRotate(value)`: Set the axis tick rotation. * `fxGrid(value)`: Set if the axis should include grid lines. * `fxLabel(value)`: Set the axis label. * `fxLabelAnchor(value)`: Set the axis label anchor (`"left"`, `"center"`, `"right"`). * `fxLabelOffset(value)`: Set the axis label offset in pixels. * `fxFontVariant(value)`: Set the axis label font variant. * `fxAriaLabel(value)`: Set the axis ARIA label for accessibility. * `fxAriaDescription(value)`: Set the axis ARIA description for accessibility. * `fxReverse(value)`: Set if the range should be reversed. ## fy Scale Attributes * `fyDomain(value)`: Set the scale domain. * `fyRange(value)`: Set the scale range. * `fyInset(value)`: Set the scale insets in pixels. * `fyInsetTop(value)`: Set the top inset in pixels. * `fyInsetBottom(value)`: Set the bottom inset in pixels. * `fyRound(value)`: Set if the scale should round output values to the nearest pixel. * `fyAlign(value)`: Set the axis alignment: where to distribute points or bands (0 = at start, 0.5 = at middle, 1 = at end). * `fyPadding(value)`: Set the axis padding (for `band` or `point` scales). * `fyPaddingInner(value)`: Set the axis inner padding (for `band` or `point` scales). * `fyPaddingOuter(value)`: Set the axis outer padding (for `band` or `point` scales). * `fyAxis(value)`: Set the axis position (`"top"` or `"bottom"`) or hide the axis (`null`). * `fyTickSize(value)`: Set the axis tick size. * `fyTickPadding(value)`: Set the axis tick padding. * `fyTickFormat(value)`: Set the axis tick format. * `fyTickRotate(value)`: Set the axis tick rotation. * `fyGrid(value)`: Set if the axis should include grid lines. * `fyLabel(value)`: Set the axis label. * `fyLabelAnchor(value)`: Set the axis label anchor (`"left"`, `"center"`, `"right"`). * `fyLabelOffset(value)`: Set the axis label offset in pixels. * `fyFontVariant(value)`: Set the axis label font variant. * `fyAriaLabel(value)`: Set the axis ARIA label for accessibility. * `fyAriaDescription(value)`: Set the axis ARIA description for accessibility. * `fyReverse(value)`: Set if the range should be reversed. ## Facet Attributes * `facetMargin(value)`: Set all four facet margins. * `facetMarginTop(value)`: Set the facet top margin. * `facetMarginBottom(value)`: Set the facet bottom margin. * `facetMarginLeft(value)`: Set the facet left margin. * `facetMarginRight(value)`: Set the facet right margin. * `facetGrid(value)`: Set if grid lines should be drawn for each facet. * `facetLabel(value)`: If null, disable default facet axis labels. ## Projection Attributes For more on projections, see the [Observable Plot projection documentation](https://observablehq.com/plot/features/projections). * `projectionType(value)`: Set the projection type, such as `"mercator"`, `"orthographic"`. * `projectionParallels(value)`: Set the [standard parallels](https://github.com/d3/d3-geo/blob/main/README.md#conic_parallels) (for conic projections only). * `projectionPrecision(value)`: Set the [sampling threshold](https://github.com/d3/d3-geo/blob/main/README.md#projection_precision). * `projectionRotate(value)`: Set a two- or three- element array of Euler angles to rotate the sphere. * `projectionDomain(value)`: Set a GeoJSON object to fit in the center of the (inset) frame. * `projectionInset(value)`: Set the inset to the given amount in pixels when fitting to the frame (default zero). * `projectionInsetLeft(value)`: Set the inset from the left edge of the frame (defaults to `projectionInset`). * `projectionInsetRight(value)`: Set the inset from the right edge of the frame (defaults to `projectionInset`). * `projectionInsetTop(value)`: Set the inset from the top edge of the frame (defaults to `projectionInset`). * `projectionInsetBottom(value)`: Set the inset from the bottom edge of the frame (defaults to `projectionInset`). * `projectionClip(value)`: Set the projection clipping method. One of: `"frame"` or `true` (default) to clip to the extent of the frame (including margins but not insets), a number to clip to a great circle of the given radius in degrees centered around the origin, or `null` or `false` to disable clipping. ::: warning Interval interactors are not currently supported when cartographic projections are used. ::: **(end JavaScript API)** **(begin Python API)** * `name(value)`: Set a globally unique name by which to refer to the plot. * `style(value)`: Set CSS styles to apply to the plot output. * `width(value)`: Set the plot width in pixels, including margins. * `height(value)`: Set the plot height in pixels, including margins. * `margin(value)`: Sets all margins to the same value in pixels. * `margin_left(value)`: Set the left plot margin in pixels. * `margin_right(value)`: Set the right plot margin in pixels. * `margin_top(value)`: Set the top plot margin in pixels. * `margin_bottom(value)`: Set the bottom plot margin in pixels. * `margins(value)`: Set plot margins in pixels, using an object of the form `{left, right, top, bottom}`. Margins omitted from the object are not set. * `align(value)`: Set the plot alignment. * `aspect_ratio(value)`: Set the plot aspect ratio. * `inset(value)`: Set the plot insets in pixels. * `axis(value)`: Set a global setting for including axes. * `grid(value)`: Set a global setting for including grid lines. * `label(value)`: Set a global setting for axis labels. * `padding(value)`: Set the axis padding across all axes. * `round(value)`: Set axis roundings across all axes. ## x Scale Attributes * `x_scale(value)`: Set the scale type, such as `"linear"`, `"log"`, etc. * `x_domain(value)`: Set the scale domain. * `x_range(value)`: Set the scale range. * `x_nice(value)`: Set if the scale domain should have "nice" (human-friendly) end points. * `x_inset(value)`: Set the scale insets in pixels. * `x_inset_left(value)`: Set the left inset in pixels. * `x_inset_right(value)`: Set the right inset in pixels. * `x_clamp(value)`: Set if the scale should clamp out-of-domain values. * `x_round(value)`: Set if the scale should round output values to the nearest pixel. * `x_align(value)`: Set the axis alignment: where to distribute points or bands (0 = at start, 0.5 = at middle, 1 = at end). * `x_padding(value)`: Set the axis padding (for `band` or `point` scales). * `x_padding_inner(value)`: Set the axis inner padding (for `band` or `point` scales). * `x_padding_outer(value)`: Set the axis outer padding (for `band` or `point` scales). * `x_axis(value)`: Set the axis position (`"top"` or `"bottom"`) or hide the axis (`null`). * `x_ticks(value)`: Set the approximate number of ticks to generate, or interval, or array of values. * `x_tick_size(value)`: Set the axis tick size. * `x_tick_spacing(value)`: Set the approximate number of pixels between ticks (if `x_ticks` is not specified). * `x_tick_padding(value)`: Set the axis tick padding. * `x_tick_format(value)`: Set the axis tick format. * `x_tick_rotate(value)`: Set the axis tick rotation. * `x_grid(value)`: Set if the axis should include grid lines. * `x_line(value)`: Set if the axis should include a line on the plot edge. * `x_label(value)`: Set the axis label. * `x_label_anchor(value)`: Set the axis label anchor (`"left"`, `"center"`, `"right"`). * `x_label_offset(value)`: Set the axis label offset in pixels. * `x_font_variant(value)`: Set the axis label font variant. * `x_aria_label(value)`: Set the axis ARIA label for accessibility. * `x_aria_description(value)`: Set the axis ARIA description for accessibility. * `x_reverse(value)`: Set if the range should be reversed. * `x_zero(value)`: Set the domain to always include zero. ## y Scale Attributes * `y_scale(value)`: Set the scale type, such as `"linear"`, `"log"`, etc. * `y_domain(value)`: Set the scale domain. * `y_range(value)`: Set the scale range. * `y_nice(value)`: Set if the scale domain should have "nice" (human-friendly) end points. * `y_inset(value)`: Set the scale insets in pixels. * `y_inset_top(value)`: Set the top inset in pixels. * `y_inset_bottom(value)`: Set the bottom inset in pixels. * `y_clamp(value)`: Set if the scale should clamp out-of-domain values. * `y_round(value)`: Set if the scale should round output values to the nearest pixel. * `y_align(value)`: Set the axis alignment: where to distribute points or bands (0 = at start, 0.5 = at middle, 1 = at end). * `y_padding(value)`: Set the axis padding (for `band` or `point` scales). * `y_padding_inner(value)`: Set the axis inner padding (for `band` or `point` scales). * `y_padding_outer(value)`: Set the axis outer padding (for `band` or `point` scales). * `y_axis(value)`: Set the axis position (`"left"` or `"right"`) or hide the axis (`null`). * `y_ticks(value)`: Set the approximate number of ticks to generate, or interval, or array of values. * `y_tick_size(value)`: Set the axis tick size. * `y_tick_spacing(value)`: Set the approximate number of pixels between ticks (if `y_ticks` is not specified). * `y_tick_padding(value)`: Set the axis tick padding. * `y_tick_format(value)`: Set the axis tick format. * `y_tick_rotate(value)`: Set the axis tick rotation. * `y_grid(value)`: Set if the axis should include grid lines. * `y_line(value)`: Set if the axis should include a line on the plot edge. * `y_label(value)`: Set the axis label. * `y_label_anchor(value)`: Set the axis label anchor (`"top"`, `"middle"`, `"bottom"`). * `y_label_offset(value)`: Set the axis label offset in pixels. * `y_font_variant(value)`: Set the axis label font variant. * `y_aria_label(value)`: Set the axis ARIA label for accessibility. * `y_aria_description(value)`: Set the axis ARIA description for accessibility. * `y_reverse(value)`: Set if the range should be reversed. * `y_zero(value)`: Set the domain to always include zero. ## color Scale Attributes * `color_scale(value)`: Set the scale type, such as `"linear"`, `"log"`, etc. * `color_domain(value)`: Set the scale domain. * `color_range(value)`: Set the scale range. * `color_clamp(value)`: Set if the scale should clamp out-of-domain values. * `color_nice(value)`: Set if the scale domain should have "nice" (human-friendly) end points. * `color_scheme(value)`: Set the named color scheme to use. * `color_interpolate(value)`: Set a custom color interpolation function. * `color_pivot(value)`: Set the pivot value for diverging `color` scales. * `color_symmetric(value)`: Set the domain to be symmetric around a pivot. * `color_label(value)`: Set the scale label. * `color_reverse(value)`: Set if the range should be reversed. * `color_zero(value)`: Set the domain to always include zero. * `color_tick_format(value)`: Set the legend tick format. ## opacity Scale Attributes * `opacity_scale(value)`: Set the scale type, such as `"linear"`, `"log"`, etc. * `opacity_domain(value)`: Set the scale domain. * `opacity_range(value)`: Set the scale range. * `opacity_clamp(value)`: Set if the scale should clamp out-of-domain values. * `opacity_nice(value)`: Set if the scale domain should have "nice" (human-friendly) end points. * `opacity_label(value)`: Set the scale label. * `opacity_reverse(value)`: Set if the range should be reversed. * `opacity_zero(value)`: Set the domain to always include zero. * `opacity_tick_format(value)`: Set the legend tick format. ## r Scale Attributes * `r_scale(value)`: Set the scale type, such as `"linear"`, `"log"`, etc. * `r_domain(value)`: Set the scale domain. * `r_range(value)`: Set the scale range. * `r_clamp(value)`: Set if the scale should clamp out-of-domain values. * `r_nice(value)`: Set if the scale domain should have "nice" (human-friendly) end points. * `r_label(value)`: Set the scale label. * `r_zero(value)`: Set the domain to always include zero. ## length Scale Attributes * `length_scale(value)`: Set the scale type, such as `"linear"`, `"log"`, etc. * `length_domain(value)`: Set the scale domain. * `length_range(value)`: Set the scale range. * `length_clamp(value)`: Set if the scale should clamp out-of-domain values. * `length_nice(value)`: Set if the scale domain should have "nice" (human-friendly) end points. * `length_zero(value)`: Set the domain to always include zero. ## fx Scale Attributes * `fx_domain(value)`: Set the scale domain. * `fx_range(value)`: Set the scale range. * `fx_inset(value)`: Set the scale insets in pixels. * `fx_inset_left(value)`: Set the left inset in pixels. * `fx_inset_right(value)`: Set the right inset in pixels. * `fx_round(value)`: Set if the scale should round output values to the nearest pixel. * `fx_align(value)`: Set the axis alignment: where to distribute points or bands (0 = at start, 0.5 = at middle, 1 = at end). * `fx_padding(value)`: Set the axis padding (for `band` or `point` scales). * `fx_padding_inner(value)`: Set the axis inner padding (for `band` or `point` scales). * `fx_padding_outer(value)`: Set the axis outer padding (for `band` or `point` scales). * `fx_axis(value)`: Set the axis position (`"top"` or `"bottom"`) or hide the axis (`null`). * `fx_tick_size(value)`: Set the axis tick size. * `fx_tick_padding(value)`: Set the axis tick padding. * `fx_tick_format(value)`: Set the axis tick format. * `fx_tick_rotate(value)`: Set the axis tick rotation. * `fx_grid(value)`: Set if the axis should include grid lines. * `fx_label(value)`: Set the axis label. * `fx_label_anchor(value)`: Set the axis label anchor (`"left"`, `"center"`, `"right"`). * `fx_label_offset(value)`: Set the axis label offset in pixels. * `fx_font_variant(value)`: Set the axis label font variant. * `fx_aria_label(value)`: Set the axis ARIA label for accessibility. * `fx_aria_description(value)`: Set the axis ARIA description for accessibility. * `fx_reverse(value)`: Set if the range should be reversed. ## fy Scale Attributes * `fy_domain(value)`: Set the scale domain. * `fy_range(value)`: Set the scale range. * `fy_inset(value)`: Set the scale insets in pixels. * `fy_inset_top(value)`: Set the top inset in pixels. * `fy_inset_bottom(value)`: Set the bottom inset in pixels. * `fy_round(value)`: Set if the scale should round output values to the nearest pixel. * `fy_align(value)`: Set the axis alignment: where to distribute points or bands (0 = at start, 0.5 = at middle, 1 = at end). * `fy_padding(value)`: Set the axis padding (for `band` or `point` scales). * `fy_padding_inner(value)`: Set the axis inner padding (for `band` or `point` scales). * `fy_padding_outer(value)`: Set the axis outer padding (for `band` or `point` scales). * `fy_axis(value)`: Set the axis position (`"top"` or `"bottom"`) or hide the axis (`null`). * `fy_tick_size(value)`: Set the axis tick size. * `fy_tick_padding(value)`: Set the axis tick padding. * `fy_tick_format(value)`: Set the axis tick format. * `fy_tick_rotate(value)`: Set the axis tick rotation. * `fy_grid(value)`: Set if the axis should include grid lines. * `fy_label(value)`: Set the axis label. * `fy_label_anchor(value)`: Set the axis label anchor (`"left"`, `"center"`, `"right"`). * `fy_label_offset(value)`: Set the axis label offset in pixels. * `fy_font_variant(value)`: Set the axis label font variant. * `fy_aria_label(value)`: Set the axis ARIA label for accessibility. * `fy_aria_description(value)`: Set the axis ARIA description for accessibility. * `fy_reverse(value)`: Set if the range should be reversed. ## Facet Attributes * `facet_margin(value)`: Set all four facet margins. * `facet_margin_top(value)`: Set the facet top margin. * `facet_margin_bottom(value)`: Set the facet bottom margin. * `facet_margin_left(value)`: Set the facet left margin. * `facet_margin_right(value)`: Set the facet right margin. * `facet_grid(value)`: Set if grid lines should be drawn for each facet. * `facet_label(value)`: If null, disable default facet axis labels. ## Projection Attributes For more on projections, see the [Observable Plot projection documentation](https://observablehq.com/plot/features/projections). * `projection_type(value)`: Set the projection type, such as `"mercator"`, `"orthographic"`. * `projection_parallels(value)`: Set the [standard parallels](https://github.com/d3/d3-geo/blob/main/README.md#conic_parallels) (for conic projections only). * `projection_precision(value)`: Set the [sampling threshold](https://github.com/d3/d3-geo/blob/main/README.md#projection_precision). * `projection_rotate(value)`: Set a two- or three- element array of Euler angles to rotate the sphere. * `projection_domain(value)`: Set a GeoJSON object to fit in the center of the (inset) frame. * `projection_inset(value)`: Set the inset to the given amount in pixels when fitting to the frame (default zero). * `projection_inset_left(value)`: Set the inset from the left edge of the frame (defaults to `projection_inset`). * `projection_inset_right(value)`: Set the inset from the right edge of the frame (defaults to `projection_inset`). * `projection_inset_top(value)`: Set the inset from the top edge of the frame (defaults to `projection_inset`). * `projection_inset_bottom(value)`: Set the inset from the bottom edge of the frame (defaults to `projection_inset`). * `projection_clip(value)`: Set the projection clipping method. One of: `"frame"` or `true` (default) to clip to the extent of the frame (including margins but not insets), a number to clip to a great circle of the given radius in degrees centered around the origin, or `null` or `false` to disable clipping. ::: warning Interval interactors are not currently supported when cartographic projections are used. ::: **(end Python API)** --- --- url: /mosaic/api/vgplot/marks.md --- **(begin JavaScript API)** # Marks Marks are graphical elements that visualize data through encoding *channels* such as *x* and *y* position, *fill* color, and *r* (radius) size. Marks are added to a [`Plot`](./plot) using the mark directive functions listed below. Most mark functions take two arguments: a *data* source and an *options* object that specifies encoding channels or constant values. To visualize data from a backing database, the `from()` method should be used to specify the data source. For example, `from("data", { filterBy: sel })` indicates that data should be drawn from the database table `"data"`, interactively filtered by the selection `sel`. ```js import { barY, from, plot } from "@uwdata/vgplot"; plot( barY(from("data"), { x: "a", y: "b", fill: "steelblue", opacity: 0.5 }) ) ``` The example above specifies a bar chart with bars oriented vertically. Data is drawn from the `"data"` table, with the column `"a"` mapped to an ordinal *x* axis and the column `"b"` mapped to the *y* axis. The *fill* option is the constant CSS color `"steelblue"` and the *opacity* is a constant `0.5`. For encoding channels, strings are interpreted as column names *unless* they match a reserved constant for that key, such as a CSS color name for the *fill* or *stroke* options. If an explicit array of data values is provided instead of a backing `from(tableName)` reference, vgplot will visualize that data without issuing any queries to the database. This functionality is particularly useful for adding manual annotations, such as custom rules or text labels. Marks that only add reference lines or shapes (e.g., [`frame`](#frame), [`axisX`](#axis), [`gridY`](#grid), [`hexgrid`](#hexgrid), [`graticule`](#geo), [`sphere`](#geo)) do not require corresponding data, and take only *options*. Marks use the semantics of [Observable Plot](https://observablehq.com/plot/features/marks). For example, mark variants may indicate not only shapes but also data type assumptions. The [`barY`](#bar) mark above assumes a discrete (ordinal) *x* axis and will produce a `band` scale, whereas the related [`rectY`](#rect) mark instead assumes a continuous *x* axis and by default will produce a `linear` scale. ## Area An `area` mark, with `areaX` and `areaY` variants. When feasible, the `areaX` and `areaY` marks will perform [M4 optimization](https://observablehq.com/@uwdata/m4-scalable-time-series-visualization) to limit the number of sample points returned from the database. Use `from("data", { optimize: false })` to disable this behavior. For supported options, see the [Observable Plot `area` documentation](https://observablehq.com/plot/marks/area). ## Arrow The `arrow` mark provides line segments with arrow heads. For supported options, see the [Observable Plot `arrow` documentation](https://observablehq.com/plot/marks/arrow). ## Axis To go beyond the built-in axis generation, the axis mark supports explicit inclusion of axes, along with control over drawing order. The provided mark directives are `axisX` and `axisY` (for standard axes) as well as `axisFx` and `axisFy` (for facet axes). For supported options, see the [Observable Plot `axis` documentation](https://observablehq.com/plot/marks/axis). ## Bar The `barX` and `barY` marks draw rectangles, and should be used when one dimension is ordinal and the other is quantitative. For supported options, see the [Observable Plot `bar` documentation](https://observablehq.com/plot/marks/bar). ## Cell The `cell` mark, with `cellX` and `cellY` variants, draws rectangles positioned in two ordinal dimensions. For supported options, see the [Observable Plot `cell` documentation](https://observablehq.com/plot/marks/cell). ## Contour The `contour` mark draws isolines to delineate regions above and below a particular continuous value. It is often used to convey densities as a height field. The special column name `"density"` can be used to map density values to the *fill* or *stroke* options. The supported *options* are: * *x*: The x dimension encoding channel * *y*: The y dimension encoding channel * *fill*: The contour fill color * *stroke*: The contour stroke color * *thresholds*: The number of contour thresholds to include (default `10`) * *bandwidth*: The kernel density bandwidth for smoothing, in pixels (default `20`) * *interpolate*: The binning interpolation method to use, one of `"linear"` (default) or `"none"` * *pixelSize*: The grid cell size in screen pixels (default `2`); ignored when *width* and *height* options are provided * *width*: The number of grid bins to include along the *x* dimension * *height*: The number of grid bins to include along the *y* dimension * *pad*: The bin padding, one of `0` (default) to make the bins flush with the maximum domain value, or `1` to include extra padding for the final bin * Other standard mark options including *fillOpacity* and *strokeWidth* ## Delaunay Given set of points in x and y, the Delaunay marks compute the Delaunay triangulation, its dual the Voronoi tessellation, and the convex hull. The supported marks are `voronoi`, `voronoiMesh`, `delaunayLink`, `delaunayMesh`, and `hull`. For more, see the [Observable Plot `delaunay` documentation](https://observablehq.com/plot/marks/delaunay). ## Density 1D The 1D density marks show smoothed point cloud densities along one dimension. The `densityX` and `densityY` marks bin the data, count the number of records that fall into each bin, smooth the resulting counts, then plot the smoothed distribution (by default using an `area` mark). The `densityX` mark maps density values to the *x* dimension automatically, while `densityY` maps the density values to the *y* dimension. The supported *options* are: * *x*: The x dimension encoding channel, used with `densityY` * *y*: The y dimension encoding channel, used with `densityX` * *type*: The mark type to use (default [`areaX`](#area) or [`areaY`](#area)) * *bins*: The number of bins (default `1024`) * *bandwidth*: The kernel density bandwidth for smoothing, in pixels (default `20`) * Any options accepted by the mark *type*, including *stroke* and *fill* ## Density 2D The 2D `density` mark shows smoothed point cloud densities along two dimensions. The mark will bin the data, count the number of records that fall into each bin, smooth the resulting counts, then plot the smoothed distribution (by default using a circular `dot` mark). The `density` mark calculates density values that can be mapped to encoding channels such as *fill* or *r* using the column name `"density"`. The supported *options* are: * *x*: The x dimension encoding channel * *y*: The y dimension encoding channel * *type*: The mark type to use (default [`dot`](#dot)) * *bandwidth*: The kernel density bandwidth for smoothing, in pixels (default `20`) * *interpolate*: The binning interpolation method to use, one of `"linear"` (default) or `"none"` * *pixelSize*: The grid cell size in screen pixels (default `2`); ignored when *width* and *height* options are provided * *width*: The number of grid bins to include along the *x* dimension * *height*: The number of grid bins to include along the *y* dimension * *pad*: The bin padding, one of `0` (default) to make the bins flush with the maximum domain value, or `1` to include extra padding for the final bin * Any options accepted by the mark *type*, including *fill*, *stroke*, and *r* ## Dense Line Rather than plot point densities, the `denseLine` mark plots line densities: the mark forms a binned raster grid and "draws" lines into it. To avoid over-weighting steep lines, by default each drawn series will be normalized on a per-column basis to approximate arc length normalization. The values for each series are then aggregated to form the line density, which is then drawn as an image similar to the [`raster`](#raster) mark. The supported *options* are: * *x*: The x dimension encoding channel * *y*: The y dimension encoding channel * *bandwidth*: The kernel density bandwidth for smoothing (default `0`) * *pixelSize*: The grid cell size in screen pixels (default `1`) * *pad*: The bin padding, one of `1` (default) to include extra padding for the final bin, or `0` to make the bins flush with the maximum domain value. * *width*: The number of grid bins to include along the *x* dimension * *height*: The number of grid bins to include along the *y* dimension * *normalize*: Boolean flag (default `true`) controlling approximate arc length normalization. ## Dot The `dot` mark, with `dotX` and `dotY` variants, draws circles or other symbols positioned in *x* and *y* as in a scatterplot. The `circle` and `hexagon` marks are convenient shorthands for specific shapes. For supported options, see the [Observable Plot `dot` documentation](https://observablehq.com/plot/marks/dot). ## Frame The `frame` mark draws a rectangle around the plot area. It does not take a *data* argument. For supported options, see the [Observable Plot `frame` documentation](https://observablehq.com/plot/marks/frame). ## Geo The `geo` mark draws geographic features—polygons, lines, points, and other geometry—often as thematic maps. Input data can be provided directly as an array of GeoJSON features or geographic data can be loaded and queried directly in DuckDB using the `spatial` extension. The *geometry* option indicates the column name containing GeoJSON features or GeoJSON geometry objects. If *geometry* is not specified, the mark will interpret input objects as GeoJSON when data is passed in directly. When querying geometry from a DuckDB table, the *geometry* option will default to `'geom'` (the default name for geometry data loaded using the `spatial` extension's `ST_Read` function) and will be automatically converted to GeoJSON format in the database using the `ST_asGeoJSON` function. If the *geometry* option is specified, automatic conversion of DuckDB query results is *not* performed; this enables more fine-grained control, but may require explicit conversion of data to GeoJSON format using `ST_asGeoJSON` (or equivalently using Mosaic's `geojson()` SQL helper). The `sphere` and `graticule` marks (which do not accept input data) include the sphere of the Earth and global reference lines, respectively. For other supported options, see the [Observable Plot `geo` documentation](https://observablehq.com/plot/marks/geo). ## Grid The grid mark is a specially-configured rule for drawing an axis-aligned grid. To go beyond the built-in axis generation, the grid mark supports explicit inclusion of grid lines, along with control over drawing order. The provided mark directives are `gridX` and `gridY` (for standard axes) as well as `gridFx` and `gridFy` (for facet axes). For supported options, see the [Observable Plot `grid` documentation](https://observablehq.com/plot/marks/grid). ## Heatmap The `heatmap` mark is a raster mark with default options for accurate density estimation via smoothing. The *bandwidth* (`20`), *interpolate* (`"linear"`), and *pixelSize* (`2`) options are set to produce smoothed density heatmaps. For all supported options, see the [`raster`](#raster) mark. ## Hexbin The `hexbin` mark bins data into a hexagonal grid and visualizes aggregate functions per bin (e.g., `count` for binned density). Hexagonal binning and aggregation are pushed to the backing database. Aggregate functions can be used for the mark *fill*, *stroke*, or radius size *r* options. The supported *options* are: * *x*: The x dimension encoding channel * *y*: The y dimension encoding channel * *type*: The mark type to use (default [`hexagon`](#dot)) * *binWidth*: The hexagon bin width in screen pixels (default `20`) * Any options accepted by the mark *type*, including *fill*, *stroke*, *r*. ## Hexgrid The `hexgrid` mark draws a hexagonal grid spanning the frame. For supported options, see the [Observable Plot `hexgrid` documentation](https://observablehq.com/plot/marks/hexgrid). ## Image The `image` mark draws images centered at the given position in *x* and *y*. For supported options, see the [Observable Plot `image` documentation](https://observablehq.com/plot/marks/image). ## Line A `line` mark, with `lineX` and `lineY` variants. When feasible, the `lineX` and `lineY` marks will perform [M4 optimization](https://observablehq.com/@uwdata/m4-scalable-time-series-visualization) to limit the number of sample points returned from the database. Use `from("data", { optimize: false })` to disable this behavior. For supported options, see the [Observable Plot `line` documentation](https://observablehq.com/plot/marks/line). ## Regression The `regressionY` mark draws a regression line and optional confidence interval area for a linear regression fit. The regression calculation is pushed to the backing database. The supported *options* are: * *x*: The x dimension (predictor) encoding channel * *y*: The y dimension (predicted) encoding channel * *ci*: The confidence level (default `0.95`) to visualize as a confidence band area; use zero or `null` to suppress * *precision*: The distance (in pixels) between samples of the confidence band (default `4`) ## Link The `link` mark draws straight lines between two points \[*x1*, *y1*] and \[*x2*, *y2*] in quantitative dimensions. For supported options, see the [Observable Plot `link` documentation](https://observablehq.com/plot/marks/link). ## Raster The `raster` mark draws an image whose pixel colors are a function of the underlying data. The *x* and *y* data domains are binned into the cells ("pixels") of a raster grid, typically with an aggregate function evaluated over the binned data. The result can be optionally smoothed (blurred) in-browser. To create a smoothed density heatmap, use the [`heatmap`](#heatmap) mark; this is a raster mark with different default options. The supported *options* are: * *x*: The x dimension encoding channel * *y*: The y dimension encoding channel * *fill*: The pixel fill color. Use the special value `"density"` to map computed density values to pixel colors. Use an aggregate expression to instead visualize an aggregate value per raster bin. If *fill* is set to a constant color or to a non-aggregate field, opacity will be used to convey densities. If a non-aggregate (group by) field is provided, multiple rasters are created with a unique categorical color per layer. * *fillOpacity*: The pixel fill opacity. Use the special value `"density"` to map computed density values to opacity. Use an aggregate expression to instead visualize an aggregate value per raster bin. * *weight*: A data column by which to weight computed densities * *bandwidth*: The kernel density bandwidth for smoothing, in pixels (default `0`) * *interpolate*: The binning interpolation method to use. The `"none"` and `"linear"` methods are performed in-database and only fill bins corresponding to observed data samples. The other methods are performed in-browser and interpolate to fill all raster pixels. The options are: * `"none"` (default): Map data samples to single bins only. * `"linear"`: Linearly distribute the "weight" of a sample across adjacent bin boundaries. Linear binning provides more stable and accurate density estimation upon subsequent smoothing. * `"nearest"`: Perform nearest-neighbor interpolation, forming a pixel-level Voronoi diagram. * `"barycentric"`: Interpolate over a triangulation of sample points. Pixels outside the convex hull of data samples are extrapolated. * `"random-walk`: Apply a random walk from empty pixels until a sample is found. * *pixelSize*: The grid cell size in screen pixels (default `1`); ignored when *width* and *height* options are provided * *width*: The number of grid bins to include along the *x* dimension * *height*: The number of grid bins to include along the *y* dimension * *pad*: The bin padding, one of `1` (default) to include extra padding for the final bin, or `0` to make the bins flush with the maximum domain value ## Rect The `rect` mark, with `rectX` and `rectY` variants, draws axis-aligned rectangles defined by *x1*, *y1*, *x2*, and *y2*. For supported options, see the [Observable Plot `rect` documentation](https://observablehq.com/plot/marks/rect). ## Rule The `ruleX` mark draws a vertical line with a given *x* value, while the `ruleY` mark draws a horizontal line with a given *y* value. For supported options, see the [Observable Plot `rule` documentation](https://observablehq.com/plot/marks/rule). ## Text The `text` mark, with `textX` and `textY` variants, draws text at the given position in *x* and *y*. It is often used to label other marks. For supported options, see the [Observable Plot `text` documentation](https://observablehq.com/plot/marks/text). ## Tick The `tickX` draws a vertical line with a given *x* value, while the `tickY` mark draws a horizontal line with a given *y* value. Ticks have an optional secondary position dimension (*y* for `tickX` and *x* for `tickY`); this second dimension is ordinal, unlike a [`rule`](#rule), and requires a corresponding band scale. For supported options, see the [Observable Plot `tick` documentation](https://observablehq.com/plot/marks/tick). ## Vector The `vector` mark, with `vectorX` and `vectorY` variants, draws little arrows, typically positioned in *x* and *y* quantitative dimensions, with an optional magnitude (`length`) and direction (`rotate`), as in a vector field. The `spike` mark is equivalent to `vector`, but changes the default `shape`, `anchor`, and color options to draw a more spiky element. For supported options, see the [Observable Plot `vector` documentation](https://observablehq.com/plot/marks/vector). **(end JavaScript API)** **(begin Python API)** # Marks Marks are graphical elements that visualize data through encoding *channels* such as *x* and *y* position, *fill* color, and *r* (radius) size. Marks are added to a [`Plot`](./plot) using mark directives from `vgplot` (for example `vg.bar_y(...)`). Most mark functions take a *data* source and an *options* object that specifies encoding channels or constant values. To visualize data from a backing database, pass a `DataDef` object (from `vg.parquet()`, `vg.csv()`, etc.) or a `vg.source("table")` reference as the first positional argument. Interactive filtering is expressed via the `filter_by` keyword (see the [Python vgplot README](https://pypi.org/project/vgplot/) for details on selection wiring). ```python import vgplot as vg vg.plot( vg.bar_y(vg.source("data"), x="a", y="b", fill="steelblue", opacity=0.5), ) ``` The example above specifies a bar chart with bars oriented vertically. Data is drawn from the `"data"` table, with the column `"a"` mapped to an ordinal *x* axis and the column `"b"` mapped to the *y* axis. The *fill* option is the constant CSS color `"steelblue"` and the *opacity* is a constant `0.5`. For encoding channels, strings are interpreted as column names *unless* they match a reserved constant for that key, such as a CSS color name for the *fill* or *stroke* options. If an explicit array of data values is provided instead of a database-backed source, vgplot will visualize that data without issuing any queries to the database. This functionality is particularly useful for adding manual annotations, such as custom rules or text labels. Marks that only add reference lines or shapes (e.g., [`frame`](#frame), [`axis_x`](#axis), [`grid_y`](#grid), [`hexgrid`](#hexgrid), [`graticule`](#geo), [`sphere`](#geo)) do not require corresponding data, and take only *options*. Marks use the semantics of [Observable Plot](https://observablehq.com/plot/features/marks). For example, mark variants may indicate not only shapes but also data type assumptions. The [`bar_y`](#bar) mark above assumes a discrete (ordinal) *x* axis and will produce a `band` scale, whereas the related [`rect_y`](#rect) mark instead assumes a continuous *x* axis and by default will produce a `linear` scale. ## Area An `area` mark, with `area_x` and `area_y` variants. When feasible, the `area_x` and `area_y` marks will perform [M4 optimization](https://observablehq.com/@uwdata/m4-scalable-time-series-visualization) to limit the number of sample points returned from the database. Use `vg.source("data", optimize=False)` as the mark `data` argument to disable this behavior. For supported options, see the [Observable Plot `area` documentation](https://observablehq.com/plot/marks/area). ## Arrow The `arrow` mark provides line segments with arrow heads. For supported options, see the [Observable Plot `arrow` documentation](https://observablehq.com/plot/marks/arrow). ## Axis To go beyond the built-in axis generation, the axis mark supports explicit inclusion of axes, along with control over drawing order. The provided mark directives are `axis_x` and `axis_y` (for standard axes) as well as `axis_fx` and `axis_fy` (for facet axes). For supported options, see the [Observable Plot `axis` documentation](https://observablehq.com/plot/marks/axis). ## Bar The `bar_x` and `bar_y` marks draw rectangles, and should be used when one dimension is ordinal and the other is quantitative. For supported options, see the [Observable Plot `bar` documentation](https://observablehq.com/plot/marks/bar). ## Cell The `cell` mark, with `cell_x` and `cell_y` variants, draws rectangles positioned in two ordinal dimensions. For supported options, see the [Observable Plot `cell` documentation](https://observablehq.com/plot/marks/cell). ## Contour The `contour` mark draws isolines to delineate regions above and below a particular continuous value. It is often used to convey densities as a height field. The special column name `"density"` can be used to map density values to the *fill* or *stroke* options. The supported *options* are: * *x*: The x dimension encoding channel * *y*: The y dimension encoding channel * *fill*: The contour fill color * *stroke*: The contour stroke color * *thresholds*: The number of contour thresholds to include (default `10`) * *bandwidth*: The kernel density bandwidth for smoothing, in pixels (default `20`) * *interpolate*: The binning interpolation method to use, one of `"linear"` (default) or `"none"` * *pixel\_size*: The grid cell size in screen pixels (default `2`); ignored when *width* and *height* options are provided * *width*: The number of grid bins to include along the *x* dimension * *height*: The number of grid bins to include along the *y* dimension * *pad*: The bin padding, one of `0` (default) to make the bins flush with the maximum domain value, or `1` to include extra padding for the final bin * Other standard mark options including *fill\_opacity* and *stroke\_width* ## Delaunay Given set of points in x and y, the Delaunay marks compute the Delaunay triangulation, its dual the Voronoi tessellation, and the convex hull. The supported marks are `voronoi`, `voronoi_mesh`, `delaunay_link`, `delaunay_mesh`, and `hull`. For more, see the [Observable Plot `delaunay` documentation](https://observablehq.com/plot/marks/delaunay). ## Density 1D The 1D density marks show smoothed point cloud densities along one dimension. The `density_x` and `density_y` marks bin the data, count the number of records that fall into each bin, smooth the resulting counts, then plot the smoothed distribution (by default using an `area` mark). The `density_x` mark maps density values to the *x* dimension automatically, while `density_y` maps the density values to the *y* dimension. The supported *options* are: * *x*: The x dimension encoding channel, used with `density_y` * *y*: The y dimension encoding channel, used with `density_x` * *type*: The mark type to use (default [`area_x`](#area) or [`area_y`](#area)) * *bins*: The number of bins (default `1024`) * *bandwidth*: The kernel density bandwidth for smoothing, in pixels (default `20`) * Any options accepted by the mark *type*, including *stroke* and *fill* ## Density 2D The 2D `density` mark shows smoothed point cloud densities along two dimensions. The mark will bin the data, count the number of records that fall into each bin, smooth the resulting counts, then plot the smoothed distribution (by default using a circular `dot` mark). The `density` mark calculates density values that can be mapped to encoding channels such as *fill* or *r* using the column name `"density"`. The supported *options* are: * *x*: The x dimension encoding channel * *y*: The y dimension encoding channel * *type*: The mark type to use (default [`dot`](#dot)) * *bandwidth*: The kernel density bandwidth for smoothing, in pixels (default `20`) * *interpolate*: The binning interpolation method to use, one of `"linear"` (default) or `"none"` * *pixel\_size*: The grid cell size in screen pixels (default `2`); ignored when *width* and *height* options are provided * *width*: The number of grid bins to include along the *x* dimension * *height*: The number of grid bins to include along the *y* dimension * *pad*: The bin padding, one of `0` (default) to make the bins flush with the maximum domain value, or `1` to include extra padding for the final bin * Any options accepted by the mark *type*, including *fill*, *stroke*, and *r* ## Dense Line Rather than plot point densities, the `dense_line` mark plots line densities: the mark forms a binned raster grid and "draws" lines into it. To avoid over-weighting steep lines, by default each drawn series will be normalized on a per-column basis to approximate arc length normalization. The values for each series are then aggregated to form the line density, which is then drawn as an image similar to the [`raster`](#raster) mark. The supported *options* are: * *x*: The x dimension encoding channel * *y*: The y dimension encoding channel * *bandwidth*: The kernel density bandwidth for smoothing (default `0`) * *pixel\_size*: The grid cell size in screen pixels (default `1`) * *pad*: The bin padding, one of `1` (default) to include extra padding for the final bin, or `0` to make the bins flush with the maximum domain value. * *width*: The number of grid bins to include along the *x* dimension * *height*: The number of grid bins to include along the *y* dimension * *normalize*: Boolean flag (default `true`) controlling approximate arc length normalization. ## Dot The `dot` mark, with `dot_x` and `dot_y` variants, draws circles or other symbols positioned in *x* and *y* as in a scatterplot. The `circle` and `hexagon` marks are convenient shorthands for specific shapes. For supported options, see the [Observable Plot `dot` documentation](https://observablehq.com/plot/marks/dot). ## Frame The `frame` mark draws a rectangle around the plot area. It does not take a *data* argument. For supported options, see the [Observable Plot `frame` documentation](https://observablehq.com/plot/marks/frame). ## Geo The `geo` mark draws geographic features—polygons, lines, points, and other geometry—often as thematic maps. Input data can be provided directly as an array of GeoJSON features or geographic data can be loaded and queried directly in DuckDB using the `spatial` extension. The *geometry* option indicates the column name containing GeoJSON features or GeoJSON geometry objects. If *geometry* is not specified, the mark will interpret input objects as GeoJSON when data is passed in directly. When querying geometry from a DuckDB table, the *geometry* option will default to `'geom'` (the default name for geometry data loaded using the `spatial` extension's `ST_Read` function) and will be automatically converted to GeoJSON format in the database using the `ST_asGeoJSON` function. If the *geometry* option is specified, automatic conversion of DuckDB query results is *not* performed; this enables more fine-grained control, but may require explicit conversion of data to GeoJSON format using `ST_asGeoJSON` (or equivalently using Mosaic's `geojson()` SQL helper). The `sphere` and `graticule` marks (which do not accept input data) include the sphere of the Earth and global reference lines, respectively. For other supported options, see the [Observable Plot `geo` documentation](https://observablehq.com/plot/marks/geo). ## Grid The grid mark is a specially-configured rule for drawing an axis-aligned grid. To go beyond the built-in axis generation, the grid mark supports explicit inclusion of grid lines, along with control over drawing order. The provided mark directives are `grid_x` and `grid_y` (for standard axes) as well as `grid_fx` and `grid_fy` (for facet axes). For supported options, see the [Observable Plot `grid` documentation](https://observablehq.com/plot/marks/grid). ## Heatmap The `heatmap` mark is a raster mark with default options for accurate density estimation via smoothing. The *bandwidth* (`20`), *interpolate* (`"linear"`), and *pixel\_size* (`2`) options are set to produce smoothed density heatmaps. For all supported options, see the [`raster`](#raster) mark. ## Hexbin The `hexbin` mark bins data into a hexagonal grid and visualizes aggregate functions per bin (e.g., `count` for binned density). Hexagonal binning and aggregation are pushed to the backing database. Aggregate functions can be used for the mark *fill*, *stroke*, or radius size *r* options. The supported *options* are: * *x*: The x dimension encoding channel * *y*: The y dimension encoding channel * *type*: The mark type to use (default [`hexagon`](#dot)) * *bin\_width*: The hexagon bin width in screen pixels (default `20`) * Any options accepted by the mark *type*, including *fill*, *stroke*, *r*. ## Hexgrid The `hexgrid` mark draws a hexagonal grid spanning the frame. For supported options, see the [Observable Plot `hexgrid` documentation](https://observablehq.com/plot/marks/hexgrid). ## Image The `image` mark draws images centered at the given position in *x* and *y*. For supported options, see the [Observable Plot `image` documentation](https://observablehq.com/plot/marks/image). ## Line A `line` mark, with `line_x` and `line_y` variants. When feasible, the `line_x` and `line_y` marks will perform [M4 optimization](https://observablehq.com/@uwdata/m4-scalable-time-series-visualization) to limit the number of sample points returned from the database. Use `vg.source("data", optimize=False)` as the mark `data` argument to disable this behavior. For supported options, see the [Observable Plot `line` documentation](https://observablehq.com/plot/marks/line). ## Regression The `regression_y` mark draws a regression line and optional confidence interval area for a linear regression fit. The regression calculation is pushed to the backing database. The supported *options* are: * *x*: The x dimension (predictor) encoding channel * *y*: The y dimension (predicted) encoding channel * *ci*: The confidence level (default `0.95`) to visualize as a confidence band area; use zero or `null` to suppress * *precision*: The distance (in pixels) between samples of the confidence band (default `4`) ## Link The `link` mark draws straight lines between two points \[*x1*, *y1*] and \[*x2*, *y2*] in quantitative dimensions. For supported options, see the [Observable Plot `link` documentation](https://observablehq.com/plot/marks/link). ## Raster The `raster` mark draws an image whose pixel colors are a function of the underlying data. The *x* and *y* data domains are binned into the cells ("pixels") of a raster grid, typically with an aggregate function evaluated over the binned data. The result can be optionally smoothed (blurred) in-browser. To create a smoothed density heatmap, use the [`heatmap`](#heatmap) mark; this is a raster mark with different default options. The supported *options* are: * *x*: The x dimension encoding channel * *y*: The y dimension encoding channel * *fill*: The pixel fill color. Use the special value `"density"` to map computed density values to pixel colors. Use an aggregate expression to instead visualize an aggregate value per raster bin. If *fill* is set to a constant color or to a non-aggregate field, opacity will be used to convey densities. If a non-aggregate (group by) field is provided, multiple rasters are created with a unique categorical color per layer. * *fill\_opacity*: The pixel fill opacity. Use the special value `"density"` to map computed density values to opacity. Use an aggregate expression to instead visualize an aggregate value per raster bin. * *weight*: A data column by which to weight computed densities * *bandwidth*: The kernel density bandwidth for smoothing, in pixels (default `0`) * *interpolate*: The binning interpolation method to use. The `"none"` and `"linear"` methods are performed in-database and only fill bins corresponding to observed data samples. The other methods are performed in-browser and interpolate to fill all raster pixels. The options are: * `"none"` (default): Map data samples to single bins only. * `"linear"`: Linearly distribute the "weight" of a sample across adjacent bin boundaries. Linear binning provides more stable and accurate density estimation upon subsequent smoothing. * `"nearest"`: Perform nearest-neighbor interpolation, forming a pixel-level Voronoi diagram. * `"barycentric"`: Interpolate over a triangulation of sample points. Pixels outside the convex hull of data samples are extrapolated. * `"random-walk`: Apply a random walk from empty pixels until a sample is found. * *pixel\_size*: The grid cell size in screen pixels (default `1`); ignored when *width* and *height* options are provided * *width*: The number of grid bins to include along the *x* dimension * *height*: The number of grid bins to include along the *y* dimension * *pad*: The bin padding, one of `1` (default) to include extra padding for the final bin, or `0` to make the bins flush with the maximum domain value ## Rect The `rect` mark, with `rect_x` and `rect_y` variants, draws axis-aligned rectangles defined by *x1*, *y1*, *x2*, and *y2*. For supported options, see the [Observable Plot `rect` documentation](https://observablehq.com/plot/marks/rect). ## Rule The `rule_x` mark draws a vertical line with a given *x* value, while the `rule_y` mark draws a horizontal line with a given *y* value. For supported options, see the [Observable Plot `rule` documentation](https://observablehq.com/plot/marks/rule). ## Text The `text` mark, with `text_x` and `text_y` variants, draws text at the given position in *x* and *y*. It is often used to label other marks. For supported options, see the [Observable Plot `text` documentation](https://observablehq.com/plot/marks/text). ## Tick The `tick_x` mark draws a vertical line with a given *x* value, while the `tick_y` mark draws a horizontal line with a given *y* value. Ticks have an optional secondary position dimension (*y* for `tick_x` and *x* for `tick_y`); this second dimension is ordinal, unlike a [`rule`](#rule), and requires a corresponding band scale. For supported options, see the [Observable Plot `tick` documentation](https://observablehq.com/plot/marks/tick). ## Vector The `vector` mark, with `vector_x` and `vector_y` variants, draws little arrows, typically positioned in *x* and *y* quantitative dimensions, with an optional magnitude (`length`) and direction (`rotate`), as in a vector field. The `spike` mark is equivalent to `vector`, but changes the default `shape`, `anchor`, and color options to draw a more spiky element. For supported options, see the [Observable Plot `vector` documentation](https://observablehq.com/plot/marks/vector). **(end Python API)** --- --- url: /mosaic/api/vgplot/interactors.md --- **(begin JavaScript API)** # Interactors Interactors imbue plots with interactive behavior, such as selecting or highlighting values, and panning or zooming the display. To determine which fields (database columns) an interactor should select, an interactor defaults to looking at the corresponding encoding channels for the most recently added mark. Alternatively, interactors accept options that explicitly indicate which data fields should be selected. ## toggle `toggle(options)` Select individual data values by clicking / shift-clicking points. The supported *options* are: * *as*: The [Selection](../core/selection) to populate with filter predicates. * *channels*: An array of encoding channels (e.g., `"x"`, `"y"`, `"color"`) indicating the data values to select. * *peers*: A Boolean-flag (default `true`) indicating if all marks in the current plot should be considered "peers" in the clients set used to perform cross-filtering. A peer mark will be exempt from filtering. Set this to false if you are using a cross-filtered selection but want to filter across marks within the same plot. ### toggleX `toggleX(options)` A shorthand for a [`toggle`](#toggle) interactor over the `"x"` encoding channel only. ### toggleY `toggleY(options)` A shorthand for a [`toggle`](#toggle) interactor over the `"y"` encoding channel only. ### toggleColor `toggleColor(options)` A shorthand for a [`toggle`](#toggle) interactor over the `"color"` encoding channel only. ## nearest Select the nearest value to the current cursor position. ### nearestX `nearestX(options)` Select the nearest value along the x dimension. The supported *options* are: * *as*: The [Selection](../core/selection) to populate with filter predicates. * *field*: The field to select. If not specified, the field backing the `"x"` encoding channel of the most recently added mark is used. ### nearestY `nearestY(options)` Select the nearest value along the y dimension. The supported *options* are: * *as*: The [Selection](../core/selection) to populate with filter predicates. * *field*: The field to select. If not specified, the field backing the `"y"` encoding channel of the most recently added mark is used. ## region `region(options)` Select point values from elements within a rectangular region. Unlike `interval` interactors (which select a domain value range along an axis), the `region` interactor generates clauses for values extracted from the selected set of on-screen elements. This interactor functions similar to `toggle`, but uses a rectangular selection region rather than click / tap interactions. To select non-visualized data fields, use the plot `channels` property to define additional named channels, which can then be included in this interactor's *channels* option. * *as*: The [Selection](../core/selection) to populate with filter predicates. A clause of the form `(field = value1) OR (field = value2) ...` is added for the currently selected values. * *channels*: An array of encoding channels (e.g., `"x"`, `"y"`, `"color"`) indicating the data values to select. A sub-clause will be included for each channel. * *peers*: A Boolean-flag (default `true`) indicating if all marks in the current plot should be considered "peers" in the clients set used to perform cross-filtering. A peer mark will be exempt from filtering. Set this to false if you are using a cross-filtered selection but want to filter across marks within the same plot. * *brush*: An optional object of CSS style attribute-value pairs for the selection brush (SVG `rect`) element. ## interval Select all values within an interval range. ### intervalX `intervalX(options)` Select a 1D interval range along the x dimension. The supported *options* are: * *as*: The [Selection](../core/selection) to populate with filter predicates. * *field*: The field to select. If not specified, the field backing the `"x"` encoding channel of the most recently added mark is used. * *pixelSize*: The size of an interactive "pixel" (default 1). If set larger, the interval brush will "snap" to a grid larger than visible pixels. In some cases this can be helpful to improve scalability to large data by reducing interactive resolution. * *peers*: A Boolean-flag (default `true`) indicating if all marks in the current plot should be considered "peers" in the clients set used to perform cross-filtering. A peer mark will be exempt from filtering. Set this to false if you are using a cross-filtered selection but want to filter across marks within the same plot. * *brush*: An optional object of CSS style attribute-value pairs for the selection brush (SVG `rect`) element. ### intervalY `intervalY(options)` Select a 1D interval range along the y dimension. The supported *options* are: * *as*: The [Selection](../core/selection) to populate with filter predicates. * *field*: The field to select. If not specified, the field backing the `"y"` encoding channel of the most recently added mark is used. * *pixelSize*: The size of an interactive "pixel" (default 1). If set larger, the interval brush will "snap" to a grid larger than visible pixels. In some cases this can be helpful to improve scalability to large data by reducing interactive resolution. * *peers*: A Boolean-flag (default `true`) indicating if all marks in the current plot should be considered "peers" in the clients set used to perform cross-filtering. A peer mark will be exempt from filtering. Set this to false if you are using a cross-filtered selection but want to filter across marks within the same plot. * *brush*: An optional object of CSS style attribute-value pairs for the selection brush (SVG `rect`) element. ### intervalXY `intervalXY(options)` Select a 2D interval range along the x and y dimensions. The supported *options* are: * *as*: The [Selection](../core/selection) to populate with filter predicates. * *xfield*: The x field to select. If not specified, the field backing the `"x"` encoding channel of the most recently added mark is used. * *yfield*: The y field to select. If not specified, the field backing the `"y"` encoding channel of the most recently added mark is used. * *pixelSize*: The size of an interactive "pixel" (default 1). If set larger, the interval brush will "snap" to a grid larger than visible pixels. In some cases this can be helpful to improve scalability to large data by reducing interactive resolution. * *peers*: A Boolean-flag (default `true`) indicating if all marks in the current plot should be considered "peers" in the clients set used to perform cross-filtering. A peer mark will be exempt from filtering. Set this to false if you are using a cross-filtered selection but want to filter across marks within the same plot. * *brush*: An optional object of CSS style attribute-value pairs for the selection brush (SVG `rect`) element. ## pan & zoom Pan or zoom a plot. To pan, click and drag within a plot. To zoom, scroll within a plot. Panning and zooming is implemented by changing the `x` and/or `y` scale domains and re-rendering the plot in response. Pan/zoom interactors will automatically update the plot `xDomain` and `yDomain` attributes. For linked panning and zooming across plots, first define your own selections and pass them as options. You can additionally use such selections to have the pan/zoom state filter other marks. All pan/zoom directives share the same possible *options*: * *x*: The [Selection](../core/selection) over the `x` encoding channel domain. If unspecified, a new selection instance is used. * *y*: The [Selection](../core/selection) over the `y` encoding channel domain. If unspecified, a new selection instance is used. * *xfield*: The x field to select. If not specified, the field backing the `"x"` encoding channel of the most recently added mark is used. * *yfield*: The y field to select. If not specified, the field backing the `"y"` encoding channel of the most recently added mark is used. ### pan `pan(options)` Pan the plot in either the `x` or `y` dimension. Do not perform zooming. The supported *options* are listed above. ### panX `panX(options)` Pan the plot in the `x` dimension only. Do not perform zooming. The supported *options* are listed above. ### panY `panY(options)` Pan the plot in the `y` dimension only. Do not perform zooming. The supported *options* are listed above. ### panZoom `panZoom(options)` Pan or zoom the plot in either the `x` or `y` dimension. The supported *options* are listed above. ### panZoomX `panZoomX(options)` Pan or zoom the plot in the `x` dimension only. The supported *options* are listed above. ### panZoomY `panZoomY(options)` Pan or zoom the plot in the `y` dimension only. The supported *options* are listed above. ## highlight `highlight(options)` Highlight individual visualized data points based on a [Selection](../core/selection). Selected values keep their normal appearance. Unselected values are deemphasized. * *by*: The [Selection](../core/selection) driving the highlighting. * *channels*: An optional object of channel/value mappings that defines what CSS styles to apply to deemphasized items. The default value is to set the `opacity` channel to `0.2`. **(end JavaScript API)** **(begin Python API)** # Interactors Interactors imbue plots with interactive behavior, such as selecting or highlighting values, and panning or zooming the display. To determine which fields (database columns) an interactor should select, an interactor defaults to looking at the corresponding encoding channels for the most recently added mark. Alternatively, interactors accept options that explicitly indicate which data fields should be selected. ## toggle `toggle(options)` Select individual data values by clicking / shift-clicking points. The supported *options* are: * *bind*: The [Selection](../core/selection) to populate with filter predicates. * *channels*: An array of encoding channels (e.g., `"x"`, `"y"`, `"color"`) indicating the data values to select. * *peers*: A Boolean-flag (default `true`) indicating if all marks in the current plot should be considered "peers" in the clients set used to perform cross-filtering. A peer mark will be exempt from filtering. Set this to false if you are using a cross-filtered selection but want to filter across marks within the same plot. ### toggle\_x `toggle_x(options)` A shorthand for a [`toggle`](#toggle) interactor over the `"x"` encoding channel only. ### toggle\_y `toggle_y(options)` A shorthand for a [`toggle`](#toggle) interactor over the `"y"` encoding channel only. ### toggle\_color `toggle_color(options)` A shorthand for a [`toggle`](#toggle) interactor over the `"color"` encoding channel only. ## nearest Select the nearest value to the current cursor position. ### nearest\_x `nearest_x(options)` Select the nearest value along the x dimension. The supported *options* are: * *bind*: The [Selection](../core/selection) to populate with filter predicates. * *field*: The field to select. If not specified, the field backing the `"x"` encoding channel of the most recently added mark is used. ### nearest\_y `nearest_y(options)` Select the nearest value along the y dimension. The supported *options* are: * *bind*: The [Selection](../core/selection) to populate with filter predicates. * *field*: The field to select. If not specified, the field backing the `"y"` encoding channel of the most recently added mark is used. ## region `region(options)` Select point values from elements within a rectangular region. Unlike `interval` interactors (which select a domain value range along an axis), the `region` interactor generates clauses for values extracted from the selected set of on-screen elements. This interactor functions similar to `toggle`, but uses a rectangular selection region rather than click / tap interactions. To select non-visualized data fields, use the plot `channels` property to define additional named channels, which can then be included in this interactor's *channels* option. * *bind*: The [Selection](../core/selection) to populate with filter predicates. A clause of the form `(field = value1) OR (field = value2) ...` is added for the currently selected values. * *channels*: An array of encoding channels (e.g., `"x"`, `"y"`, `"color"`) indicating the data values to select. A sub-clause will be included for each channel. * *peers*: A Boolean-flag (default `true`) indicating if all marks in the current plot should be considered "peers" in the clients set used to perform cross-filtering. A peer mark will be exempt from filtering. Set this to false if you are using a cross-filtered selection but want to filter across marks within the same plot. * *brush*: An optional object of CSS style attribute-value pairs for the selection brush (SVG `rect`) element. ## interval Select all values within an interval range. ### interval\_x `interval_x(options)` Select a 1D interval range along the x dimension. The supported *options* are: * *bind*: The [Selection](../core/selection) to populate with filter predicates. * *field*: The field to select. If not specified, the field backing the `"x"` encoding channel of the most recently added mark is used. * *pixel\_size*: The size of an interactive "pixel" (default 1). If set larger, the interval brush will "snap" to a grid larger than visible pixels. In some cases this can be helpful to improve scalability to large data by reducing interactive resolution. * *peers*: A Boolean-flag (default `true`) indicating if all marks in the current plot should be considered "peers" in the clients set used to perform cross-filtering. A peer mark will be exempt from filtering. Set this to false if you are using a cross-filtered selection but want to filter across marks within the same plot. * *brush*: An optional object of CSS style attribute-value pairs for the selection brush (SVG `rect`) element. ### interval\_y `interval_y(options)` Select a 1D interval range along the y dimension. The supported *options* are: * *bind*: The [Selection](../core/selection) to populate with filter predicates. * *field*: The field to select. If not specified, the field backing the `"y"` encoding channel of the most recently added mark is used. * *pixel\_size*: The size of an interactive "pixel" (default 1). If set larger, the interval brush will "snap" to a grid larger than visible pixels. In some cases this can be helpful to improve scalability to large data by reducing interactive resolution. * *peers*: A Boolean-flag (default `true`) indicating if all marks in the current plot should be considered "peers" in the clients set used to perform cross-filtering. A peer mark will be exempt from filtering. Set this to false if you are using a cross-filtered selection but want to filter across marks within the same plot. * *brush*: An optional object of CSS style attribute-value pairs for the selection brush (SVG `rect`) element. ### interval\_xy `interval_xy(options)` Select a 2D interval range along the x and y dimensions. The supported *options* are: * *bind*: The [Selection](../core/selection) to populate with filter predicates. * *xfield*: The x field to select. If not specified, the field backing the `"x"` encoding channel of the most recently added mark is used. * *yfield*: The y field to select. If not specified, the field backing the `"y"` encoding channel of the most recently added mark is used. * *pixel\_size*: The size of an interactive "pixel" (default 1). If set larger, the interval brush will "snap" to a grid larger than visible pixels. In some cases this can be helpful to improve scalability to large data by reducing interactive resolution. * *peers*: A Boolean-flag (default `true`) indicating if all marks in the current plot should be considered "peers" in the clients set used to perform cross-filtering. A peer mark will be exempt from filtering. Set this to false if you are using a cross-filtered selection but want to filter across marks within the same plot. * *brush*: An optional object of CSS style attribute-value pairs for the selection brush (SVG `rect`) element. ## pan & zoom Pan or zoom a plot. To pan, click and drag within a plot. To zoom, scroll within a plot. Panning and zooming is implemented by changing the `x` and/or `y` scale domains and re-rendering the plot in response. Pan/zoom interactors will automatically update the plot `x_domain` and `y_domain` attributes. For linked panning and zooming across plots, first define your own selections and pass them as options. You can additionally use such selections to have the pan/zoom state filter other marks. All pan/zoom directives share the same possible *options*: * *x*: The [Selection](../core/selection) over the `x` encoding channel domain. If unspecified, a new selection instance is used. * *y*: The [Selection](../core/selection) over the `y` encoding channel domain. If unspecified, a new selection instance is used. * *xfield*: The x field to select. If not specified, the field backing the `"x"` encoding channel of the most recently added mark is used. * *yfield*: The y field to select. If not specified, the field backing the `"y"` encoding channel of the most recently added mark is used. ### pan `pan(options)` Pan the plot in either the `x` or `y` dimension. Do not perform zooming. The supported *options* are listed above. ### pan\_x `pan_x(options)` Pan the plot in the `x` dimension only. Do not perform zooming. The supported *options* are listed above. ### pan\_y `pan_y(options)` Pan the plot in the `y` dimension only. Do not perform zooming. The supported *options* are listed above. ### pan\_zoom `pan_zoom(options)` Pan or zoom the plot in either the `x` or `y` dimension. The supported *options* are listed above. ### pan\_zoom\_x `pan_zoom_x(options)` Pan or zoom the plot in the `x` dimension only. The supported *options* are listed above. ### pan\_zoom\_y `pan_zoom_y(options)` Pan or zoom the plot in the `y` dimension only. The supported *options* are listed above. ## highlight `highlight(options)` Highlight individual visualized data points based on a [Selection](../core/selection). Selected values keep their normal appearance. Unselected values are deemphasized. * *by*: The [Selection](../core/selection) driving the highlighting. * *channels*: An optional object of channel/value mappings that defines what CSS styles to apply to deemphasized items. The default value is to set the `opacity` channel to `0.2`. **(end Python API)** --- --- url: /mosaic/api/vgplot/legends.md --- **(begin JavaScript API)** # Legends Legends visualize color and symbol scales to aid chart interpretation. Legends can also serve as [interactors](./interactors) that filter or highlight plot content. ::: warning At present only discrete legends can be used as interactors. We plan to add support for interval selections over continuous color ramps in the future. ::: ## colorLegend `colorLegend(options)` Create a new legend for a plot's `color` scale. The following *options* are supported: * *for*: A string indicating the [name](./attributes) of the corresponding plot. * *as*: A [Selection](../core/selection) updated by interactions with this legend. * Additional options that will be passed to the [Observable Plot legend method](https://observablehq.com/plot/features/legends#legend-options). If invoked as a directive within a plot definition, the *for* option should not be used, and the legend will be included as part of the plot itself. If invoked with the *for* option in a standalone fashion, returns a Web element containing the legend only. ## opacityLegend `opacityLegend(options)` Create a new legend for a plot's `opacity` scale. The following *options* are supported: * *for*: A string indicating the [name](./attributes) of the corresponding plot. * *as*: A [Selection](../core/selection) updated by interactions with this legend. * Additional options that will be passed to the [Observable Plot legend method](https://observablehq.com/plot/features/legends#legend-options). If invoked as a directive within a plot definition, the *for* option should not be used, and the legend will be included as part of the plot itself. If invoked with the *for* option in a standalone fashion, returns a Web element containing the legend only. ## symbolLegend `symbolLegend(options)` Create a new legend for a plot's `symbol` scale. The following *options* are supported: * *for*: A string indicating the [name](./attributes) of the corresponding plot. * *as*: A [Selection](../core/selection) updated by interactions with this legend. * Additional options that will be passed to the [Observable Plot legend method](https://observablehq.com/plot/features/legends#legend-options). If invoked as a directive within a plot definition, the *for* option should not be used, and the legend will be included as part of the plot itself. If invoked with the *for* option in a standalone fashion, returns a Web element containing the legend only. **(end JavaScript API)** **(begin Python API)** # Legends Legends visualize color and symbol scales to aid chart interpretation. Legends can also serve as [interactors](./interactors) that filter or highlight plot content. ::: warning At present only discrete legends can be used as interactors. We plan to add support for interval selections over continuous color ramps in the future. ::: ## color\_legend `vg.color_legend(...)` Create a new legend for a plot's `color` scale. The following *options* are supported: * *plot*: A string indicating the [name](./attributes) of the corresponding plot (also accepted as `for_`). * *bind*: A [Selection](../core/selection) updated by interactions with this legend. * Additional options that will be passed to the [Observable Plot legend method](https://observablehq.com/plot/features/legends#legend-options). If invoked as a directive within a `vg.plot(...)` definition, the *plot* option should not be used, and the legend will be included as part of the plot itself. If invoked with the *plot* option in a standalone fashion, returns a standalone legend. ## opacity\_legend `vg.opacity_legend(...)` Create a new legend for a plot's `opacity` scale. The following *options* are supported: * *plot*: A string indicating the [name](./attributes) of the corresponding plot (also accepted as `for_`). * *bind*: A [Selection](../core/selection) updated by interactions with this legend. * Additional options that will be passed to the [Observable Plot legend method](https://observablehq.com/plot/features/legends#legend-options). If invoked as a directive within a `vg.plot(...)` definition, the *plot* option should not be used, and the legend will be included as part of the plot itself. If invoked with the *plot* option in a standalone fashion, returns a standalone legend. ## symbol\_legend `vg.symbol_legend(...)` Create a new legend for a plot's `symbol` scale. The following *options* are supported: * *plot*: A string indicating the [name](./attributes) of the corresponding plot (also accepted as `for_`). * *bind*: A [Selection](../core/selection) updated by interactions with this legend. * Additional options that will be passed to the [Observable Plot legend method](https://observablehq.com/plot/features/legends#legend-options). If invoked as a directive within a `vg.plot(...)` definition, the *plot* option should not be used, and the legend will be included as part of the plot itself. If invoked with the *plot* option in a standalone fashion, returns a standalone legend. **(end Python API)** --- --- url: /mosaic/api/vgplot/layout.md --- **(begin JavaScript API)** # Layout Layout helpers for creating dashboard displays. ## vconcat `vconcat(...elements)` Vertically concatenate a collection of Web elements. Places elements in a column. ## hconcat `hconcat(...elements)` Horizontally concatenate a collection of Web elements. Places elements in a row. ## vspace `vspace(size)` Add vertical space between elements. If *size* is a number it is interpreted as a pixel value, otherwise it will be interpreted as a [CSS dimension](https://developer.mozilla.org/en-US/docs/Web/CSS/dimension). ## hspace `hspace(size)` Add horizontal space between elements. If *size* is a number it is interpreted as a pixel value, otherwise it will be interpreted as a [CSS dimension](https://developer.mozilla.org/en-US/docs/Web/CSS/dimension). **(end JavaScript API)** **(begin Python API)** # Layout Layout helpers for creating dashboard displays. ## vconcat `vg.vconcat(...elements)` Vertically concatenate elements in a column (same helpers as in JavaScript). ## hconcat `vg.hconcat(...elements)` Horizontally concatenate elements in a row. ## vspace `vg.vspace(size)` Add vertical space between elements. If *size* is a number it is interpreted as a pixel value, otherwise it will be interpreted as a [CSS dimension](https://developer.mozilla.org/en-US/docs/Web/CSS/dimension). ## hspace `vg.hspace(size)` Add horizontal space between elements. If *size* is a number it is interpreted as a pixel value, otherwise it will be interpreted as a [CSS dimension](https://developer.mozilla.org/en-US/docs/Web/CSS/dimension). **(end Python API)** --- --- url: /mosaic/api/vgplot/context.md --- # API Context The API context is a concept of the JavaScript `vgplot` package for embedding Mosaic in the browser. The Python package instead authors declarative specifications, so it has no equivalent. All `vgplot` methods are invoked within a surrounding *context* of evaluation. A context consists of all API methods, a [coordinator](../core/coordinator), a map of [named plots](#namedplots). A default context is used when exported methods are called directly. This default context uses the global coordinator (returned by `vg.coordinator()`) and a shared `namedPlots` map (`vg.namedPlots`). A dedicated context can be created using [`createAPIContext()`](#createapicontext) to: * use an alternative coordinator to run separate Mosaic instances on the same page, * use a separate namedPlot maps to avoid plot name collisions across specs, * or extend the vgplot API with additional components and methods. ## namedPlots `namedPlots` A map from plot names to plot instances. This map gets populated with a (name, plot) pair when a plot includes the `name` attribute. Stand-alone legend components use this map to lookup needed scale information for a plot. A default global map is exported from the `vgplot` module and used as part of the default context. An isolated `namedPlots` instance can be created as part of a new API context. ## createAPIContext `createAPIContext(options)` Create a new API context that exposes `vgplot` methods. The following options are supported: * *coordinator*: The Mosaic [coordinator](../core/coordinator) to use. By default, the global coordinator (`vg.coordinator()`) is used. A new coordinator instance can be provided to use a separate database connector and isolated params. * *namedPlots*: The named plot map to use. By default a new, empty named plot map is created. The `vg.namedPlots` instance can be provided to reuse the global default map. * *extensions*: API extensions to include in the created context. All methods and properties of the extension object will be copied to returned context object, potentially overwriting existing methods. * *...options*: Any other provided options will be included as properties of the `context` property of the generated API context object. This can be used to pass configuration values to extension methods. The resulting API context object exposes the vgplot API methods, along with any properties copied from the *extensions* option. The API context object also includes a `context` property, which references an object with `coordinator` and `namedPlots` properties along with any additional options to `createAPIContext`. ### Example ```js import { Coordinator, createAPIContext, socketConnector } from "uwdata/vgplot"; // create a new API context, using a coordinator with // a dedicated socket connector to a DuckDB server const api = createAPIContext({ coordinator: new Coordinator(socketConnector("ws://localhost:8001/")) }); // use the API context just like normal vgplot exports document.appendChild( api.vconcat( api.plot(...), ... ) ); ``` --- --- url: /mosaic/api/spec/format.md --- # JSON Specifications Both individual plots and interactive dashboards can be defined using declarative specifications in either [JSON](https://en.wikipedia.org/wiki/JSON) or [YAML](https://en.wikipedia.org/wiki/YAML) format. The code below shows an example specification in both YAML and JSON formats, as well as corresponding JavaScript code produced by [`astToESM`](parser-generators#asttoesm) and Python code produced by [`astToPython`](parser-generators#asttopython). To parse a JSON specification use [`parseSpec`](parser-generators##parsespec). To generate a running application from a parsed spec, use [`astToDOM`](parser-generators#asttodom). ```py \[Python] import vgplot as vg walk = vg.parquet("data/random-walk.parquet") point = vg.param(0) view = vg.vconcat( vg.slider(label="Bias", bind=point, min=0, max=1000, step=1), vg.plot( vg.area_y(walk, x="t", y=vg.sql("v + $point"), fill="steelblue"), vg.width(680), vg.height(200), ), ) ``` ::: tip The [TypeScript types in the `@uwdata/mosaic-spec` package](https://github.com/uwdata/mosaic/tree/main/packages/vgplot/spec/src/spec) provide comprehensive documentation of Mosaic declarative specifications. ::: ## Specification Format At the top-level, a specification may contain the following keys: ```json { "meta": { /* optional metadata */ }, "config": { /* optional configuration */ }, "data": { /* input data definitions */ }, "params": { /* param and selection definitions */ }, ... /* top-level element properties */ } ``` ### Metadata The `meta` object can contain arbitrary metadata information. Commonly used properties include `title` (the specification title), `description` (a longer text description), and `credit` (acknowledgements). ### Configuration The `config` object specifies additional configuration. At present the only supported property is `extensions`, a string or string array indicating DuckDB extensions to load. The following snippet loads the DuckDB `spatial` extension, which provides support for geometric data, projections, and spatial operations: ```json "config": { "extensions": "spatial" } ``` Additional configuration properties may be added in the future. ### Data Definitions Data definitions consist of an object where keys indicate dataset names and values describe the data. Both SQL queries and external files (and combinations thereof) are supported. The keys are order-sensitive, as some datasets may be derived from another. ```json { // a string value is interpreted as a query "queryData": "SELECT * FROM existingTable", // load a tab-delimited csv file "csvData": { "file": "data.csv", "delimiter": "\t" }, // load a json file, with explicit data type "jsonData": { "file": "data.json", "type": "json" }, // load a parquet file, queried upon load "parquetData": { "file": "data.parquet", "select": ["foo", "bar"], "where": "baz > 5" } } ``` The `file` key indicates files relative to the current directory (whether in the browser, or where a data server was launched locally). Most file types (`"csv"`, `"json"`, `"parquet"`) are inferred by file extension, but can be provided using the `type` key. Data definitions can also include parameters. In the example above, the table `"csvData"` includes a `delimiter` parameter, while the new table `"parquetData"` is created by first filtering rows and selecting a subset of columns from the source data. See the [data loading methods](../sql/data-loading) for the supported options. ### Params & Selections Param and selection definitions consist of an object where keys indicate the name and values provide the definition. The keys are order-sensitive, as some params may be derived from another. To refer to a param or selection later in the specification, use a `$`-prefixed name such as `$paramName`. ```json { "scalarParam": 5, // literal values map to params "arrayParam": [0, "$scalarParam"], // derived array-valued param // selection definitions are objects with a "select" key "singleSelection": { "select": "single" }, "unionSelection": { "select": "union" }, "intersectSelection": { "select": "intersect" }, "crossfilterSelection": { "select": "crossfiltter" } } ``` If a param reference is used in a specification but not defined, a new `intersect` selection with a matching name is created. ### Layout To layout elements, use objects with `hconcat` or `vconcat` keys, like so: ```json { "hconcat": [ ...elements ] } ``` To add spacing, use an object with an `hspace` or `vspace` key: ```json { "vconcat": [ /* ...elements */ { "vspace": "1em" } // or use a number for pixels /* ...more elements */ ] } ``` ### Inputs To specify an input, use an object with an `input` key whose value is the corresponding input type. The remaining keys should be valid input options. ```json { "input": "slider", "as": "$param", "min": 0, "max": 100, "step": 10 } ``` ### Plot To specify a plot, use an object with a `plot` key whose value is an array of mark, interactor, or legend specifications. The remaining top-level keys in the plot object should be attribute names. ```json { "plot": [ { "mark": "dot", "data": { "from": "tableName", "filterBy": "$selection" }, "x": "foo", // x-encode values of column "foo" "y": "bar", // y-encode values of column "bar" "r": { "sql": "SQRT($areaParam)" }, // size based on an expression "fill": "$colorParam" // set fill color to a param value }, { "select": "intervalXY", "as": "$selection" }, { "select": "highlight", "by": "$selection" } ], "yAxis": "right", "width": 500, "height": 500 } ``` Mark entries include a `mark` key whose value should be the mark type, a `data` key indicating the input data, and the remaining keys should be mark options such as encoding channels. Interactors are defined similarly, but using the `select` key. SQL expressions can be defined as objects with a single `sql` key. Param references (as in `"1 + $param"`) will be parsed and resolved. By default, param references evaluate to SQL literal values. To instead use a param to refer to a column name, use `$$` syntax: `"1 + $$param"`. ### Legends Standalone legends are defined using an object with a `legend` key: ```json { "legend": "color", // legend type "for": "plotName" // the plot _must_ have a name attribute } ``` --- --- url: /mosaic/api/spec/parser-generators.md --- # Specification Parser & Generators Methods to parse declarative specifications and generate applications or code as output. ## parseSpec `parseSpec(specification)` Parse a JSON *specification* and return the resulting abstract syntax tree (AST). The input *specification* can either be a JSON-formatted string or a JavaScript object. To instead use a YAML specification, parse the YAML text first: ```js import { parseSpec } from "@uwdata/mosaic-spec"; import yaml from "yaml"; const spec = yaml.parse(yamlText); parseSpec(spec); ``` The resulting AST node is an object with the following properties and methods: * *meta*: An object of specification metadata, corresponding to the input spec's top-level `meta` property. * *config*: An object for top-level configuration options, such as database extensions to load. * *root*: The root node for the rest of the AST. This might represent a `plot`, `hconcat`, `vconcat`, or other top-level specification element. * *data*: Dataset definitions as an array of key-value pairs. The keys are dataset names and the values are AST nodes for the dataset definition. * *params*: Param and Selection definitions as an array of key-value pairs. The keys are params names and the values are AST nodes for Param or Selection definitions. * *plotDefaults*: An array of plot attribute AST nodes, representing default attributes to apply to all plot instances. * *toJSON*: A method that returns the specification in JSON format. The result will be compatible with the original parsed input, but may not match it exactly. For example, implicitly defined selections will now have explicit top-level definitions. ### Example ```js import { parseSpec } from "@uwdata/mosaic-spec"; // declarative specification in JSON format const spec = { plot: [ { mark: "lineY", data: { from: "table" }, x: "date", y: "value" } ], width: 640, height: 200 }; // parse specification to internal AST (abstract syntax tree) const ast = parseSpec(spec); // serialize back to a normalized JSON format const json = ast.toJSON(); ``` ## astToDOM `astToDOM(ast, options)` Given a parsed specification AST, load data, generate Params/Selections, and instantiate corresponding web Document Object Model (DOM) elements. This is an `async` method and so returns a `Promise`. The supported *options* are: * *api*: A [vgplot API context](../vgplot/context) to use. By default, a new API context is created that uses the global `Coordinator` and a new, empty `namedPlots` map. * *params*: A `Map` from parameter names to live Param or Selection instances. The default is an empty map. A pre-populated map can be provided to reuse params across specifications. * *baseURL*: The base URL (default `null`) from which to load data files. The fulfilled value of the returned Promise is an object with the following properties: * *element*: The DOM element containing the initialized application. * *params*: A `Map` of parameter names to Param/Selection instances. ### Example ```js import { astToDOM } from "@uwdata/mosaic-spec"; // instantiate a running application // assumes standard browser facilities in globabl variable `window` const { element, // root DOM element of the application params // Map of all named Params and Selections } = await astToDOM(ast); // add application to current web page document.body.appendChild(element); ``` ## astToESM `astToESM(ast, options)` Given a parsed specification AST, generate corresponding JavaScript module (ESM) code that uses the `vgplot` API. The supported *options* are: * *baseURL*: The base URL (default `null`) from which to load data files. * *namespace*: The namespace to use for vgplot API methods (default `'vg'`)\`. * *connector*: The database connector to use, one of `null` (default, for no explicit connector code), `rest`, `socket`, or `wasm`. * *depth*: The starting text indentation depth (default `0`). * *imports*: A `Map` indicating external ESM packages to load. Each key is the name of the package to load, and each value is either a string or string array indicating what to import from that package. The default is `new Map([["@uwdata/vgplot", "* as vg"]])`. The return value is a string of generated ESM code. ### Example ```js import { astToESM } from "@uwdata/mosaic-spec"; // generate ESM (ECMAScript Module) code const code = astToESM(ast); ``` ## astToPython `astToPython(ast, options)` Given a parsed specification AST, generate corresponding Python code that uses the `vgplot` API. The supported *options* are: * *namespace*: The namespace to use for vgplot API methods (default `'vg'`). * *depth*: The starting text indentation depth (default `0`). The return value is a string of generated Python code. ### Example ```js import { astToPython } from "@uwdata/mosaic-spec"; // generate Python code const code = astToPython(ast); ``` --- --- url: /mosaic/api/duckdb/duckdb.md --- # DuckDB API The `DuckDB` class is a Promise-based Node.js API for interfacing with DuckDB, providing a convenient way to launch a server-side DuckDB instance. As illustrated in the snippet below, DuckDB queries can return either JavaScript objects or [Apache Arrow buffers](https://arrow.apache.org/). ```js import { DuckDB } from "@uwdata/mosaic-duckdb"; // create an in-memory DuckDB instance // to open a database file, pass the path as the first argument const db = new DuckDB(); // execute a query without a returned result, await completion await db.exec(`CREATE TABLE myTable AS SELECT * FROM 'my-data.parquet'`); // query for data, return as an array of JavaScript objects const res = await db.query(`SELECT COUNT(*) FROM myTable`); // query for data, return as a binary Apache Arrow buffer const buf = await db.arrowBuffer(`SELECT AVG(value) FROM myTable`); // shut down the DuckDB instance db.close(); ``` Unless provided with an explicit web URL (`http://...`), queries that load files (e.g., CSV, JSON, or Parquet) will do so relative to the current working directory. ## constructor `new DuckDB(path)` Create a new local DuckDB instance. The optional *path* argument indicates a database file path to load. If omitted, a memory-only database instance is constructed. ## close `db.close()` Close the current database connection. After closing, no more queries can be issued. ## exec `db.exec(sql)` Execute the provided *sql* query and return a Promise that resolves when query evaluation completes. ## query `db.query(sql)` Execute the provided *sql* query and return a Promise that resolves to the query result table as an array of JavaScript objects. ## arrowBuffer `db.arrowBuffer(sql)` Execute the provided *sql* query and return a Promise that resolves to the query result table as binary data in the [streaming Apache Arrow IPC format](https://arrow.apache.org/). ## prepare `db.prepare(sql)` Return a new prepared statement for the given *sql* query, which may contain `?` wildcard characters. The resulting prepared statement instance exposes `exec(params)` and `query(params)` methods that accept parameter values for query wildcards. --- --- url: /mosaic/api/duckdb/data-server.md --- # Data Server The data server provides network access to a server-side DuckDB instance from Node.js. Both WebSocket (`socket`) and HTTP (`rest`) connections are supported. ::: warning Due to persistent quality issues involving the DuckDB Node.js client and Arrow extension, we recommend using Mosaic's Python-based [`duckdb-server`](/server/) package instead. However, we retain this JavaScript-based server for both backwards compatibility and potential future use as quality issues improve. ::: ## dataServer `dataServer(db, options)` Launch a new data server instance. The *db* argument should be a [`DuckDB`](./duckdb) instance. The following *options* are supported: * *port*: The port number (default `3000`) on which to listen for query requests. * *rest*: Boolean flag (default `true`) indicating if HTTP REST connections should be enabled. * *socket*: Boolean flag (default `true`) indicating if WebSocket connections should be enabled. * *cache*: Boolean flag (default `true`) indicating if server-side caching should be enabled. Incoming queries may include a `persist` flag to request server-side caching of the result. The default cache folder is `.mosaic/cache`, relative to the current working directory. Once launched, the data server will accept HTTP POST requests containing JSON content that consists of a single object with the following properties: * *type*: The type of query. The type `"exec"` indicates that the provided query should be run with no return value. The `"arrow"` and `"json"` types indicate that a result table should be returned in the corresponding format. * *sql*: The SQL query string to issue to DuckDB. * *persist*: A Boolean flag (default `false`) indicating if the query result should be cached on the server's local file system. ### Examples Launch a data server in Node.js: ```js import { DuckDB, dataServer } from "@uwdata/mosaic-duckdb"; dataServer(new DuckDB(), { rest: true, socket: true }); ``` --- --- url: /mosaic/examples/area-sine.md --- # Area Sine Wave A test specification to compare M4 optimized and unoptimized area charts over a dense dual-tone sine wave. ## Specification ```py \[Python] import vgplot as vg wave = vg.csv("data/m4-area-sine.csv") brush = vg.selection.intersect() view = vg.vconcat( vg.plot( vg.area_y(data=wave, filter_by=brush, x="time_stamp", y="power"), vg.y_domain("Fixed"), vg.color_domain("Fixed"), vg.x_label(None), vg.width(680), vg.height(180), ), vg.vspace(5), vg.plot( vg.area_y( data=wave, filter_by=brush, optimize=False, x="time_stamp", y="power" ), vg.y_domain("Fixed"), vg.color_domain("Fixed"), vg.x_label(None), vg.width(680), vg.height(180), ), vg.vspace(10), vg.plot( vg.area_y(data=wave, optimize=False, x="time_stamp", y="power"), vg.interval_x(bind=brush), vg.y_domain("Fixed"), vg.width(680), vg.height(90), ), ) ``` --- --- url: /mosaic/examples/crossfilter.md --- # crossfilter ## Specification ```py \[Python] import vgplot as vg flights = vg.parquet("data/flights-200k.parquet") brush = vg.selection.crossfilter() view = vg.vconcat( vg.plot( vg.rect_y( data=flights, filter_by=brush, x=vg.bin("delay"), y=vg.count(), fill="steelblue", inset_left=0.5, inset_right=0.5, ), vg.interval_x(bind=brush), vg.x_domain("Fixed"), vg.x_label("Arrival Delay (min)"), vg.x_label_anchor("center"), vg.y_tick_format("s"), vg.height(200), ), vg.plot( vg.rect_y( data=flights, filter_by=brush, x=vg.bin("time"), y=vg.count(), fill="steelblue", inset_left=0.5, inset_right=0.5, ), vg.interval_x(bind=brush), vg.x_domain("Fixed"), vg.x_label("Departure Time (hour)"), vg.x_label_anchor("center"), vg.y_tick_format("s"), vg.height(200), ), ) ``` --- --- url: /mosaic/examples/facet-interval.md --- # Faceted Interval Selections A faceted plot with 2D interval selections. **Credit**: Adapted from https://observablehq.com/@observablehq/plot-non-faceted-marks ## Specification ```py \[Python] import vgplot as vg penguins = vg.parquet("data/penguins.parquet") sel = vg.selection.intersect() view = vg.hconcat( vg.plot( vg.frame(), vg.dot(penguins, x="bill_length", y="bill_depth", fill="#aaa", r=1), vg.dot( penguins, x="bill_length", y="bill_depth", fill="species", fx="sex", fy="species", ), vg.interval_xy(bind=sel, brush=vg.brush(stroke="transparent")), vg.highlight(by=sel), vg.name("plot"), vg.grid(True), vg.margin_right(60), vg.x_domain("Fixed"), vg.y_domain("Fixed"), vg.fx_domain("Fixed"), vg.fy_domain("Fixed"), vg.fx_label(None), vg.fy_label(None), ), ) ``` --- --- url: /mosaic/examples/legends.md --- # Legends Tests for different legend types and configurations. We test both legends defined within plots (with a zero-size frame) and external legends that reference a named plot. ## Specification ```py \[Python] import vgplot as vg toggle = vg.selection.single() interval = vg.selection.intersect() domain = vg.param(["foo", "bar", "baz", "bop", "doh"]) view = vg.vconcat( vg.hconcat( vg.plot( vg.color_legend(label="Color Swatch", bind=toggle), vg.name("color-categorical"), vg.color_scale("categorical"), vg.color_domain(domain), ), vg.hspace(35), vg.color_legend( plot="color-categorical", label="Color Swatch (External)", bind=toggle ), ), vg.hconcat( vg.plot( vg.symbol_legend(label="Symbol Swatch", bind=toggle), vg.name("symbol-categorical"), vg.symbol_domain(domain), ), vg.hspace(35), vg.symbol_legend( plot="symbol-categorical", label="Symbol Swatch (External)", bind=toggle ), ), vg.vspace("1em"), vg.hconcat( vg.plot( vg.opacity_legend(label="Opacity Ramp", bind=interval), vg.name("opacity-linear"), vg.opacity_domain([0, 100]), ), vg.hspace(30), vg.opacity_legend( plot="opacity-linear", label="Opacity Ramp (External)", bind=interval ), ), vg.hconcat( vg.plot( vg.opacity_legend(), vg.name("opacity-linear-no-label"), vg.opacity_domain([0, 100]), ), vg.hspace(30), vg.opacity_legend(plot="opacity-linear-no-label"), ), vg.vspace("1em"), vg.hconcat( vg.plot( vg.color_legend(label="Linear Color Ramp", bind=interval), vg.name("color-linear"), vg.color_domain([0, 100]), ), vg.hspace(30), vg.color_legend( plot="color-linear", label="Linear Color Ramp (External)", bind=interval ), ), vg.hconcat( vg.plot( vg.color_legend(), vg.name("color-linear-no-label"), vg.color_domain([0, 100]), ), vg.hspace(30), vg.color_legend(plot="color-linear-no-label"), ), vg.vspace("1em"), vg.hconcat( vg.plot( vg.color_legend(label="Logarithmic Color Ramp", bind=interval), vg.name("color-log"), vg.color_scale("log"), vg.color_domain([1, 100]), ), vg.hspace(30), vg.color_legend( plot="color-log", label="Logarithmic Color Ramp (External)", bind=interval ), ), vg.hconcat( vg.plot( vg.color_legend(label="Diverging Color Ramp", bind=interval), vg.name("color-diverging"), vg.color_scale("diverging"), vg.color_domain([-100, 100]), vg.color_constant(20), ), vg.hspace(30), vg.color_legend( plot="color-diverging", label="Diverging Color Ramp (External)", bind=interval, ), ), vg.hconcat( vg.plot( vg.color_legend(label="Diverging Symlog Color Ramp", bind=interval), vg.name("color-diverging-symlog"), vg.color_scale("diverging-symlog"), vg.color_domain([-100, 100]), vg.color_constant(20), ), vg.hspace(30), vg.color_legend( plot="color-diverging-symlog", label="Diverging Symlog Color Ramp (External)", bind=interval, ), ), vg.hconcat( vg.plot( vg.color_legend(label="Quantize Color Ramp"), vg.name("color-quantize"), vg.color_scale("quantize"), vg.color_domain([0, 100]), ), vg.hspace(30), vg.color_legend(plot="color-quantize", label="Quantize Color Ramp (External)"), ), vg.hconcat( vg.plot( vg.color_legend(label="Threshold Color Ramp"), vg.name("color-threshold"), vg.color_scale("threshold"), vg.color_domain([0, 10, 20, 40, 80]), ), vg.hspace(30), vg.color_legend( plot="color-threshold", label="Threshold Color Ramp (External)" ), ), plot_defaults={"margin": 0, "width": 0, "height": 20}, ) ``` --- --- url: /mosaic/examples/line.md --- # line ## Specification ```py \[Python] import vgplot as vg aapl = vg.parquet("data/stocks.parquet", where="Symbol = 'AAPL'") view = vg.plot( vg.line_y(aapl, x="Date", y="Close"), vg.width(680), vg.height(200), ) ``` --- --- url: /mosaic/duckdb.md --- # Mosaic DuckDB The Mosaic `duckdb` package provides facilities for running DuckDB from Node.js and handling query requests over a network connection. ::: tip This package runs a server-side DuckDB instance in Node.js. If instead you want to connect to DuckDB-WASM in a browser, skip this package and look at the [WASM connector](/api/core/connectors#wasmconnector) provided by the `mosaic-core` package. ::: ::: info DuckDB can also connect to and query other databases, such as PostgreSQL and MySQL. See the [multi-database support page](/api/core/multi-database-support) for examples. ::: ## DuckDB API The `DuckDB` class is a Promise-based Node.js API for interfacing with DuckDB, providing a convenient way to launch a server-side DuckDB instance. As illustrated in the snippet below, DuckDB queries can return either JavaScript objects or [Apache Arrow buffers](https://arrow.apache.org/). ```js import { DuckDB } from "@uwdata/mosaic-duckdb"; // create an in-memory DuckDB instance // to open a database file, pass the path as the first argument const db = new DuckDB(); // execute a query without a returned result, await completion await db.exec(`CREATE TABLE myTable AS SELECT * FROM 'my-data.parquet'`); // query for data, return as an array of JavaScript objects const res = await db.query(`SELECT COUNT(*) FROM myTable`); // query for data, return as a binary Apache Arrow buffer const buf = await db.arrowBuffer(`SELECT AVG(value) FROM myTable`); // shut down the DuckDB instance db.close(); ``` Unless provided with an explicit web URL (`http://...`), queries that load files (e.g., CSV, JSON, or Parquet) will do so relative to the current working directory. [DuckDB API Reference](/api/duckdb/duckdb) ## Data Server The data server provides network access to a server-side DuckDB instance. Both WebSocket (`socket`) and HTTP (`rest`) connections are supported. The following snippet launches a data server in Node.js: ```js import { DuckDB, dataServer } from "@uwdata/mosaic-duckdb"; dataServer(new DuckDB(), { rest: true, socket: true }); ``` By default the server listens to port 3000. If the coordinator sends a request to persist a result, the data server will cache the results to the local filesystem. The default cache folder is `.mosaic/cache`, relative to the current working directory. [Data Server API Reference](/api/duckdb/data-server) --- --- url: /mosaic/examples/region-tests.md --- # Region Interactor Tests ## Specification ```py \[Python] import vgplot as vg bls_unemp = vg.parquet("data/bls-metro-unemployment.parquet") feed = vg.spatial("data/usgs-feed.geojson") world = vg.spatial("data/countries-110m.json", layer="land") counties = vg.spatial("data/us-counties-10m.json", layer="counties") series = vg.selection.single() quakes = vg.selection.single() counties_filter = vg.selection.single() view = vg.vconcat( vg.plot( vg.rule_y(data=[0]), vg.line_y( data=bls_unemp, optimize=False, x="date", y="unemployment", z="division", stroke="steelblue", stroke_opacity=0.9, curve="monotone-x", ), vg.region(channels=["z"], bind=series), vg.highlight(by=series), vg.margin_left(24), vg.x_label(None), vg.x_ticks(10), vg.x_line(True), vg.y_line(True), vg.y_label("Unemployment (%)"), vg.y_grid(True), vg.margin_right(0), ), vg.vspace(10), vg.plot( vg.geo(world, fill="currentColor", fill_opacity=0.2), vg.sphere(stroke_width=0.5), vg.geo( feed, channels=vg.channels(id="id"), r=vg.sql("POW(10, mag)"), stroke="red", fill="red", fill_opacity=0.2, title="title", href="url", target="_blank", ), vg.region(channels=["id"], bind=quakes), vg.highlight(by=quakes), vg.margin(2), vg.projection_type("equirectangular"), ), vg.vspace(10), vg.plot( vg.geo( counties, channels=vg.channels(id="id"), stroke="currentColor", stroke_width=0.25, ), vg.region(channels=["id"], bind=counties_filter), vg.highlight(by=counties_filter), vg.margin(0), vg.projection_type("albers"), ), ) ``` --- --- url: /mosaic/examples/triangle-wave.md --- # Triangle Wave A test specification to compare M4 optimized and unoptimized line charts. ## Specification ```py \[Python] import vgplot as vg wave = vg.csv("data/triangle-wave-day.csv") brush = vg.selection.intersect() view = vg.vconcat( vg.plot( vg.line_y(wave, x="time_stamp", y="power", z=None, stroke="time_stamp"), vg.interval_x(bind=brush), vg.x_label(None), vg.width(680), vg.height(150), ), vg.vspace(5), vg.plot( vg.line_y( data=wave, filter_by=brush, x="time_stamp", y="power", z=None, stroke="time_stamp", ), vg.y_domain("Fixed"), vg.color_domain("Fixed"), vg.x_label(None), vg.width(680), vg.height(150), ), vg.vspace(5), vg.plot( vg.line_y( data=wave, filter_by=brush, optimize=False, x="time_stamp", y="power", z=None, stroke="time_stamp", ), vg.y_domain("Fixed"), vg.color_domain("Fixed"), vg.x_label(None), vg.width(680), vg.height(150), ), ) ``` --- --- url: /mosaic/plot.md --- --- --- url: /mosaic/examples/window-frame.md --- # window-frame ## Specification ```py \[Python] import vgplot as vg aapl = vg.parquet("data/stocks.parquet", where="Symbol = 'AAPL'") view = vg.plot( vg.line_y(aapl, stroke="#ccc", x="Date", y="Close"), vg.line_y( aapl, stroke="black", x="Date", y=vg.avg( "Close", orderby="Date", range=[ {"days": 15}, {"days": 15}, ], ), ), vg.line_y( aapl, stroke="firebrick", x="Date", y=vg.avg( "Close", orderby="Date", range=[ {"months": 3}, {"months": 3}, ], ), ), vg.y_label("Close"), vg.width(680), vg.height(200), ) ```