|
1 | 1 | import type {ChannelValueSpec} from "../channel.js";
|
2 | 2 | import type {Data, MarkOptions, RenderableMark} from "../mark.js";
|
3 | 3 |
|
| 4 | +/** |
| 5 | + * The built-in spatial interpolation methods; one of: |
| 6 | + * |
| 7 | + * - *nearest* - assign each pixel to the closest sample’s value (Voronoi diagram) |
| 8 | + * - *barycentric* - apply barycentric interpolation over the Delaunay triangulation |
| 9 | + * - *random-walk* - apply a random walk from each pixel, stopping when near a sample |
| 10 | + */ |
4 | 11 | export type RasterInterpolateName = "nearest" | "barycentric" | "random-walk";
|
5 | 12 |
|
| 13 | +/** |
| 14 | + * A spatial interpolation implementation function that receives samples’ |
| 15 | + * positions and values and returns a flat array of *width*×*height* values. |
| 16 | + * *x*[*index*[0]] represents the *x*-position of the first sample, |
| 17 | + * *y*[*index*[0]] its *y*-position, and *value*[*index*[0]] its value (*e.g.*, |
| 18 | + * the observed height for a topographic map). |
| 19 | + */ |
6 | 20 | export type RasterInterpolateFunction = (
|
| 21 | + /** An array of numeric indexes into the channels *x*, *y*, *value*. */ |
7 | 22 | index: number[],
|
| 23 | + /** The width of the raster grid in pixels; a positive integer. */ |
8 | 24 | width: number,
|
| 25 | + /** The height of the raster grid in pixels; a positive integer. */ |
9 | 26 | height: number,
|
10 |
| - X: number[], |
11 |
| - Y: number[], |
12 |
| - V: any[] |
| 27 | + /** An array of values representing the *x*-position of samples. */ |
| 28 | + x: number[], |
| 29 | + /** An array of values representing the *y*-position of samples. */ |
| 30 | + y: number[], |
| 31 | + /** An array of values representing the sample’s observed value. */ |
| 32 | + values: any[] |
13 | 33 | ) => any[];
|
14 | 34 |
|
| 35 | +/** |
| 36 | + * A spatial interpolation method; either a named built-in interpolation method, |
| 37 | + * or a custom interpolation function. |
| 38 | + */ |
15 | 39 | export type RasterInterpolate = RasterInterpolateName | RasterInterpolateFunction;
|
16 | 40 |
|
| 41 | +/** |
| 42 | + * A source of pseudo-random numbers in [0, 1). The default source is seeded to |
| 43 | + * ensure reproducibility. |
| 44 | + */ |
17 | 45 | export type RandomSource = () => number;
|
18 | 46 |
|
19 |
| -export type RasterSampler = (x: number, y: number, facet: number[] & {fx: any; fy: any}) => any; |
| 47 | +/** |
| 48 | + * A sampler function, which returns a value for the given *x* and *y* values in |
| 49 | + * the current *facet*. |
| 50 | + */ |
| 51 | +export type RasterSampler = ( |
| 52 | + /** The horizontal position. */ |
| 53 | + x: number, |
| 54 | + /** The vertical position. */ |
| 55 | + y: number, |
| 56 | + /** The current facet index, and corresponding *fx* and *fy* value. */ |
| 57 | + facet: number[] & {fx: any; fy: any} |
| 58 | +) => any; |
20 | 59 |
|
| 60 | +/** Options for the raster mark. */ |
21 | 61 | export interface RasterOptions extends Omit<MarkOptions, "fill" | "fillOpacity"> {
|
| 62 | + /** The horizontal position channel, typically bound to the *x* scale. */ |
22 | 63 | x?: ChannelValueSpec;
|
| 64 | + /** The vertical position channel, typically bound to the *y* scale. */ |
23 | 65 | y?: ChannelValueSpec;
|
| 66 | + |
| 67 | + /** |
| 68 | + * The starting horizontal position (typically the left edge) of the raster |
| 69 | + * domain; the lower bound of the *x* scale. |
| 70 | + * |
| 71 | + * If **width** is specified, defaults to 0; otherwise, if *data* is |
| 72 | + * specified, defaults to the frame’s left coordinate in *x*. If *data* is not |
| 73 | + * specified (as when **value** is a function of *x* and *y*), you must |
| 74 | + * specify **x1** explicitly. |
| 75 | + */ |
24 | 76 | x1?: number;
|
| 77 | + |
| 78 | + /** |
| 79 | + * The ending horizontal position (typically the right edge) of the raster |
| 80 | + * domain; the upper bound of the *x* scale. |
| 81 | + * |
| 82 | + * If **width** is specified, defaults to **width**; otherwise, if *data* is |
| 83 | + * specified, defaults to the frame’s right coordinate in *x*. If *data* is |
| 84 | + * not specified (as when **value** is a function of *x* and *y*), you must |
| 85 | + * specify **x2** explicitly. |
| 86 | + */ |
25 | 87 | x2?: number;
|
| 88 | + |
| 89 | + /** |
| 90 | + * The starting vertical position (typically the bottom edge) of the raster |
| 91 | + * domain; the lower bound of the *y* scale. |
| 92 | + * |
| 93 | + * If **height** is specified, defaults to 0; otherwise, if *data* is |
| 94 | + * specified, defaults to the frame’s top coordinate in *y*. If *data* is not |
| 95 | + * specified (as when **value** is a function of *x* and *y*), you must |
| 96 | + * specify **y1** explicitly. |
| 97 | + */ |
26 | 98 | y1?: number;
|
| 99 | + |
| 100 | + /** |
| 101 | + * The ending vertical position (typically the bottom edge) of the raster |
| 102 | + * domain; the lower bound of the *y* scale. |
| 103 | + * |
| 104 | + * If **height** is specified, defaults to **height**; otherwise, if *data* is |
| 105 | + * specified, defaults to the frame’s bottom coordinate in *y*. If *data* is |
| 106 | + * not specified (as when **value** is a function of *x* and *y*), you must |
| 107 | + * specify **y2** explicitly. |
| 108 | + */ |
27 | 109 | y2?: number;
|
| 110 | + |
| 111 | + /** The width (number of columns) of the raster grid, in actual pixels. */ |
28 | 112 | width?: number;
|
| 113 | + |
| 114 | + /** The height (number of rows) of the raster grid, in actual pixels. */ |
29 | 115 | height?: number;
|
| 116 | + |
| 117 | + /** |
| 118 | + * The effective screen size of a raster pixel, used to determine the height |
| 119 | + * and width of the raster from the frame’s dimensions; defaults to 1. |
| 120 | + */ |
30 | 121 | pixelSize?: number;
|
| 122 | + |
| 123 | + /** |
| 124 | + * A non-negative pixel radius for smoothing; defaults to 0. Note that |
| 125 | + * blurring is applied on the values (before the color scale is applied) if |
| 126 | + * quantitative, and after (on the materialized pixels), if ordinal. |
| 127 | + */ |
31 | 128 | blur?: number;
|
| 129 | + |
| 130 | + /** |
| 131 | + * The spatial interpolation method, when using *data* samples. One of: |
| 132 | + * |
| 133 | + * - *none* (or null, default) - assign each sample to the containing pixel |
| 134 | + * - a named interpolation method, such as *nearest*, *barycentric*, or *random-walk* |
| 135 | + * - a custom interpolation function |
| 136 | + */ |
32 | 137 | interpolate?: RasterInterpolate | "none" | null;
|
| 138 | + |
| 139 | + /** |
| 140 | + * The [image-rendering attribute][1]; defaults to *auto* (bilinear). The |
| 141 | + * option may be set to *pixelated* to disable bilinear interpolation for a |
| 142 | + * sharper image; however, note that this is not supported in WebKit. |
| 143 | + * |
| 144 | + * [1]: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/image-rendering |
| 145 | + */ |
33 | 146 | imageRendering?: string;
|
| 147 | + |
| 148 | + /** |
| 149 | + * The fill, typically bound to the *color* scale. Can be specified as a |
| 150 | + * constant, a channel based on the sample *data*, or as a function *f*(*x*, |
| 151 | + * *y*) to be evaluated at each pixel if the *data* is not provided. |
| 152 | + */ |
34 | 153 | fill?: ChannelValueSpec | RasterSampler;
|
| 154 | + |
| 155 | + /** |
| 156 | + * The opacity, typically bound to the *opacity* scale. Can be specified as a |
| 157 | + * constant, a channel based on the sample *data*, or as a function *f*(*x*, |
| 158 | + * *y*) to be evaluated at each pixel if the *data* is not provided. |
| 159 | + */ |
35 | 160 | fillOpacity?: ChannelValueSpec | RasterSampler;
|
36 | 161 | }
|
37 | 162 |
|
38 |
| -export function raster(options?: RasterOptions): Raster; |
39 |
| - |
| 163 | +/** |
| 164 | + * Returns a raster mark which renders a raster image from spatial samples. If |
| 165 | + * *data* is provided, it represents discrete samples in abstract coordinates |
| 166 | + * **x** and **y**; the **fill** and **fillOpacity** channels specify further |
| 167 | + * abstract values (_e.g._, height in a topographic map) to be spatially |
| 168 | + * interpolated to produce an image. |
| 169 | + * |
| 170 | + * ```js |
| 171 | + * Plot.raster(volcano.values, {width: volcano.width, height: volcano.height}) |
| 172 | + * ``` |
| 173 | + * |
| 174 | + * The **fill** and **fillOpacity** channels may alternatively be specified as |
| 175 | + * functions *f*(*x*, *y*) to be evaluated at each pixel centroid of the raster |
| 176 | + * grid (without interpolation). |
| 177 | + * |
| 178 | + * ```js |
| 179 | + * Plot.raster({x1: -1, x2: 1, y1: -1, y2: 1, fill: (x, y) => Math.atan2(y, x)}) |
| 180 | + * ``` |
| 181 | + * |
| 182 | + * If **width** is specified, **x1** defaults to 0 and **x2** defaults to |
| 183 | + * **width**; likewise, if **height** is specified, **y1** defaults to 0 and |
| 184 | + * **y2** defaults to **height**. Otherwise, if *data* is specified, **x1**, |
| 185 | + * **y1**, **x2**, and **y2** respectively default to the frame’s left, top, |
| 186 | + * right, and bottom coordinates. Lastly, if *data* is not specified (as when |
| 187 | + * **value** is a function of *x* and *y*), you must specify all of **x1**, |
| 188 | + * **x2**, **y1**, and **y2** to define the raster domain. |
| 189 | + */ |
40 | 190 | export function raster(data?: Data, options?: RasterOptions): Raster;
|
| 191 | +export function raster(options?: RasterOptions): Raster; |
41 | 192 |
|
| 193 | +/** |
| 194 | + * Applies a simple forward mapping of samples, binning them into pixels in the |
| 195 | + * raster grid without any blending or interpolation. If multiple samples map to |
| 196 | + * the same pixel, the last one wins; this can introduce bias if the points are |
| 197 | + * not in random order, so use Plot.shuffle to randomize the input if needed. |
| 198 | + */ |
42 | 199 | export const interpolateNone: RasterInterpolateFunction;
|
43 | 200 |
|
| 201 | +/** |
| 202 | + * Constructs a Delaunay triangulation of the samples, and then for each pixel |
| 203 | + * in the raster grid, determines the triangle that covers the pixel’s centroid |
| 204 | + * and interpolates the values associated with the triangle’s vertices using |
| 205 | + * [barycentric coordinates][1]. If the interpolated values are ordinal or |
| 206 | + * categorical (_i.e._, anything other than numbers or dates), then one of the |
| 207 | + * three values will be picked randomly weighted by the barycentric coordinates; |
| 208 | + * the given *random* number generator will be used, which defaults to a [linear |
| 209 | + * congruential generator][2] with a fixed seed (for deterministic results). |
| 210 | + * |
| 211 | + * [1]: https://en.wikipedia.org/wiki/Barycentric_coordinate_system |
| 212 | + * [2]: https://github.com/d3/d3-random/blob/main/README.md#randomLcg |
| 213 | + */ |
44 | 214 | export function interpolatorBarycentric(options?: {random?: RandomSource}): RasterInterpolateFunction;
|
45 | 215 |
|
| 216 | +/** |
| 217 | + * Assigns each pixel in the raster grid the value of the closest sample; |
| 218 | + * effectively a Voronoi diagram. |
| 219 | + */ |
46 | 220 | export const interpolateNearest: RasterInterpolateFunction;
|
47 | 221 |
|
| 222 | +/** |
| 223 | + * For each pixel in the raster grid, initiates a random walk, stopping when |
| 224 | + * either the walk is within a given distance (**minDistance**) of a sample or |
| 225 | + * the maximum allowable number of steps (**maxSteps**) have been taken, and |
| 226 | + * then assigning the current pixel the closest sample’s value. The random walk |
| 227 | + * uses the “walk on spheres” algorithm in two dimensions described by [Sawhney |
| 228 | + * and Crane][1], SIGGRAPH 2020. |
| 229 | + * |
| 230 | + * [1]: https://www.cs.cmu.edu/~kmcrane/Projects/MonteCarloGeometryProcessing/index.html |
| 231 | + */ |
48 | 232 | export function interpolatorRandomWalk(options?: {
|
| 233 | + /** |
| 234 | + * An optional source of pseudo-random numbers in [0, 1). Called at each step |
| 235 | + * of the random walk algorithm with arguments *x*, *y*, and *step*. If not |
| 236 | + * specified, defaults to a seeded random number generator. |
| 237 | + */ |
49 | 238 | random?: RandomSource;
|
| 239 | + |
| 240 | + /** |
| 241 | + * The random walk ends by “snapping” to the closest sample if closer than |
| 242 | + * this distance (in pixels). |
| 243 | + */ |
50 | 244 | minDistance?: number;
|
| 245 | + |
| 246 | + /** |
| 247 | + * After this number of steps, which defaults to 3, lift the **minDistance** |
| 248 | + * requirement and snap to the closest sample. |
| 249 | + */ |
51 | 250 | maxSteps?: number;
|
52 | 251 | }): RasterInterpolateFunction;
|
53 | 252 |
|
| 253 | +/** The raster mark. */ |
54 | 254 | export class Raster extends RenderableMark {}
|
0 commit comments