From ee9bb12fcfb117379861084fc417c5db2a59b777 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Rivi=C3=A8re?= Date: Sat, 25 Mar 2023 17:16:09 +0100 Subject: [PATCH 1/9] a weird space --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5395202b4e..c8a3fcffd7 100644 --- a/README.md +++ b/README.md @@ -2936,7 +2936,7 @@ Constructs a Delaunay triangulation of the samples, and then for each pixel in t #### Plot.interpolatorRandomWalk({*random*, *minDistance* = 0.5, *maxSteps* = 2}) -For each pixel in the raster grid, initiates a random walk, stopping when either the walk is within a given distance (*minDistance*) of a sample or the maximum allowable number of steps (*maxSteps*) have been taken, and then assigning the current pixel the closest sample’s value. The random walk uses the “walk on spheres” algorithm in two dimensions described by [Sawhney and Crane](https://www.cs.cmu.edu/~kmcrane/Projects/MonteCarloGeometryProcessing/index.html), SIGGRAPH 2020. +For each pixel in the raster grid, initiates a random walk, stopping when either the walk is within a given distance (*minDistance*) of a sample or the maximum allowable number of steps (*maxSteps*) have been taken, and then assigning the current pixel the closest sample’s value. The random walk uses the “walk on spheres” algorithm in two dimensions described by [Sawhney and Crane](https://www.cs.cmu.edu/~kmcrane/Projects/MonteCarloGeometryProcessing/index.html), SIGGRAPH 2020. ## Markers From f56194544eef587a0d9437c9f8f8568dc1ef7327 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Rivi=C3=A8re?= Date: Sat, 25 Mar 2023 17:16:19 +0100 Subject: [PATCH 2/9] document raster --- src/marks/raster.d.ts | 172 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 171 insertions(+), 1 deletion(-) diff --git a/src/marks/raster.d.ts b/src/marks/raster.d.ts index 33acb74911..5d063717b8 100644 --- a/src/marks/raster.d.ts +++ b/src/marks/raster.d.ts @@ -1,8 +1,25 @@ import type {ChannelValueSpec} from "../channel.js"; import type {Data, MarkOptions, RenderableMark} from "../mark.js"; +import type {Interval} from "../interval.js"; +/** The built-in spatial interpolation methods. */ export type RasterInterpolateName = "nearest" | "barycentric" | "random-walk"; +/** + * A spatial interpolation implementation. A function that returns a flat array + * of *width* × *height* values, with the following arguments: + * + * - *index* - an array of numeric indexes into the channels *x*, *y*, *value* + * - *width* - the width of the raster grid; a positive integer + * - *height* - the height of the raster grid; a positive integer + * - *x* - an array of values representing the *x*-position of samples + * - *y* - an array of values representing the *y*-position of samples + * - *value* - an array of values representing the sample’s observed value + * + * So, *x*[*index*[0]] represents the *x*-position of the first sample, + * *y*[*index*[0]] its *y*-position, and *value*[*index*[0]] its value (*e.g.*, + * the observed height for a topographic map). + */ export type RasterInterpolateFunction = ( index: number[], width: number, @@ -12,43 +29,196 @@ export type RasterInterpolateFunction = ( V: any[] ) => any[]; +/** A spatial interpolation method. */ export type RasterInterpolate = RasterInterpolateName | RasterInterpolateFunction; +/** + * A source of pseudo-random numbers in [0, 1). The default source is seeded to + * ensure reproducibility. + */ export type RandomSource = () => number; +/** + * A sampler function, which returns a value for the given *x* and *y* values in + * the current *facet*. For example, to create side-by-side color plots of two + * functions of *x* and *y*: + * + * ```js + * Plot.raster({ + * fill: (x, y, {fx}) => fx(x) * y, + * fx: [Math.sin, Math.cos], + * x1: 0, + * y1: 0, + * x2: 4 * Math.PI, + * y2: 2, + * interval: 0.2 + * }); + * ``` + */ export type RasterSampler = (x: number, y: number, facet: number[] & {fx: any; fy: any}) => any; +/** Options for the raster mark. */ export interface RasterOptions extends Omit { + /** The horizontal coordinate of a sample. */ x?: ChannelValueSpec; + /** The vertical coordinate of a sample. */ y?: ChannelValueSpec; + /** + * The lower value of *x*, on the left edge of the raster (right edge if + * reversed). + */ x1?: number; + /** + * The higher value of *x*, on the right edge of the raster (left edge if + * reversed). + */ x2?: number; + /** + * The lower value of *y*, on the top edge of the raster (bottom edge if + * reversed). + */ y1?: number; + /** + * The higher value of *y*, on the bottom edge of the raster (top edge if + * reversed). + */ y2?: number; + /** + * The width of the raster grid, in actual columns of pixels. The grid might + * be scaled to the frame’s dimensions. + */ width?: number; + /** + * The height of the raster grid, in actual rows of pixels. The grid might be + * scaled to the frame’s dimensions. + */ height?: number; + /** + * The screen size of a raster pixel, used to determine the height and width + * of the raster from the frame’s dimensions; defaults to 1 + */ pixelSize?: number; + /** + * The sampling interval, used to determine the height and width of the raster + * from the frame’s dimensions and the *x* and *y* extents. + */ + interval?: Interval; + /** + * A non-negative pixel radius for smoothing; defaults to 0. Note that + * blurring is applied on the values (before the color scale is applied) if + * quantitative, and after (on the materialized pixels), if ordinal. + */ blur?: number; + /** + * The spatial interpolation method, when using *data* samples. One of: + * + * - *none* (or null) - assign each sample to the containing pixel + * - *nearest* - assign each pixel to the closest sample’s value (Voronoi + * diagram) + * - *barycentric* - apply barycentric interpolation over the Delaunay + * triangulation + * - *random-walk* - apply a random walk from each pixel, stopping when near a + * sample + * - a function - custom interpolation + */ interpolate?: RasterInterpolate | "none" | null; + /** + * The [image-rendering + * attribute](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/image-rendering); + * defaults to *auto* (bilinear). The option may be set to *pixelated* to + * disable bilinear interpolation for a sharper image; however, note that this + * is not supported in WebKit + */ imageRendering?: string; + /** + * The fill, typically bound to the *color* scale. Can be specified as a + * constant, a channel based on the sample *data*, or as a function *f*(*x*, + * *y*) to be evaluated at each pixel if the *data* is not provided. + */ fill?: ChannelValueSpec | RasterSampler; + /** + * The opacity, typically bound to the *opacity* scale. Can be specified as a + * constant, a channel based on the sample *data*, or as a function *f*(*x*, + * *y*) to be evaluated at each pixel if the *data* is not provided. + */ fillOpacity?: ChannelValueSpec | RasterSampler; } +/** + * Returns a raster mark, which renders a raster image from spatial samples. If + * data is provided, it represents discrete samples in abstract coordinates *x* + * and *y*; the **fill** and **fillOpacity** channels specify further abstract + * values (_e.g._, height in a topographic map) to be spatially interpolated to + * produce an image. + * + * ```js + * Plot.raster(volcano.values, {width: volcano.width, height: volcano.height}) + * ``` + * + * The **fill** and **fillOpacity** channels may alternatively be specified as + * functions *f*(*x*, *y*) to be evaluated at each pixel centroid of the raster + * grid (without interpolation). + * + * The resolution of the rectangular raster image may be specified with the following options: + * + * * **width** - the number of pixels on each horizontal line + * * **height** - the number of lines; a positive integer + * + * The raster dimensions may also be imputed from the extent of *x* and *y* and a pixel size: + * + * * **x1** - the starting horizontal position; bound to the *x* scale + * * **x2** - the ending horizontal position; bound to the *x* scale + * * **y1** - the starting vertical position; bound to the *y* scale + * * **y2** - the ending vertical position; bound to the *y* scale + * * **pixelSize** - the screen size of a raster pixel; defaults to 1 + */ export function raster(options?: RasterOptions): Raster; - export function raster(data?: Data, options?: RasterOptions): Raster; +/** + * Applies a simple forward mapping of samples, binning them into pixels in the + * raster grid without any blending or interpolation. If multiple samples map to + * the same pixel, the last one wins; this can introduce bias if the points are + * not in random order, so use Plot.**shuffle** to randomize the input if + * needed. + */ export const interpolateNone: RasterInterpolateFunction; +/** + * Constructs a Delaunay triangulation of the samples, and then for each pixel + * in the raster grid, determines the triangle that covers the pixel’s centroid + * and interpolates the values associated with the triangle’s vertices using + * [barycentric + * coordinates](https://en.wikipedia.org/wiki/Barycentric_coordinate_system). If + * the interpolated values are ordinal or categorical (_i.e._, anything other + * than numbers or dates), then one of the three values will be picked randomly + * weighted by the barycentric coordinates; the given *random* number generator + * will be used, which defaults to a [linear congruential + * generator](https://github.com/d3/d3-random/blob/main/README.md#randomLcg) + * with a fixed seed (for deterministic results). + */ export function interpolatorBarycentric(options?: {random?: RandomSource}): RasterInterpolateFunction; +/** + * Assigns each pixel in the raster grid the value of the closest sample; + * effectively a Voronoi diagram. + */ export const interpolateNearest: RasterInterpolateFunction; +/** + * For each pixel in the raster grid, initiates a random walk, stopping when + * either the walk is within a given distance (*minDistance*) of a sample or the + * maximum allowable number of steps (*maxSteps*) have been taken, and then + * assigning the current pixel the closest sample’s value. The random walk uses + * the “walk on spheres” algorithm in two dimensions described by [Sawhney and + * Crane](https://www.cs.cmu.edu/~kmcrane/Projects/MonteCarloGeometryProcessing/index.html), + * SIGGRAPH 2020. + */ export function interpolatorRandomWalk(options?: { random?: RandomSource; minDistance?: number; maxSteps?: number; }): RasterInterpolateFunction; +/** The raster mark. */ export class Raster extends RenderableMark {} From b18f11aaf99f8a40a893ce64625831983573ab69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Rivi=C3=A8re?= Date: Sat, 25 Mar 2023 17:56:54 +0100 Subject: [PATCH 3/9] document contour --- src/marks/contour.d.ts | 98 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 2 deletions(-) diff --git a/src/marks/contour.d.ts b/src/marks/contour.d.ts index 183fe42e9b..541d30d1af 100644 --- a/src/marks/contour.d.ts +++ b/src/marks/contour.d.ts @@ -4,15 +4,109 @@ import type {Data, RenderableMark} from "../mark.js"; import type {Thresholds} from "../transforms/bin.js"; import type {RasterOptions, RasterSampler} from "./raster.js"; -export interface ContourOptions extends Omit { +/** Options for the contour mark. */ +export interface ContourOptions extends Omit { + /** + * Whether to apply linear interpolation after marching squares when computing + * contour polygons (defaults to true). For smoother contours, see the + * **blur** option. + */ smooth?: boolean; + /** + * The value can be specified as a channel based on the sample *data*, or as a + * function *f*(*x*, *y*) to be evaluated at each pixel if the *data* is not + * provided. + */ value?: ChannelValue | RasterSampler; + /** + * How to subdivide the domain into discrete level sets; defaults to *auto*; + * one of: + * + * - a named threshold implementation such as *auto* (default) or *sturges* + * - a function that returns an array, count, or range interval + * - a range interval + * - an array of *n* threshold values for *n* - 1 bins + * - a count representing the desired number of bins (a hint; not guaranteed) + * + * For example, for about ten contours: + * + * ```js + * Plot.contour({fill: (x, y) => Math.sin(x) * Math.cos(y), thresholds: 10, x1: 0, x2: 1, y1: 0, y2: 1}) + * ``` + * + * See also the **interval** option. + */ thresholds?: Thresholds; + /** + * An alternative way of specifying the contour thresholds. For example to + * create an isoline every 15 meters on a topographic map: + * + * ```js + * Plot.contour(volcano.values, {interval: 15, width: volcano.width, height: volcano.height, value: Plot.identity}) + * ``` + */ interval?: RangeInterval; } +/** + * Return a contour mark, which creates contour polygons from spatial samples. + * If *data* is provided, it represents discrete samples in abstract coordinates + * *x* and *y*; the *value* channel specifies further abstract values (_e.g._, + * height in a topographic map) to be spatially interpolated to produce a raster + * grid of quantitative values (like in the **raster** mark), and lastly + * contours via marching squares, which are rendered as vector polygons. + * + * For example, to generate filled contours from a topographic map, where the + * color corresponds to the contour threshold value: + * + * ```js + * Plot.contour(volcano.values, {width: volcano.width, height: volcano.height, value: Plot.identity, fill: "value"}) + * ``` + * + * For smoother contours, the **blur** option (default 0) specifies a + * non-negative pixel radius for smoothing prior to applying marching squares. + * The **smooth** option (default true) specifies whether to apply linear + * interpolation after marching squares when computing contour polygons. The + * **thresholds** and **interval** options specify the contour thresholds; see + * the **bin** transform for details. + * + * With the exception of the *x*, *y*, *x1*, *y1*, *x2*, *y2*, and *value* + * channels, the contour mark’s channels are not evaluated on the initial *data* + * but rather on the contour multipolygons generated in the initializer, as in + * the example above. + * + * The **fill** and **fillOpacity** channels may alternatively be specified as + * functions *f*(*x*, *y*) to be evaluated at each pixel centroid of the + * underlying raster grid (without interpolation). For example, to draw a + * contour plot of a two-dimensional function: + * + * ```js + * Plot.contour({ + * fill: (x, y) => Math.sin(x) * Math.cos(y), + * x1: 0, + * y1: 0, + * x2: 4 * Math.PI, + * y2: 4 * Math.PI + * }) + * ``` + * + * The resolution of the underlying raster grid may be specified with the + * following options: + * + * * **width** - the number of pixels on each horizontal line + * * **height** - the number of lines; a positive integer + * + * The raster dimensions may also be imputed from the extent of *x* and *y* and + * a pixel size: + * + * * **x1** - the starting horizontal position; bound to the *x* scale + * * **x2** - the ending horizontal position; bound to the *x* scale + * * **y1** - the starting vertical position; bound to the *y* scale + * * **y2** - the ending vertical position; bound to the *y* scale + * * **pixelSize** - the screen size of a raster pixel; defaults to 1 + */ export function contour(options?: ContourOptions): Contour; - export function contour(data?: Data, options?: ContourOptions): Contour; +/** The contour mark. */ export class Contour extends RenderableMark {} From 42136e30eccfd827cfb51988c215e95566fd9269 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Rivi=C3=A8re?= Date: Sun, 26 Mar 2023 17:30:42 +0200 Subject: [PATCH 4/9] cleaner --- src/marks/raster.d.ts | 53 +++++++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/src/marks/raster.d.ts b/src/marks/raster.d.ts index 5d063717b8..840e00da89 100644 --- a/src/marks/raster.d.ts +++ b/src/marks/raster.d.ts @@ -6,27 +6,31 @@ import type {Interval} from "../interval.js"; export type RasterInterpolateName = "nearest" | "barycentric" | "random-walk"; /** - * A spatial interpolation implementation. A function that returns a flat array - * of *width* × *height* values, with the following arguments: - * - * - *index* - an array of numeric indexes into the channels *x*, *y*, *value* - * - *width* - the width of the raster grid; a positive integer - * - *height* - the height of the raster grid; a positive integer - * - *x* - an array of values representing the *x*-position of samples - * - *y* - an array of values representing the *y*-position of samples - * - *value* - an array of values representing the sample’s observed value + * A spatial interpolation implementation. A function that receives samples’ + * positions and values and returns a flat array of *width* × *height* values. * * So, *x*[*index*[0]] represents the *x*-position of the first sample, * *y*[*index*[0]] its *y*-position, and *value*[*index*[0]] its value (*e.g.*, * the observed height for a topographic map). */ export type RasterInterpolateFunction = ( + /** An array of numeric indexes into the channels *x*, *y*, *value*. */ index: number[], + + /** The width of the raster grid; a positive integer. */ width: number, + + /** The height of the raster grid; a positive integer. */ height: number, - X: number[], - Y: number[], - V: any[] + + /** An array of values representing the *x*-position of samples. */ + x: number[], + + /** An array of values representing the *y*-position of samples. */ + y: number[], + + /** An array of values representing the sample’s observed value. */ + values: any[] ) => any[]; /** A spatial interpolation method. */ @@ -61,54 +65,65 @@ export type RasterSampler = (x: number, y: number, facet: number[] & {fx: any; f export interface RasterOptions extends Omit { /** The horizontal coordinate of a sample. */ x?: ChannelValueSpec; + /** The vertical coordinate of a sample. */ y?: ChannelValueSpec; + /** * The lower value of *x*, on the left edge of the raster (right edge if * reversed). */ x1?: number; + /** * The higher value of *x*, on the right edge of the raster (left edge if * reversed). */ x2?: number; + /** * The lower value of *y*, on the top edge of the raster (bottom edge if * reversed). */ y1?: number; + /** * The higher value of *y*, on the bottom edge of the raster (top edge if * reversed). */ y2?: number; + /** * The width of the raster grid, in actual columns of pixels. The grid might * be scaled to the frame’s dimensions. */ width?: number; + /** * The height of the raster grid, in actual rows of pixels. The grid might be * scaled to the frame’s dimensions. */ height?: number; + /** * The screen size of a raster pixel, used to determine the height and width * of the raster from the frame’s dimensions; defaults to 1 */ pixelSize?: number; + /** * The sampling interval, used to determine the height and width of the raster * from the frame’s dimensions and the *x* and *y* extents. */ interval?: Interval; + /** * A non-negative pixel radius for smoothing; defaults to 0. Note that * blurring is applied on the values (before the color scale is applied) if * quantitative, and after (on the materialized pixels), if ordinal. */ blur?: number; + /** * The spatial interpolation method, when using *data* samples. One of: * @@ -122,20 +137,24 @@ export interface RasterOptions extends Omit * - a function - custom interpolation */ interpolate?: RasterInterpolate | "none" | null; + /** - * The [image-rendering - * attribute](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/image-rendering); - * defaults to *auto* (bilinear). The option may be set to *pixelated* to - * disable bilinear interpolation for a sharper image; however, note that this - * is not supported in WebKit + * The [image-rendering attribute][1]; defaults to *auto* (bilinear). The + * option may be set to *pixelated* to disable bilinear interpolation for a + * sharper image; however, note that this is not supported in WebKit. + * + * [1]: + * https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/image-rendering */ imageRendering?: string; + /** * The fill, typically bound to the *color* scale. Can be specified as a * constant, a channel based on the sample *data*, or as a function *f*(*x*, * *y*) to be evaluated at each pixel if the *data* is not provided. */ fill?: ChannelValueSpec | RasterSampler; + /** * The opacity, typically bound to the *opacity* scale. Can be specified as a * constant, a channel based on the sample *data*, or as a function *f*(*x*, From 2b9a076e0ddc941ba0c9e937b084f966d27e8994 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Rivi=C3=A8re?= Date: Wed, 29 Mar 2023 17:57:09 +0200 Subject: [PATCH 5/9] better contour, raster --- src/marks/contour.d.ts | 20 +++++++------------- src/marks/raster.d.ts | 31 +++++++++++++++++++------------ 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/src/marks/contour.d.ts b/src/marks/contour.d.ts index 541d30d1af..36b955ad5e 100644 --- a/src/marks/contour.d.ts +++ b/src/marks/contour.d.ts @@ -12,12 +12,14 @@ export interface ContourOptions extends Omit /** * The spatial interpolation method, when using *data* samples. One of: * - * - *none* (or null) - assign each sample to the containing pixel + * - *none* (or null, default) - assign each sample to the containing pixel * - *nearest* - assign each pixel to the closest sample’s value (Voronoi * diagram) * - *barycentric* - apply barycentric interpolation over the Delaunay @@ -178,18 +178,11 @@ export interface RasterOptions extends Omit * functions *f*(*x*, *y*) to be evaluated at each pixel centroid of the raster * grid (without interpolation). * - * The resolution of the rectangular raster image may be specified with the following options: + * The resolution of the rectangular raster image may be specified with + * **width** and **height**. * - * * **width** - the number of pixels on each horizontal line - * * **height** - the number of lines; a positive integer - * - * The raster dimensions may also be imputed from the extent of *x* and *y* and a pixel size: - * - * * **x1** - the starting horizontal position; bound to the *x* scale - * * **x2** - the ending horizontal position; bound to the *x* scale - * * **y1** - the starting vertical position; bound to the *y* scale - * * **y2** - the ending vertical position; bound to the *y* scale - * * **pixelSize** - the screen size of a raster pixel; defaults to 1 + * The raster dimensions may alternatively be imputed from a rectangular extent + * *x1*, *y1*, *x2*, *y2* and a **pixelSize**. */ export function raster(options?: RasterOptions): Raster; export function raster(data?: Data, options?: RasterOptions): Raster; @@ -234,8 +227,22 @@ export const interpolateNearest: RasterInterpolateFunction; * SIGGRAPH 2020. */ export function interpolatorRandomWalk(options?: { + /** + * A source of pseudo-random numbers in [0, 1). Called at each step of the + * random walk algorithm with arguments *x*, *y*, and *step*. + */ random?: RandomSource; + + /** + * The random walk ends by “snapping” to the closest sample if closer than + * this distance (in pixels). + */ minDistance?: number; + + /** + * After this number of steps, which defaults to 3, lift the minDistance + * requirement and snap to the closest sample. + */ maxSteps?: number; }): RasterInterpolateFunction; From 24cb0e63e32763f0323856eb94d97ccfaee2854e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Rivi=C3=A8re?= Date: Wed, 29 Mar 2023 18:13:38 +0200 Subject: [PATCH 6/9] defaults for x1, x2, y1, y2 (I think) --- src/marks/raster.d.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/marks/raster.d.ts b/src/marks/raster.d.ts index 76afd20f75..c0245b4589 100644 --- a/src/marks/raster.d.ts +++ b/src/marks/raster.d.ts @@ -71,25 +71,33 @@ export interface RasterOptions extends Omit /** * The lower value of *x*, on the left edge of the raster (right edge if - * reversed). + * reversed). Defaults to the minimum of the **x** channel, if given, + * otherwise to 0, enabling to set up the raster coordinate system with a + * **width**. */ x1?: number; /** * The higher value of *x*, on the right edge of the raster (left edge if - * reversed). + * reversed). Defaults to the maximum of the **x** channel, if given, + * otherwise to **width**, enabling to set up the raster coordinate system + * with a **width**. */ x2?: number; /** * The lower value of *y*, on the top edge of the raster (bottom edge if - * reversed). + * reversed). Defaults to the minimum of the **y** channel, if given, + * otherwise to 0, enabling to set up the raster coordinate system with a + * **height**. */ y1?: number; /** * The higher value of *y*, on the bottom edge of the raster (top edge if - * reversed). + * reversed). Defaults to the maximum of the **y** channel, if given, + * otherwise to **height**, enabling to set up the raster coordinate system with a + * **height**. */ y2?: number; From 58af8612b8fd1cb4acd767567512099c760a6c83 Mon Sep 17 00:00:00 2001 From: Mike Bostock Date: Thu, 30 Mar 2023 20:17:06 -0700 Subject: [PATCH 7/9] edits --- src/marks/raster.d.ts | 121 ++++++++++++++++++++++-------------------- 1 file changed, 64 insertions(+), 57 deletions(-) diff --git a/src/marks/raster.d.ts b/src/marks/raster.d.ts index c0245b4589..80bd8a549d 100644 --- a/src/marks/raster.d.ts +++ b/src/marks/raster.d.ts @@ -1,8 +1,13 @@ import type {ChannelValueSpec} from "../channel.js"; import type {Data, MarkOptions, RenderableMark} from "../mark.js"; -import type {Interval} from "../interval.js"; -/** The built-in spatial interpolation methods. */ +/** + * The built-in spatial interpolation methods; one of: + * + * - *nearest* - assign each pixel to the closest sample’s value (Voronoi diagram) + * - *barycentric* - apply barycentric interpolation over the Delaunay triangulation + * - *random-walk* - apply a random walk from each pixel, stopping when near a sample + */ export type RasterInterpolateName = "nearest" | "barycentric" | "random-walk"; /** @@ -33,7 +38,10 @@ export type RasterInterpolateFunction = ( values: any[] ) => any[]; -/** A spatial interpolation method. */ +/** + * A spatial interpolation method; either a named built-in interpolation method, + * or a custom interpolation function. + */ export type RasterInterpolate = RasterInterpolateName | RasterInterpolateFunction; /** @@ -63,68 +71,67 @@ export type RasterSampler = (x: number, y: number, facet: number[] & {fx: any; f /** Options for the raster mark. */ export interface RasterOptions extends Omit { - /** The horizontal coordinate of a sample. */ + /** The horizontal position channel, typically bound to the *x* scale. */ x?: ChannelValueSpec; - - /** The vertical coordinate of a sample. */ + /** The vertical position channel, typically bound to the *y* scale. */ y?: ChannelValueSpec; /** - * The lower value of *x*, on the left edge of the raster (right edge if - * reversed). Defaults to the minimum of the **x** channel, if given, - * otherwise to 0, enabling to set up the raster coordinate system with a - * **width**. + * The starting horizontal position (typically the left edge) of the raster + * domain; the lower bound of the *x* scale. + * + * If **width** is specified, defaults to 0; otherwise, if *data* is + * specified, defaults to the frame’s left coordinate in *x*. If *data* is not + * specified (as when **value** is a function of *x* and *y*), you must + * specify **x1** explicitly. */ x1?: number; /** - * The higher value of *x*, on the right edge of the raster (left edge if - * reversed). Defaults to the maximum of the **x** channel, if given, - * otherwise to **width**, enabling to set up the raster coordinate system - * with a **width**. + * The ending horizontal position (typically the right edge) of the raster + * domain; the upper bound of the *x* scale. + * + * If **width** is specified, defaults to **width**; otherwise, if *data* is + * specified, defaults to the frame’s right coordinate in *x*. If *data* is + * not specified (as when **value** is a function of *x* and *y*), you must + * specify **x2** explicitly. */ x2?: number; /** - * The lower value of *y*, on the top edge of the raster (bottom edge if - * reversed). Defaults to the minimum of the **y** channel, if given, - * otherwise to 0, enabling to set up the raster coordinate system with a - * **height**. + * The starting vertical position (typically the bottom edge) of the raster + * domain; the lower bound of the *y* scale. + * + * If **height** is specified, defaults to 0; otherwise, if *data* is + * specified, defaults to the frame’s top coordinate in *y*. If *data* is not + * specified (as when **value** is a function of *x* and *y*), you must + * specify **y1** explicitly. */ y1?: number; /** - * The higher value of *y*, on the bottom edge of the raster (top edge if - * reversed). Defaults to the maximum of the **y** channel, if given, - * otherwise to **height**, enabling to set up the raster coordinate system with a - * **height**. + * The ending vertical position (typically the bottom edge) of the raster + * domain; the lower bound of the *y* scale. + * + * If **height** is specified, defaults to **height**; otherwise, if *data* is + * specified, defaults to the frame’s bottom coordinate in *y*. If *data* is + * not specified (as when **value** is a function of *x* and *y*), you must + * specify **y2** explicitly. */ y2?: number; - /** - * The width of the raster grid, in actual columns of pixels. The grid might - * be scaled to the frame’s dimensions. - */ + /** The width (number of columns) of the raster grid, in actual pixels. */ width?: number; - /** - * The height of the raster grid, in actual rows of pixels. The grid might be - * scaled to the frame’s dimensions. - */ + /** The height (number of rows) of the raster grid, in actual pixels. */ height?: number; /** - * The screen size of a raster pixel, used to determine the height and width - * of the raster from the frame’s dimensions; defaults to 1 + * The effective screen size of a raster pixel, used to determine the height + * and width of the raster from the frame’s dimensions; defaults to 1. */ pixelSize?: number; - /** - * The sampling interval, used to determine the height and width of the raster - * from the frame’s dimensions and the *x* and *y* extents. - */ - interval?: Interval; - /** * A non-negative pixel radius for smoothing; defaults to 0. Note that * blurring is applied on the values (before the color scale is applied) if @@ -136,13 +143,8 @@ export interface RasterOptions extends Omit * The spatial interpolation method, when using *data* samples. One of: * * - *none* (or null, default) - assign each sample to the containing pixel - * - *nearest* - assign each pixel to the closest sample’s value (Voronoi - * diagram) - * - *barycentric* - apply barycentric interpolation over the Delaunay - * triangulation - * - *random-walk* - apply a random walk from each pixel, stopping when near a - * sample - * - a function - custom interpolation + * - a named interpolation method, such as *nearest*, *barycentric*, or *random-walk* + * - a custom interpolation function */ interpolate?: RasterInterpolate | "none" | null; @@ -151,8 +153,7 @@ export interface RasterOptions extends Omit * option may be set to *pixelated* to disable bilinear interpolation for a * sharper image; however, note that this is not supported in WebKit. * - * [1]: - * https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/image-rendering + * [1]: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/image-rendering */ imageRendering?: string; @@ -172,11 +173,11 @@ export interface RasterOptions extends Omit } /** - * Returns a raster mark, which renders a raster image from spatial samples. If - * data is provided, it represents discrete samples in abstract coordinates *x* - * and *y*; the **fill** and **fillOpacity** channels specify further abstract - * values (_e.g._, height in a topographic map) to be spatially interpolated to - * produce an image. + * Returns a raster mark which renders a raster image from spatial samples. If + * *data* is provided, it represents discrete samples in abstract coordinates + * **x** and **y**; the **fill** and **fillOpacity** channels specify further + * abstract values (_e.g._, height in a topographic map) to be spatially + * interpolated to produce an image. * * ```js * Plot.raster(volcano.values, {width: volcano.width, height: volcano.height}) @@ -186,14 +187,20 @@ export interface RasterOptions extends Omit * functions *f*(*x*, *y*) to be evaluated at each pixel centroid of the raster * grid (without interpolation). * - * The resolution of the rectangular raster image may be specified with - * **width** and **height**. + * ```js + * Plot.raster({x1: -1, x2: 1, y1: -1, y2: 1, fill: (x, y) => Math.atan2(y, x)}) + * ``` * - * The raster dimensions may alternatively be imputed from a rectangular extent - * *x1*, *y1*, *x2*, *y2* and a **pixelSize**. + * If **width** is specified, **x1** defaults to 0 and **x2** defaults to + * **width**; likewise, if **height** is specified, **y1** defaults to 0 and + * **y2** defaults to **height**. Otherwise, if *data* is specified, **x1**, + * **y1**, **x2**, and **y2** respectively default to the frame’s left, top, + * right, and bottom coordinates. Lastly, if *data* is not specified (as when + * **value** is a function of *x* and *y*), you must specify all of **x1**, + * **x2**, **y1**, and **y2** to define the raster domain. */ -export function raster(options?: RasterOptions): Raster; export function raster(data?: Data, options?: RasterOptions): Raster; +export function raster(options?: RasterOptions): Raster; /** * Applies a simple forward mapping of samples, binning them into pixels in the From 8671e99392efc02f5ba270e35c277999bda3e916 Mon Sep 17 00:00:00 2001 From: Mike Bostock Date: Thu, 30 Mar 2023 22:52:56 -0700 Subject: [PATCH 8/9] edits --- src/marks/contour.d.ts | 4 +-- src/marks/raster.d.ts | 79 ++++++++++++++++++------------------------ 2 files changed, 36 insertions(+), 47 deletions(-) diff --git a/src/marks/contour.d.ts b/src/marks/contour.d.ts index 36b955ad5e..b5308b490f 100644 --- a/src/marks/contour.d.ts +++ b/src/marks/contour.d.ts @@ -8,8 +8,8 @@ import type {RasterOptions, RasterSampler} from "./raster.js"; export interface ContourOptions extends Omit { /** * Whether to apply linear interpolation after marching squares when computing - * contour polygons (defaults to true). For smoother contours, see the - * **blur** option. + * contour polygons; defaults to true. For smoother contours, see the **blur** + * option. */ smooth?: boolean; diff --git a/src/marks/raster.d.ts b/src/marks/raster.d.ts index 80bd8a549d..fdf6fe9d0f 100644 --- a/src/marks/raster.d.ts +++ b/src/marks/raster.d.ts @@ -11,29 +11,23 @@ import type {Data, MarkOptions, RenderableMark} from "../mark.js"; export type RasterInterpolateName = "nearest" | "barycentric" | "random-walk"; /** - * A spatial interpolation implementation. A function that receives samples’ - * positions and values and returns a flat array of *width* × *height* values. - * - * So, *x*[*index*[0]] represents the *x*-position of the first sample, + * A spatial interpolation implementation function that receives samples’ + * positions and values and returns a flat array of *width*×*height* values. + * *x*[*index*[0]] represents the *x*-position of the first sample, * *y*[*index*[0]] its *y*-position, and *value*[*index*[0]] its value (*e.g.*, * the observed height for a topographic map). */ export type RasterInterpolateFunction = ( /** An array of numeric indexes into the channels *x*, *y*, *value*. */ index: number[], - - /** The width of the raster grid; a positive integer. */ + /** The width of the raster grid in pixels; a positive integer. */ width: number, - - /** The height of the raster grid; a positive integer. */ + /** The height of the raster grid in pixels; a positive integer. */ height: number, - /** An array of values representing the *x*-position of samples. */ x: number[], - /** An array of values representing the *y*-position of samples. */ y: number[], - /** An array of values representing the sample’s observed value. */ values: any[] ) => any[]; @@ -52,22 +46,16 @@ export type RandomSource = () => number; /** * A sampler function, which returns a value for the given *x* and *y* values in - * the current *facet*. For example, to create side-by-side color plots of two - * functions of *x* and *y*: - * - * ```js - * Plot.raster({ - * fill: (x, y, {fx}) => fx(x) * y, - * fx: [Math.sin, Math.cos], - * x1: 0, - * y1: 0, - * x2: 4 * Math.PI, - * y2: 2, - * interval: 0.2 - * }); - * ``` + * the current *facet*. */ -export type RasterSampler = (x: number, y: number, facet: number[] & {fx: any; fy: any}) => any; +export type RasterSampler = ( + /** The horizontal position. */ + x: number, + /** The vertical position. */ + y: number, + /** The current facet index, and corresponding *fx* and *fy* value. */ + facet: number[] & {fx: any; fy: any} +) => any; /** Options for the raster mark. */ export interface RasterOptions extends Omit { @@ -206,8 +194,7 @@ export function raster(options?: RasterOptions): Raster; * Applies a simple forward mapping of samples, binning them into pixels in the * raster grid without any blending or interpolation. If multiple samples map to * the same pixel, the last one wins; this can introduce bias if the points are - * not in random order, so use Plot.**shuffle** to randomize the input if - * needed. + * not in random order, so use Plot.shuffle to randomize the input if needed. */ export const interpolateNone: RasterInterpolateFunction; @@ -215,14 +202,14 @@ export const interpolateNone: RasterInterpolateFunction; * Constructs a Delaunay triangulation of the samples, and then for each pixel * in the raster grid, determines the triangle that covers the pixel’s centroid * and interpolates the values associated with the triangle’s vertices using - * [barycentric - * coordinates](https://en.wikipedia.org/wiki/Barycentric_coordinate_system). If - * the interpolated values are ordinal or categorical (_i.e._, anything other - * than numbers or dates), then one of the three values will be picked randomly - * weighted by the barycentric coordinates; the given *random* number generator - * will be used, which defaults to a [linear congruential - * generator](https://github.com/d3/d3-random/blob/main/README.md#randomLcg) - * with a fixed seed (for deterministic results). + * [barycentric coordinates][1]. If the interpolated values are ordinal or + * categorical (_i.e._, anything other than numbers or dates), then one of the + * three values will be picked randomly weighted by the barycentric coordinates; + * the given *random* number generator will be used, which defaults to a [linear + * congruential generator][2] with a fixed seed (for deterministic results). + * + * [1]: https://en.wikipedia.org/wiki/Barycentric_coordinate_system + * [2]: https://github.com/d3/d3-random/blob/main/README.md#randomLcg */ export function interpolatorBarycentric(options?: {random?: RandomSource}): RasterInterpolateFunction; @@ -234,17 +221,19 @@ export const interpolateNearest: RasterInterpolateFunction; /** * For each pixel in the raster grid, initiates a random walk, stopping when - * either the walk is within a given distance (*minDistance*) of a sample or the - * maximum allowable number of steps (*maxSteps*) have been taken, and then - * assigning the current pixel the closest sample’s value. The random walk uses - * the “walk on spheres” algorithm in two dimensions described by [Sawhney and - * Crane](https://www.cs.cmu.edu/~kmcrane/Projects/MonteCarloGeometryProcessing/index.html), - * SIGGRAPH 2020. + * either the walk is within a given distance (**minDistance**) of a sample or + * the maximum allowable number of steps (**maxSteps**) have been taken, and + * then assigning the current pixel the closest sample’s value. The random walk + * uses the “walk on spheres” algorithm in two dimensions described by [Sawhney + * and Crane][1], SIGGRAPH 2020. + * + * [1]: https://www.cs.cmu.edu/~kmcrane/Projects/MonteCarloGeometryProcessing/index.html */ export function interpolatorRandomWalk(options?: { /** - * A source of pseudo-random numbers in [0, 1). Called at each step of the - * random walk algorithm with arguments *x*, *y*, and *step*. + * An optional source of pseudo-random numbers in [0, 1). Called at each step + * of the random walk algorithm with arguments *x*, *y*, and *step*. If not + * specified, defaults to a seeded random number generator. */ random?: RandomSource; @@ -255,7 +244,7 @@ export function interpolatorRandomWalk(options?: { minDistance?: number; /** - * After this number of steps, which defaults to 3, lift the minDistance + * After this number of steps, which defaults to 3, lift the **minDistance** * requirement and snap to the closest sample. */ maxSteps?: number; From 9c81f95f1973a9bdbc7c6ec3f1ab648d3aa9b266 Mon Sep 17 00:00:00 2001 From: Mike Bostock Date: Thu, 30 Mar 2023 23:05:50 -0700 Subject: [PATCH 9/9] edits --- src/marks/contour.d.ts | 58 ++++++++++++++++------------------------- src/transforms/bin.d.ts | 2 ++ 2 files changed, 24 insertions(+), 36 deletions(-) diff --git a/src/marks/contour.d.ts b/src/marks/contour.d.ts index b5308b490f..2b06111d24 100644 --- a/src/marks/contour.d.ts +++ b/src/marks/contour.d.ts @@ -41,66 +41,52 @@ export interface ContourOptions extends Omit Math.sin(x) * Math.cos(y), - * x1: 0, - * y1: 0, - * x2: 4 * Math.PI, - * y2: 4 * Math.PI - * }) + * Plot.contour({x1: -1, x2: 1, y1: -1, y2: 1, fill: (x, y) => Math.atan2(y, x)}) * ``` * - * The resolution of the rectangular raster image may be specified with - * **width** and **height**. - * - * The raster dimensions may alternatively be imputed from a rectangular extent - * *x1*, *y1*, *x2*, *y2* and a **pixelSize**. + * With the exception of the **x**, **y**, and **value** channels, the contour + * mark’s channels are not evaluated on the initial *data* but rather on the + * generated contour multipolygons. */ -export function contour(options?: ContourOptions): Contour; export function contour(data?: Data, options?: ContourOptions): Contour; +export function contour(options?: ContourOptions): Contour; /** The contour mark. */ export class Contour extends RenderableMark {} diff --git a/src/transforms/bin.d.ts b/src/transforms/bin.d.ts index eca387479d..2a4a182dcf 100644 --- a/src/transforms/bin.d.ts +++ b/src/transforms/bin.d.ts @@ -81,6 +81,8 @@ export interface BinOptions { * ```js * Plot.rectY(numbers, Plot.binX({y: "count"}, {thresholds: 10})) * ``` + * + * See also the **interval** option. */ thresholds?: Thresholds;