From 21f268d46f72e77992f9f7b1f5d4ce9a63fb0e39 Mon Sep 17 00:00:00 2001 From: geokrety-bot Date: Sat, 5 Aug 2023 11:52:56 +0200 Subject: [PATCH] feat: Add select2 and d3 js libraries --- content/libraries/d3-path/v3.0.1/d3-path.js | 2 + .../libraries/d3-plot/v0.4.3/.eslintrc.json | 20 + .../d3-plot/v0.4.3/.github/eslint.json | 18 + .../v0.4.3/.github/workflows/node.js.yml | 30 + content/libraries/d3-plot/v0.4.3/.gitignore | 5 + content/libraries/d3-plot/v0.4.3/LICENSE | 13 + content/libraries/d3-plot/v0.4.3/README.md | 2240 ++++++ .../libraries/d3-plot/v0.4.3/plot.umd.min.js | 2 + content/libraries/d3-shape/v3.1.0/d3-shape.js | 2 + .../select2/4.1.0-rc.0/css/select2.css | 537 ++ .../select2/4.1.0-rc.0/css/select2.min.css | 1 + .../select2/4.1.0-rc.0/js/i18n/af.js | 3 + .../select2/4.1.0-rc.0/js/i18n/ar.js | 3 + .../select2/4.1.0-rc.0/js/i18n/az.js | 3 + .../select2/4.1.0-rc.0/js/i18n/bg.js | 3 + .../select2/4.1.0-rc.0/js/i18n/bn.js | 3 + .../select2/4.1.0-rc.0/js/i18n/bs.js | 3 + .../select2/4.1.0-rc.0/js/i18n/ca.js | 3 + .../select2/4.1.0-rc.0/js/i18n/cs.js | 3 + .../select2/4.1.0-rc.0/js/i18n/da.js | 3 + .../select2/4.1.0-rc.0/js/i18n/de.js | 3 + .../select2/4.1.0-rc.0/js/i18n/dsb.js | 3 + .../select2/4.1.0-rc.0/js/i18n/el.js | 3 + .../select2/4.1.0-rc.0/js/i18n/en.js | 3 + .../select2/4.1.0-rc.0/js/i18n/eo.js | 3 + .../select2/4.1.0-rc.0/js/i18n/es.js | 3 + .../select2/4.1.0-rc.0/js/i18n/et.js | 3 + .../select2/4.1.0-rc.0/js/i18n/eu.js | 3 + .../select2/4.1.0-rc.0/js/i18n/fa.js | 3 + .../select2/4.1.0-rc.0/js/i18n/fi.js | 3 + .../select2/4.1.0-rc.0/js/i18n/fr.js | 3 + .../select2/4.1.0-rc.0/js/i18n/gl.js | 3 + .../select2/4.1.0-rc.0/js/i18n/he.js | 3 + .../select2/4.1.0-rc.0/js/i18n/hi.js | 3 + .../select2/4.1.0-rc.0/js/i18n/hr.js | 3 + .../select2/4.1.0-rc.0/js/i18n/hsb.js | 3 + .../select2/4.1.0-rc.0/js/i18n/hu.js | 3 + .../select2/4.1.0-rc.0/js/i18n/hy.js | 3 + .../select2/4.1.0-rc.0/js/i18n/id.js | 3 + .../select2/4.1.0-rc.0/js/i18n/is.js | 3 + .../select2/4.1.0-rc.0/js/i18n/it.js | 3 + .../select2/4.1.0-rc.0/js/i18n/ja.js | 3 + .../select2/4.1.0-rc.0/js/i18n/ka.js | 3 + .../select2/4.1.0-rc.0/js/i18n/km.js | 3 + .../select2/4.1.0-rc.0/js/i18n/ko.js | 3 + .../select2/4.1.0-rc.0/js/i18n/lt.js | 3 + .../select2/4.1.0-rc.0/js/i18n/lv.js | 3 + .../select2/4.1.0-rc.0/js/i18n/mk.js | 3 + .../select2/4.1.0-rc.0/js/i18n/ms.js | 3 + .../select2/4.1.0-rc.0/js/i18n/nb.js | 3 + .../select2/4.1.0-rc.0/js/i18n/ne.js | 3 + .../select2/4.1.0-rc.0/js/i18n/nl.js | 3 + .../select2/4.1.0-rc.0/js/i18n/pa.js | 3 + .../select2/4.1.0-rc.0/js/i18n/pl.js | 3 + .../select2/4.1.0-rc.0/js/i18n/ps.js | 3 + .../select2/4.1.0-rc.0/js/i18n/pt-BR.js | 3 + .../select2/4.1.0-rc.0/js/i18n/pt.js | 3 + .../select2/4.1.0-rc.0/js/i18n/ro.js | 3 + .../select2/4.1.0-rc.0/js/i18n/ru.js | 3 + .../select2/4.1.0-rc.0/js/i18n/sk.js | 3 + .../select2/4.1.0-rc.0/js/i18n/sl.js | 3 + .../select2/4.1.0-rc.0/js/i18n/sq.js | 3 + .../select2/4.1.0-rc.0/js/i18n/sr-Cyrl.js | 3 + .../select2/4.1.0-rc.0/js/i18n/sr.js | 3 + .../select2/4.1.0-rc.0/js/i18n/sv.js | 3 + .../select2/4.1.0-rc.0/js/i18n/te.js | 3 + .../select2/4.1.0-rc.0/js/i18n/th.js | 3 + .../select2/4.1.0-rc.0/js/i18n/tk.js | 3 + .../select2/4.1.0-rc.0/js/i18n/tr.js | 3 + .../select2/4.1.0-rc.0/js/i18n/uk.js | 3 + .../select2/4.1.0-rc.0/js/i18n/vi.js | 3 + .../select2/4.1.0-rc.0/js/i18n/zh-CN.js | 3 + .../select2/4.1.0-rc.0/js/i18n/zh-TW.js | 3 + .../select2/4.1.0-rc.0/js/select2.full.js | 6521 +++++++++++++++++ .../select2/4.1.0-rc.0/js/select2.full.min.js | 2 + .../select2/4.1.0-rc.0/js/select2.js | 6209 ++++++++++++++++ .../select2/4.1.0-rc.0/js/select2.min.js | 2 + 77 files changed, 15790 insertions(+) create mode 100644 content/libraries/d3-path/v3.0.1/d3-path.js create mode 100644 content/libraries/d3-plot/v0.4.3/.eslintrc.json create mode 100644 content/libraries/d3-plot/v0.4.3/.github/eslint.json create mode 100644 content/libraries/d3-plot/v0.4.3/.github/workflows/node.js.yml create mode 100644 content/libraries/d3-plot/v0.4.3/.gitignore create mode 100644 content/libraries/d3-plot/v0.4.3/LICENSE create mode 100644 content/libraries/d3-plot/v0.4.3/README.md create mode 100644 content/libraries/d3-plot/v0.4.3/plot.umd.min.js create mode 100644 content/libraries/d3-shape/v3.1.0/d3-shape.js create mode 100644 content/libraries/select2/4.1.0-rc.0/css/select2.css create mode 100644 content/libraries/select2/4.1.0-rc.0/css/select2.min.css create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/af.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/ar.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/az.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/bg.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/bn.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/bs.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/ca.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/cs.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/da.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/de.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/dsb.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/el.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/en.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/eo.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/es.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/et.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/eu.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/fa.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/fi.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/fr.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/gl.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/he.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/hi.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/hr.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/hsb.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/hu.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/hy.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/id.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/is.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/it.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/ja.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/ka.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/km.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/ko.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/lt.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/lv.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/mk.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/ms.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/nb.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/ne.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/nl.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/pa.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/pl.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/ps.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/pt-BR.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/pt.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/ro.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/ru.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/sk.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/sl.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/sq.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/sr-Cyrl.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/sr.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/sv.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/te.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/th.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/tk.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/tr.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/uk.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/vi.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/zh-CN.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/i18n/zh-TW.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/select2.full.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/select2.full.min.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/select2.js create mode 100644 content/libraries/select2/4.1.0-rc.0/js/select2.min.js diff --git a/content/libraries/d3-path/v3.0.1/d3-path.js b/content/libraries/d3-path/v3.0.1/d3-path.js new file mode 100644 index 0000000..db7d1f4 --- /dev/null +++ b/content/libraries/d3-path/v3.0.1/d3-path.js @@ -0,0 +1,2 @@ +// https://d3js.org/d3-path/ v3.0.1 Copyright 2015-2021 Mike Bostock +!function(t,i){"object"==typeof exports&&"undefined"!=typeof module?i(exports):"function"==typeof define&&define.amd?define(["exports"],i):i((t="undefined"!=typeof globalThis?globalThis:t||self).d3=t.d3||{})}(this,(function(t){"use strict";const i=Math.PI,s=2*i,h=1e-6,_=s-h;function e(){this._x0=this._y0=this._x1=this._y1=null,this._=""}function n(){return new e}e.prototype=n.prototype={constructor:e,moveTo:function(t,i){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+i)},closePath:function(){null!==this._x1&&(this._x1=this._x0,this._y1=this._y0,this._+="Z")},lineTo:function(t,i){this._+="L"+(this._x1=+t)+","+(this._y1=+i)},quadraticCurveTo:function(t,i,s,h){this._+="Q"+ +t+","+ +i+","+(this._x1=+s)+","+(this._y1=+h)},bezierCurveTo:function(t,i,s,h,_,e){this._+="C"+ +t+","+ +i+","+ +s+","+ +h+","+(this._x1=+_)+","+(this._y1=+e)},arcTo:function(t,s,_,e,n){t=+t,s=+s,_=+_,e=+e,n=+n;var o=this._x1,r=this._y1,a=_-t,u=e-s,f=o-t,c=r-s,y=f*f+c*c;if(n<0)throw new Error("negative radius: "+n);if(null===this._x1)this._+="M"+(this._x1=t)+","+(this._y1=s);else if(y>h)if(Math.abs(c*a-u*f)>h&&n){var x=_-o,l=e-r,M=a*a+u*u,d=x*x+l*l,p=Math.sqrt(M),v=Math.sqrt(y),b=n*Math.tan((i-Math.acos((M+y-d)/(2*p*v)))/2),T=b/v,g=b/p;Math.abs(T-1)>h&&(this._+="L"+(t+T*f)+","+(s+T*c)),this._+="A"+n+","+n+",0,0,"+ +(c*x>f*l)+","+(this._x1=t+g*a)+","+(this._y1=s+g*u)}else this._+="L"+(this._x1=t)+","+(this._y1=s);else;},arc:function(t,e,n,o,r,a){t=+t,e=+e,a=!!a;var u=(n=+n)*Math.cos(o),f=n*Math.sin(o),c=t+u,y=e+f,x=1^a,l=a?o-r:r-o;if(n<0)throw new Error("negative radius: "+n);null===this._x1?this._+="M"+c+","+y:(Math.abs(this._x1-c)>h||Math.abs(this._y1-y)>h)&&(this._+="L"+c+","+y),n&&(l<0&&(l=l%s+s),l>_?this._+="A"+n+","+n+",0,1,"+x+","+(t-u)+","+(e-f)+"A"+n+","+n+",0,1,"+x+","+(this._x1=c)+","+(this._y1=y):l>h&&(this._+="A"+n+","+n+",0,"+ +(l>=i)+","+x+","+(this._x1=t+n*Math.cos(r))+","+(this._y1=e+n*Math.sin(r))))},rect:function(t,i,s,h){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+i)+"h"+ +s+"v"+ +h+"h"+-s+"Z"},toString:function(){return this._}},t.path=n,Object.defineProperty(t,"__esModule",{value:!0})})); diff --git a/content/libraries/d3-plot/v0.4.3/.eslintrc.json b/content/libraries/d3-plot/v0.4.3/.eslintrc.json new file mode 100644 index 0000000..48aa23d --- /dev/null +++ b/content/libraries/d3-plot/v0.4.3/.eslintrc.json @@ -0,0 +1,20 @@ +{ + "extends": "eslint:recommended", + "parserOptions": { + "sourceType": "module", + "ecmaVersion": 2020 + }, + "env": { + "es6": true, + "node": true, + "browser": true + }, + "rules": { + "no-cond-assign": 0, + "no-constant-condition": 0, + "no-sparse-arrays": 0, + "no-unexpected-multiline": 0, + "comma-dangle": ["error", "never"], + "semi": [2, "always"] + } +} diff --git a/content/libraries/d3-plot/v0.4.3/.github/eslint.json b/content/libraries/d3-plot/v0.4.3/.github/eslint.json new file mode 100644 index 0000000..c280fdb --- /dev/null +++ b/content/libraries/d3-plot/v0.4.3/.github/eslint.json @@ -0,0 +1,18 @@ +{ + "problemMatcher": [ + { + "owner": "eslint-compact", + "pattern": [ + { + "regexp": "^(.+):\\sline\\s(\\d+),\\scol\\s(\\d+),\\s(Error|Warning|Info)\\s-\\s(.+)\\s\\((.+)\\)$", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5, + "code": 6 + } + ] + } + ] +} diff --git a/content/libraries/d3-plot/v0.4.3/.github/workflows/node.js.yml b/content/libraries/d3-plot/v0.4.3/.github/workflows/node.js.yml new file mode 100644 index 0000000..afef0e6 --- /dev/null +++ b/content/libraries/d3-plot/v0.4.3/.github/workflows/node.js.yml @@ -0,0 +1,30 @@ +# https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions + +name: Node.js CI + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + build: + + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [14.x] + + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - run: yarn --frozen-lockfile + - run: | + echo ::add-matcher::.github/eslint.json + yarn run eslint . --format=compact + - run: yarn test diff --git a/content/libraries/d3-plot/v0.4.3/.gitignore b/content/libraries/d3-plot/v0.4.3/.gitignore new file mode 100644 index 0000000..443d880 --- /dev/null +++ b/content/libraries/d3-plot/v0.4.3/.gitignore @@ -0,0 +1,5 @@ +.DS_Store +dist/ +node_modules/ +test/output/*-changed.svg +test/output/*-changed.html diff --git a/content/libraries/d3-plot/v0.4.3/LICENSE b/content/libraries/d3-plot/v0.4.3/LICENSE new file mode 100644 index 0000000..3d39082 --- /dev/null +++ b/content/libraries/d3-plot/v0.4.3/LICENSE @@ -0,0 +1,13 @@ +Copyright 2020-2022 Observable, Inc. + +Permission to use, copy, modify, and/or distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright notice +and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. diff --git a/content/libraries/d3-plot/v0.4.3/README.md b/content/libraries/d3-plot/v0.4.3/README.md new file mode 100644 index 0000000..51e4de1 --- /dev/null +++ b/content/libraries/d3-plot/v0.4.3/README.md @@ -0,0 +1,2240 @@ +# Observable Plot + +**Observable Plot** is a JavaScript library for exploratory data visualization. If you are new to Plot, we highly recommend first reading these notebooks to introduce Plot’s core concepts such as *marks* and *scales*: + +* [Introduction](https://observablehq.com/@observablehq/plot?collection=@observablehq/plot) - a quick tour, and Plot’s motivations +* [Marks and Channels](https://observablehq.com/@observablehq/plot-marks?collection=@observablehq/plot) - drawing data-driven shapes with Plot +* [Scales](https://observablehq.com/@observablehq/plot-scales?collection=@observablehq/plot) - visual encodings for abstract data +* [Transforms](https://observablehq.com/@observablehq/plot-transforms?collection=@observablehq/plot) - deriving data +* [Facets](https://observablehq.com/@observablehq/plot-facets?collection=@observablehq/plot) - small multiples +* [Legends](https://observablehq.com/@observablehq/plot-legends?collection=@observablehq/plot) - documenting visual encodings + +This README is intended as a technical reference for Plot’s API. For more, please see: + +* [Cheatsheets](https://observablehq.com/@observablehq/plot-cheatsheets) - a handy, interactive guide +* [Changelog](./CHANGELOG.md) - release notes +* [Contributing](./CONTRIBUTING.md) - if you’d like to help build Plot +* [Discussions](https://github.com/observablehq/plot/discussions) - if you’d like help +* [Forum](https://talk.observablehq.com/c/help/6) - another place to ask for help +* [Issues](https://github.com/observablehq/plot/issues) - to file a bug or request a new feature + +## Installing + +In Observable notebooks, Plot and D3 are available by default as part of the [standard library](https://observablehq.com/@observablehq/recommended-libraries). + +For use with Webpack, Rollup, or other Node-based bundlers, Plot is typically installed via a package manager such as Yarn or npm. (Plot is distributed as an ES module; see [Sindre Sorhus’s guide](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c) for help upgrading.) + +```bash +yarn add @observablehq/plot +``` + +Plot can then be imported as a namespace: + +```js +import * as Plot from "@observablehq/plot"; +``` + +In vanilla HTML, Plot can be imported as an ES module, say from Skypack: + +```html + +``` + +Plot is also available as a UMD bundle for legacy browsers. + +```html + + + +``` + +See also our [Plot + React example](https://github.com/observablehq/plot-create-react-app-example/blob/main/src/App.js). + +## Plot.plot(*options*) + +Renders a new plot given the specified *options* and returns the corresponding SVG or HTML figure element. All *options* are optional. + +### Mark options + +The **marks** option specifies an array of [marks](#marks) to render. Each mark has its own data and options; see the respective mark type (*e.g.*, [bar](#bar) or [dot](#dot)) for which mark options are supported. Each mark may be a nested array of marks, allowing composition. Marks may also be a function which returns an SVG element, if you wish to insert some arbitrary content into your plot. And marks may be null or undefined, which produce no output; this is useful for showing marks conditionally (*e.g.*, when a box is checked). Marks are drawn in *z*-order, last on top. For example, here a single rule at *y* = 0 is drawn on top of blue bars for the [*alphabet* dataset](./test/data/alphabet.csv). + +```js +Plot.plot({ + marks: [ + Plot.barY(alphabet, {x: "letter", y: "frequency", fill: "steelblue"}), + Plot.ruleY([0]) + ] +}) +``` + +### Layout options + +These options determine the overall layout of the plot; all are specified as numbers in pixels: + +* **marginTop** - the top margin +* **marginRight** - the right margin +* **marginBottom** - the bottom margin +* **marginLeft** - the left margin +* **margin** - shorthand for the four margins +* **width** - the outer width of the plot (including margins) +* **height** - the outer height of the plot (including margins) + +The default **width** is 640. On Observable, the width can be set to the [standard width](https://github.com/observablehq/stdlib/blob/master/README.md#width) to make responsive plots. The default **height** is chosen automatically based on the plot’s associated scales; for example, if *y* is linear and there is no *fy* scale, it might be 396. + +The default margins depend on the plot’s axes: for example, **marginTop** and **marginBottom** are at least 30 if there is a corresponding top or bottom *x* axis, and **marginLeft** and **marginRight** are at least 40 if there is a corresponding left or right *y* axis. For simplicity’s sake and for consistent layout across plots, margins are not automatically sized to make room for tick labels; instead, shorten your tick labels or increase the margins as needed. (In the future, margins may be specified indirectly via a scale property to make it easier to reorient axes without adjusting margins; see [#210](https://github.com/observablehq/plot/issues/210).) + +The **style** option allows custom styles to override Plot’s defaults. It may be specified either as a string of inline styles (*e.g.*, `"color: red;"`, in the same fashion as assigning [*element*.style](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/style)) or an object of properties (*e.g.*, `{color: "red"}`, in the same fashion as assigning [*element*.style properties](https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleDeclaration)). Note that unitless numbers ([quirky lengths](https://www.w3.org/TR/css-values-4/#deprecated-quirky-length)) such as `{padding: 20}` may not supported by some browsers; you should instead specify a string with units such as `{padding: "20px"}`. By default, the returned plot has a white background, a max-width of 100%, and the system-ui font. Plot’s marks and axes default to [currentColor](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value#currentcolor_keyword), meaning that they will inherit the surrounding content’s color. For example, a dark theme: + +```js +Plot.plot({ + marks: …, + style: { + background: "black", + color: "white" + } +}) +``` + +If a **caption** is specified, Plot.plot wraps the generated SVG element in an HTML figure element with a figcaption, returning the figure. To specify an HTML caption, consider using the [`html` tagged template literal](http://github.com/observablehq/htl); otherwise, the specified string represents text that will be escaped as needed. + +```js +Plot.plot({ + marks: …, + caption: html`Figure 1. This chart has a fancy caption.` +}) +``` + +The generated SVG element has a random class name which applies a default stylesheet. Use the top-level **className** option to specify that class name. + +### Scale options + +Plot passes data through [scales](https://observablehq.com/@observablehq/plot-scales) as needed before rendering marks. A scale maps abstract values such as time or temperature to visual values such as position or color. Within a given plot, marks share scales. For example, if a plot has two Plot.line marks, both share the same *x* and *y* scales for a consistent representation of data. (Plot does not currently support dual-axis charts, which are [not advised](https://blog.datawrapper.de/dualaxis/).) + +```js +Plot.plot({ + marks: [ + Plot.line(aapl, {x: "Date", y: "Close"}), + Plot.line(goog, {x: "Date", y: "Close"}) + ] +}) +``` + +Each scale’s options are specified as a nested options object with the corresponding scale name within the top-level plot *options*: + +* **x** - horizontal position +* **y** - vertical position +* **r** - radius (size) +* **color** - fill or stroke +* **opacity** - fill or stroke opacity +* **length** - linear length (for [vectors](#vector)) +* **symbol** - categorical symbol (for [dots](#dot)) + +For example, to set the domain for the *x* and *y* scales: + +```js +Plot.plot({ + x: { + domain: [new Date("1880-01-01"), new Date("2016-11-01")] + }, + y: { + domain: [-0.78, 1.35] + } +}) +``` + +Plot supports many scale types. Some scale types are for quantitative data: values that can be added or subtracted, such as temperature or time. Other scale types are for ordinal or categorical data: unquantifiable values that can only be ordered, such as t-shirt sizes, or values with no inherent order that can only be tested for equality, such as types of fruit. Some scale types are further intended for specific visual encodings: for example, as [position](#position-options) or [color](#color-options). + +You can set the scale type explicitly via the *scale*.**type** option, though typically the scale type is inferred automatically. Some marks mandate a particular scale type: for example, [Plot.barY](#plotbarydata-options) requires that the *x* scale is a *band* scale. Some scales have a default type: for example, the *radius* scale defaults to *sqrt* and the *opacity* scale defaults to *linear*. Most often, the scale type is inferred from associated data, pulled either from the domain (if specified) or from associated channels. A *color* scale defaults to *identity* if no range or scheme is specified and all associated defined values are valid CSS color strings. Otherwise, strings and booleans imply an ordinal scale; dates imply a UTC scale; and anything else is linear. Unless they represent text, we recommend explicitly converting strings to more specific types when loading data (*e.g.*, with d3.autoType or Observable’s FileAttachment). For simplicity’s sake, Plot assumes that data is consistently typed; type inference is based solely on the first non-null, non-undefined value. + +For quantitative data (*i.e.* numbers), a mathematical transform may be applied to the data by changing the scale type: + +* *linear* (default) - linear transform (translate and scale) +* *pow* - power (exponential) transform +* *sqrt* - square-root transform (*pow* transform with exponent = 0.5) +* *log* - logarithmic transform +* *symlog* - bi-symmetric logarithmic transform per [Webber *et al.*](https://www.researchgate.net/publication/233967063_A_bi-symmetric_log_transformation_for_wide-range_data) + +The appropriate transform depends on the data’s distribution and what you wish to know. A *sqrt* transform exaggerates differences between small values at the expense of large values; it is a special case of the *pow* transform which has a configurable *scale*.**exponent** (0.5 for *sqrt*). A *log* transform is suitable for comparing orders of magnitude and can only be used when the domain does not include zero. The base defaults to 10 and can be specified with the *scale*.**base** option; note that this only affects the axis ticks and not the scale’s behavior. A *symlog* transform is more elaborate, but works well with wide-range values that include zero; it can be configured with the *scale*.**constant** option (default 1). + +For temporal data (*i.e.* dates), two variants of a *linear* scale are also supported: + +* *utc* (default, recommended) - UTC time +* *time* - local time + +UTC is recommended over local time as charts in UTC time are guaranteed to appear consistently to all viewers whereas charts in local time will depend on the viewer’s time zone. Due to limitations in JavaScript’s Date class, Plot does not yet support an explicit time zone other than UTC. + +For ordinal data (*e.g.*, strings), use the *ordinal* scale type or the *point* or *band* [position scale types](#position-options). The *categorical* scale type is also supported; it is equivalent to *ordinal* except as a [color scale](#color-options), where it provides a different default color scheme. (Since position is inherently ordinal or even quantitative, categorical data must be assigned an effective order when represented as position, and hence *categorical* and *ordinal* may be considered synonymous in context.) + +You can opt-out of a scale using the *identity* scale type. This is useful if you wish to specify literal colors or pixel positions within a mark channel rather than relying on the scale to convert abstract values into visual values. For position scales (*x* and *y*), an *identity* scale is still quantitative and may produce an axis, yet unlike a *linear* scale the domain and range are fixed based on the plot layout. + +Quantitative scales, as well as identity position scales, coerce channel values to numbers; both null and undefined are coerced to NaN. Similarly, time scales coerce channel values to dates; numbers are assumed to be milliseconds since UNIX epoch, while strings are assumed to be in [ISO 8601 format](https://github.com/mbostock/isoformat/blob/main/README.md#parsedate-fallback). + +A scale’s domain (the extent of its inputs, abstract values) and range (the extent of its outputs, visual values) are typically inferred automatically. You can set them explicitly using these options: + +* *scale*.**domain** - typically [*min*, *max*], or an array of ordinal or categorical values +* *scale*.**range** - typically [*min*, *max*], or an array of ordinal or categorical values +* *scale*.**unknown** - the desired output value (defaults to undefined) for invalid input values +* *scale*.**reverse** - reverses the domain (or in somes cases, the range), say to flip the chart along *x* or *y* + +For most quantitative scales, the default domain is the [*min*, *max*] of all values associated with the scale. For the *radius* and *opacity* scales, the default domain is [0, *max*] to ensure a meaningful value encoding. For ordinal scales, the default domain is the set of all distinct values associated with the scale in natural ascending order; for a different order, set the domain explicitly or add a [sort option](#sort-options) to an associated mark. For threshold scales, the default domain is [0] to separate negative and non-negative values. For quantile scales, the default domain is the set of all defined values associated with the scale. If a scale is reversed, it is equivalent to setting the domain as [*max*, *min*] instead of [*min*, *max*]. + +The default range depends on the scale: for [position scales](#position-options) (*x*, *y*, *fx*, and *fy*), the default range depends on the plot’s [size and margins](#layout-options). For [color scales](#color-options), there are default color schemes for quantitative, ordinal, and categorical data. For opacity, the default range is [0, 1]. And for radius, the default range is designed to produce dots of “reasonable” size assuming a *sqrt* scale type for accurate area representation: zero maps to zero, the first quartile maps to a radius of three pixels, and other values are extrapolated. This convention for radius ensures that if the scale’s data values are all equal, dots have the default constant radius of three pixels, while if the data varies, dots will tend to be larger. + +The behavior of the *scale*.unknown option depends on the scale type. For quantitative and temporal scales, the unknown value is used whenever the input value is undefined, null, or NaN. For ordinal or categorical scales, the unknown value is returned for any input value outside the domain. For band or point scales, the unknown option has no effect; it is effectively always equal to undefined. If the unknown option is set to undefined (the default), or null or NaN, then the affected input values will be considered undefined and filtered from the output. + +Quantitative scales can be further customized with additional options: + +* *scale*.**clamp** - if true, clamp input values to the scale’s domain +* *scale*.**nice** - if true (or a tick count), extend the domain to nice round values +* *scale*.**zero** - if true, extend the domain to include zero if needed +* *scale*.**percent** - if true, transform proportions in [0, 1] to percentages in [0, 100] + +Clamping is typically used in conjunction with setting an explicit domain since if the domain is inferred, no values will be outside the domain. Clamping is useful for focusing on a subset of the data while ensuring that extreme values remain visible, but use caution: clamped values may need an annotation to avoid misinterpretation. Top-level **clamp** and **nice** options are supported as shorthand for setting *scale*.clamp and *scale*.nice on all scales. + +The *scale*.**transform** option allows you to apply a function to all values before they are passed through the scale. This is convenient for transforming a scale’s data, say to convert to thousands or between temperature units. + +```js +Plot.plot({ + y: { + label: "↑ Temperature (°F)", + transform: f => f * 9 / 5 + 32 // convert Celsius to Fahrenheit + }, + marks: … +}) +``` + +#### *plot*.scale(*scaleName*) + +Scale definitions can be exposed through the *plot*.**scale**(*scaleName*) function of a returned plot. The *scaleName* must be one of the known scale names: `"x"`, `"y"`, `"fx"`, `"fy"`, `"r"`, `"color"`, `"opacity"`, `"symbol"`, or `"length"`. If the associated *plot* has no scale with the given *scaleName*, returns undefined. + +```js +const plot = Plot.plot(…); // render a plot +const color = plot.scale("color"); // retrieve the color scale object +console.log(color.range); // inspect the color scale’s range, ["red", "blue"] +``` + +#### Plot.scale(*options*) + +You can also create a standalone scale with Plot.**scale**(*options*). The *options* object must define at least one scale; see [Scale options](#scale-options) for how to define a scale. For example, here is a linear color scale with the default domain of [0, 1] and default scheme *turbo*: + +```js +const color = Plot.scale({color: {type: "linear"}}); +``` + +#### Scale objects + +Both [*plot*.scale](#plotscalescalename) and [Plot.scale](#plotscaleoptions) return scale objects. These objects represent the actual (or “materialized”) scale options used by Plot, including the domain, range, interpolate function, *etc.* The scale’s label, if any, is also returned; however, note that other axis properties are not currently exposed. Point and band scales also expose their materialized bandwidth and step. + +To reuse a scale across plots, pass the corresponding scale object into another plot specification: + +```js +const plot1 = Plot.plot(…); +const plot2 = Plot.plot({…, color: plot1.scale("color")}); +``` + +For convenience, scale objects expose a *scale*.**apply**(*input*) method which returns the scale’s output for the given *input* value. When applicable, scale objects also expose a *scale*.**invert**(*output*) method which returns the corresponding input value from the scale’s domain for the given *output* value. + +### Position options + +The position scales (*x*, *y*, *fx*, and *fy*) support additional options: + +* *scale*.**inset** - inset the default range by the specified amount in pixels +* *scale*.**round** - round the output value to the nearest integer (whole pixel) + +The *x* and *fx* scales support asymmetric insets for more precision. Replace inset by: + +* *scale*.**insetLeft** - insets the start of the default range by the specified number of pixels +* *scale*.**insetRight** - insets the end of the default range by the specified number of pixels + +Similarly, the *y* and *fy* scales support asymmetric insets with: + +* *scale*.**insetTop** - insets the top of the default range by the specified number of pixels +* *scale*.**insetBottom** - insets the bottom of the default range by the specified number of pixels + +The inset scale options can provide “breathing room” to separate marks from axes or the plot’s edge. For example, in a scatterplot with a Plot.dot with the default 3-pixel radius and 1.5-pixel stroke width, an inset of 5 pixels prevents dots from overlapping with the axes. The *scale*.round option is useful for crisp edges by rounding to the nearest pixel boundary. + +In addition to the generic *ordinal* scale type, which requires an explicit output range value for each input domain value, Plot supports special *point* and *band* scale types for encoding ordinal data as position. These scale types accept a [*min*, *max*] range similar to quantitative scales, and divide this continuous interval into discrete points or bands based on the number of distinct values in the domain (*i.e.*, the domain’s cardinality). If the associated marks have no effective width along the ordinal dimension—such as a dot, rule, or tick—then use a *point* scale; otherwise, say for a bar, use a *band* scale. In the image below, the top *x*-scale is a *point* scale while the bottom *x*-scale is a *band* scale; see [Plot: Scales](https://observablehq.com/@observablehq/plot-scales) for an interactive version. + +point and band scales + +Ordinal position scales support additional options, all specified as proportions in [0, 1]: + +* *scale*.**padding** - how much of the range to reserve to inset first and last point or band +* *scale*.**align** - where to distribute points or bands (0 = at start, 0.5 = at middle, 1 = at end) + +For a *band* scale, you can further fine-tune padding: + +* *scale*.**paddingInner** - how much of the range to reserve to separate adjacent bands +* *scale*.**paddingOuter** - how much of the range to reserve to inset first and last band + +Align defaults to 0.5 (centered). Band scale padding defaults to 0.1 (10% of available space reserved for separating bands), while point scale padding defaults to 0.5 (the gap between the first point and the edge is half the distance of the gap between points, and likewise for the gap between the last point and the opposite edge). Note that rounding and mark insets (e.g., for bars and rects) also affect separation between adjacent marks. + +Plot automatically generates axes for position scales. You can configure these axes with the following options: + +* *scale*.**axis** - the orientation: *top* or *bottom* for *x*; *left* or *right* for *y*; null to suppress +* *scale*.**ticks** - the approximate number of ticks to generate +* *scale*.**tickSize** - the size of each tick (in pixels; default 6) +* *scale*.**tickPadding** - the separation between the tick and its label (in pixels; default 3) +* *scale*.**tickFormat** - to format tick values, either a function or format specifier string; see [Formats](#formats) +* *scale*.**tickRotate** - whether to rotate tick labels (an angle in degrees clockwise; default 0) +* *scale*.**grid** - if true, draw grid lines across the plot for each tick +* *scale*.**line** - if true, draw the axis line +* *scale*.**label** - a string to label the axis +* *scale*.**labelAnchor** - the label anchor: *top*, *right*, *bottom*, *left*, or *center* +* *scale*.**labelOffset** - the label position offset (in pixels; default 0, typically for facet axes) +* *scale*.**fontVariant** - the font-variant attribute for axis ticks; defaults to tabular-nums for quantitative axes. +* *scale*.**ariaLabel** - a short label representing the axis in the accessibility tree +* *scale*.**ariaDescription** - a textual description for the axis + +Top-level options are also supported as shorthand: **grid** (for *x* and *y* only; see [facet.grid](#facet-options)), **label**, **axis**, **inset**, **round**, **align**, and **padding**. + +### Color options + +The normal scale types—*linear*, *sqrt*, *pow*, *log*, *symlog*, and *ordinal*—can be used to encode color. In addition, Plot supports special scale types for color: + +* *categorical* - equivalent to *ordinal*, but defaults to the *tableau10* scheme +* *sequential* - equivalent to *linear* +* *cyclical* - equivalent to *linear*, but defaults to the *rainbow* scheme +* *threshold* - encodes based on the specified discrete thresholds; defaults to the *rdylbu* scheme +* *quantile* - encodes based on the computed quantile thresholds; defaults to the *rdylbu* scheme +* *quantize* - transforms a continuous domain into quantized thresholds; defaults to the *rdylbu* scheme +* *diverging* - like *linear*, but with a pivot; defaults to the *rdbu* scheme +* *diverging-log* - like *log*, but with a pivot that defaults to 1; defaults to the *rdbu* scheme +* *diverging-pow* - like *pow*, but with a pivot; defaults to the *rdbu* scheme +* *diverging-sqrt* - like *sqrt*, but with a pivot; defaults to the *rdbu* scheme +* *diverging-symlog* - like *symlog*, but with a pivot; defaults to the *rdbu* scheme + +For a *threshold* scale, the *domain* represents *n* (typically numeric) thresholds which will produce a *range* of *n* + 1 output colors; the *i*th color of the *range* applies to values that are smaller than the *i*th element of the domain and larger or equal to the *i* - 1th element of the domain. For a *quantile* scale, the *domain* represents all input values to the scale, and the *n* option specifies how many quantiles to compute from the *domain*; *n* quantiles will produce *n* - 1 thresholds, and an output range of *n* colors. For a *quantize* scale, the domain will be transformed into approximately *n* quantized values, where *n* is an option that defaults to 5. + +By default, all diverging color scales are symmetric around the pivot; set *symmetric* to false if you want to cover the whole extent on both sides. + +Color scales support two additional options: + +* *scale*.**scheme** - a named color scheme in lieu of a range, such as *reds* +* *scale*.**interpolate** - in conjunction with a range, how to interpolate colors + +For quantile and quantize color scales, the *scale*.scheme option is used in conjunction with *scale*.**n**, which determines how many quantiles or quantized values to compute, and thus the number of elements in the scale’s range; it defaults to 5 (for quintiles in the case of a quantile scale). + +The following sequential scale schemes are supported for both quantitative and ordinal data: + +* blues *blues* +* greens *greens* +* greys *greys* +* oranges *oranges* +* purples *purples* +* reds *reds* +* bugn *bugn* +* bupu *bupu* +* gnbu *gnbu* +* orrd *orrd* +* pubu *pubu* +* pubugn *pubugn* +* purd *purd* +* rdpu *rdpu* +* ylgn *ylgn* +* ylgnbu *ylgnbu* +* ylorbr *ylorbr* +* ylorrd *ylorrd* +* cividis *cividis* +* inferno *inferno* +* magma *magma* +* plasma *plasma* +* viridis *viridis* +* cubehelix *cubehelix* +* turbo *turbo* +* warm *warm* +* cool *cool* + +The default color scheme, *turbo*, was chosen primarily to ensure high-contrast visibility. Color schemes such as *blues* make low-value marks difficult to see against a white background, for better or for worse. To use a subset of a continuous color scheme (or any single-argument *interpolate* function), set the *scale*.range property to the corresponding subset of [0, 1]; for example, to use the first half of the *rainbow* color scheme, use a range of [0, 0.5]. By default, the full range [0, 1] is used. If you wish to encode a quantitative value without hue, consider using *opacity* rather than *color* (e.g., use Plot.dot’s *strokeOpacity* instead of *stroke*). + +The following diverging scale schemes are supported: + +* brbg *brbg* +* prgn *prgn* +* piyg *piyg* +* puor *puor* +* rdbu *rdbu* +* rdgy *rdgy* +* rdylbu *rdylbu* +* rdylgn *rdylgn* +* spectral *spectral* +* burd *burd* +* buylrd *buylrd* + +Diverging color scales support a *scale*.**pivot** option, which defaults to zero. Values below the pivot will use the lower half of the color scheme (*e.g.*, reds for the *rdgy* scheme), while values above the pivot will use the upper half (grays for *rdgy*). + +The following cylical color schemes are supported: + +* rainbow *rainbow* +* sinebow *sinebow* + +The following categorical color schemes are supported: + +* accent *accent* (8 colors) +* category10 *category10* (10 colors) +* dark2 *dark2* (8 colors) +* paired *paired* (12 colors) +* pastel1 *pastel1* (9 colors) +* pastel2 *pastel2* (8 colors) +* set1 *set1* (9 colors) +* set2 *set2* (8 colors) +* set3 *set3* (12 colors) +* tableau10 *tableau10* (10 colors) + +The following color interpolators are supported: + +* *rgb* - RGB (red, green, blue) +* *hsl* - HSL (hue, saturation, lightness) +* *lab* - CIELAB (*a.k.a.* “Lab”) +* *hcl* - CIELChab (*a.k.a.* “LCh” or “HCL”) + +For example, to use CIELChab: + +```js +Plot.plot({ + color: { + range: ["red", "blue"], + interpolate: "hcl" + }, + marks: … +}) +``` + +Or to use gamma-corrected RGB (via [d3-interpolate](https://github.com/d3/d3-interpolate)): + +```js +Plot.plot({ + color: { + range: ["red", "blue"], + interpolate: d3.interpolateRgb.gamma(2.2) + }, + marks: … +}) +``` + +### Sort options + +If an ordinal scale’s domain is not set, it defaults to natural ascending order; to order the domain by associated values in another dimension, either compute the domain manually (consider [d3.groupSort](https://github.com/d3/d3-array/blob/main/README.md#groupSort)) or use an associated mark’s **sort** option. For example, to sort bars by ascending frequency rather than alphabetically by letter: + +```js +Plot.barY(alphabet, {x: "letter", y: "frequency", sort: {x: "y"}}) +``` + +The sort option is an object whose keys are ordinal scale names, such as *x* or *fx*, and whose values are mark channel names, such as *y*, *y1*, or *y2*. By specifying an existing channel rather than a new value, you avoid repeating the order definition and can refer to channels derived by [transforms](#transforms) (such as [stack](#stack) or [bin](#bin)). When sorting on the *x*, if no such channel is defined, the *x2* channel will be used instead if available, and similarly for *y* and *y2*; this is useful for marks that implicitly stack such as [area](#area), [bar](#bar), and [rect](#rect). A sort value may also be specified as *width* or *height*, representing derived channels |*x2* - *x1*| and |*y2* - *y1*| respectively. + +Note that there may be multiple associated values in the secondary dimension for a given value in the primary ordinal dimension. The secondary values are therefore grouped for each associated primary value, and each group is then aggregated by applying a reducer. Lastly the primary values are sorted based on the associated reduced value in natural ascending order to produce the domain. The default reducer is *max*, but may be changed by specifying the *reduce* option. The above code is shorthand for: + +```js +Plot.barY(alphabet, {x: "letter", y: "frequency", sort: {x: "y", reduce: "max"}}) +``` + +Generally speaking, a reducer only needs to be specified when there are multiple secondary values for a given primary value. TODO An example of assigning categorical colors in a scatterplot by descending count to maximize discriminability. See the [group transform](#group) for the list of supported reducers. + +For descending rather than ascending order, use the *reverse* option: + +```js +Plot.barY(alphabet, {x: "letter", y: "frequency", sort: {x: "y", reverse: true}}) +``` + +An additional *limit* option truncates the domain to the first *n* values after sorting. If *limit* is negative, the last *n* values are used instead. Hence, a positive *limit* with *reverse* = true will return the top *n* values in descending order. If *limit* is an array [*lo*, *hi*], the *i*th values with *lo* ≤ *i* < *hi* will be selected. (Note that like the [basic filter transform](#transforms), limiting the *x* domain here does not affect the computation of the *y* domain, which is computed independently without respect to filtering.) + +```js +Plot.barY(alphabet, {x: "letter", y: "frequency", sort: {x: "y", limit: 5}}) +``` + +If different sort options are needed for different ordinal scales, the channel name can be replaced with a *value* object with additional per-scale options. + +```js +Plot.barY(alphabet, {x: "letter", y: "frequency", sort: {x: {value: "y", reverse: true}}}) +``` + +If the input channel is *data*, then the reducer is passed groups of the mark’s data; this is typically used in conjunction with a custom reducer function, as when the built-in single-channel reducers are insufficient. + +Note: when the value of the sort option is a string or a function, it is interpreted as a [basic sort transform](#transforms). To use both sort options and a sort transform, use [Plot.sort](#plotsortorder-options). + +### Facet options + +The *facet* option enables [faceting](https://observablehq.com/@observablehq/plot-facets). When faceting, two additional band scales may be configured: + +* **fx** - the horizontal position, a *band* scale +* **fy** - the vertical position, a *band* scale + +Similar to [marks](#marks), faceting requires specifying data and at least one of two optional channels: + +* facet.**data** - the data to be faceted +* facet.**x** - the horizontal position; bound to the *fx* scale, which must be *band* +* facet.**y** - the vertical position; bound to the *fy* scale, which must be *band* + +The facet.**x** and facet.**y** channels are strictly ordinal or categorical (*i.e.*, discrete); each distinct channel value defines a facet. Quantitative data must be manually discretized for faceting, say by rounding or binning. (Automatic binning for quantitative data may be added in the future; see [#14](https://github.com/observablehq/plot/issues/14).) + +The following *facet* constant options are also supported: + +* facet.**marginTop** - the top margin +* facet.**marginRight** - the right margin +* facet.**marginBottom** - the bottom margin +* facet.**marginLeft** - the left margin +* facet.**margin** - shorthand for the four margins +* facet.**grid** - if true, draw grid lines for each facet +* facet.**label** - if null, disable default facet axis labels + +Faceting can be explicitly enabled or disabled on a mark with the *facet* option, which accepts the following values: + +* *auto* (default) - equivalent to *include* when mark data is strictly equal to facet data; else null +* *include* (or true) - draw the subset of the mark’s data in the current facet +* *exclude* - draw the subset of the mark’s data *not* in the current facet +* null (or false) - repeat this mark’s data across all facets (i.e., no faceting) + +```js +Plot.plot({ + facet: { + data: penguins, + x: "sex" + }, + marks: [ + Plot.frame(), // draws an outline around each facet + Plot.dot(penguins, {x: "culmen_length_mm", y: "culmen_depth_mm", fill: "#eee", facet: "exclude"}), // draws excluded penguins on each facet + Plot.dot(penguins, {x: "culmen_length_mm", y: "culmen_depth_mm"}) // draws only the current facet’s subset + ] +}) +``` + +When the *include* or *exclude* facet mode is chosen, the mark data must be parallel to the facet data: the mark data must have the same length and order as the facet data. If the data are not parallel, then the wrong data may be shown in each facet. The default *auto* therefore requires strict equality (`===`) for safety, and using the facet data as mark data is recommended when using the *exclude* facet mode. (To construct parallel data safely, consider using [*array*.map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) on the facet data.) + +## Legends + +Plot can generate legends for *color*, *opacity*, and *symbol* [scales](#scale-options). (An opacity scale is treated as a color scale with varying transparency.) For an inline legend, use the *scale*.**legend** option: + +* *scale*.**legend** - if truthy, generate a legend for the given scale + +If the *scale*.**legend** option is true, the default legend will be produced for the scale; otherwise, the meaning of the *legend* option depends on the scale. For quantitative color scales, it defaults to *ramp* but may be set to *swatches* for a discrete scale (most commonly for *threshold* color scales); for ordinal color scales and symbol scales, only the *swatches* value is supported. + +For example, this scatterplot includes a swatches legend for the ordinal color scale: + +```js +Plot.plot({ + color: { + legend: true + }, + marks: [ + Plot.dot(athletes, {x: "weight", y: "height", stroke: "sex"}) + ] +}) +``` + +Whereas this scatterplot would render a ramp legend for its diverging color scale: + +```js +Plot.plot({ + color: { + type: "diverging", + legend: true + }, + marks: [ + Plot.dot(gistemp, {x: "Date", y: "Anomaly", stroke: "Anomaly"}) + ] +}) +``` + +#### *plot*.legend(*scaleName*, *options*) + +Given an existing *plot* returned by [Plot.plot](#plotplotoptions), returns a detached legend for the *plot*’s scale with the given *scaleName*. The *scaleName* must refer to a scale that supports legends: either `"color"`, `"opacity"`, or `"symbol"`. For example: + +```js +myplot = Plot.plot(…) +``` +```js +mylegend = myplot.legend("color") +``` + +Or, with additional *options*: + +```js +mylegend = myplot.legend("color", {width: 320}) +``` + +If there is no scale with the given *scaleName* on the given *plot*, then *plot*.legend will return undefined. + +Categorical and ordinal color legends are rendered as swatches, unless *options*.**legend** is set to *ramp*. The swatches can be configured with the following options: + +* *options*.**tickFormat** - a format function for the labels +* *options*.**swatchSize** - the size of the swatch (if square) +* *options*.**swatchWidth** - the swatches’ width +* *options*.**swatchHeight** - the swatches’ height +* *options*.**columns** - the number of swatches per row +* *options*.**marginLeft** - the legend’s left margin +* *options*.**className** - a class name, that defaults to a randomly generated string scoping the styles +* *options*.**width** - the legend’s width (in pixels) + +Symbol legends are rendered as swatches and support the options above in addition to the following options: + +* *options*.**fill** - the symbol fill color +* *options*.**fillOpacity** - the symbol fill opacity; defaults to 1 +* *options*.**stroke** - the symbol stroke color +* *options*.**strokeOpacity** - the symbol stroke opacity; defaults to 1 +* *options*.**strokeWidth** - the symbol stroke width; defaults to 1.5 +* *options*.**r** - the symbol radius; defaults to 4.5 pixels + +The **fill** and **stroke** symbol legend options can be specified as “color” to apply the color scale when the symbol scale is a redundant encoding. The **fill** defaults to none. The **stroke** defaults to currentColor if the fill is none, and to none otherwise. The **fill** and **stroke** options may also be inherited from the corresponding options on an associated dot mark. + +Continuous color legends are rendered as a ramp, and can be configured with the following options: + +* *options*.**label** - the scale’s label +* *options*.**ticks** - the desired number of ticks, or an array of tick values +* *options*.**tickFormat** - a format function for the legend’s ticks +* *options*.**tickSize** - the tick size +* *options*.**round** - if true (default), round tick positions to pixels +* *options*.**width** - the legend’s width +* *options*.**height** - the legend’s height +* *options*.**marginTop** - the legend’s top margin +* *options*.**marginRight** - the legend’s right margin +* *options*.**marginBottom** - the legend’s bottom margin +* *options*.**marginLeft** - the legend’s left margin + +The **style** legend option allows custom styles to override Plot’s defaults; it has the same behavior as in Plot’s top-level [layout options](#layout-options). + +#### Plot.legend(*options*) + +Returns a standalone legend for the scale defined by the given *options* object. The *options* object must define at least one scale; see [Scale options](#scale-options) for how to define a scale. For example, here is a ramp legend of a linear color scale with the default domain of [0, 1] and default scheme *turbo*: + +```js +Plot.legend({color: {type: "linear"}}) +``` + +The *options* object may also include any additional legend options described in the previous section. For example, to make the above legend slightly wider: + +```js +Plot.legend({ + width: 320, + color: { + type: "linear" + } +}) +``` + +## Marks + +[Marks](https://observablehq.com/@observablehq/plot-marks) visualize data as geometric shapes such as bars, dots, and lines. An single mark can generate multiple shapes: for example, passing a [Plot.barY](#plotbarydata-options) to [Plot.plot](#plotplotoptions) will produce a bar for each element in the associated data. Multiple marks can be layered into [plots](#plotplotoptions). + +Mark constructors take two arguments: **data** and **options**. Together these describe a tabular dataset and how to visualize it. Option values that must be the same for all of a mark’s generated shapes are known as *constants*, whereas option values that may vary across a mark’s generated shapes are known as *channels*. Channels are typically bound to [scales](#scale-options) and encode abstract data values, such as time or temperature, as visual values, such as position or color. (Channels can also be used to order ordinal domains; see [sort options](#sort-options).) + +A mark’s data is most commonly an array of objects representing a tabular dataset, such as the result of loading a CSV file, while a mark’s options bind channels (such as *x* and *y*) to columns in the data (such as *units* and *fruit*). + +```js +sales = [ + {units: 10, fruit: "fig"}, + {units: 20, fruit: "date"}, + {units: 40, fruit: "plum"}, + {units: 30, fruit: "plum"} +] +``` +```js +Plot.dot(sales, {x: "units", y: "fruit"}).plot() +``` + +While a column name such as `"units"` is the most concise way of specifying channel values, values can also be specified as functions for greater flexibility, say to transform data or derive a new column on the fly. Channel functions are invoked for each datum (*d*) in the data and return the corresponding channel value. (This is similar to how D3’s [*selection*.attr](https://github.com/d3/d3-selection/blob/master/README.md#selection_attr) accepts functions, though note that Plot channel functions should return abstract values, not visual values.) + +```js +Plot.dot(sales, {x: d => d.units * 1000, y: d => d.fruit}).plot() +``` + +Plot also supports columnar data for greater efficiency with bigger datasets; for example, data can be specified as any array of the appropriate length (or any iterable or value compatible with [Array.from](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from)), and then separate arrays of values can be passed as *options*. + +```js +index = [0, 1, 2, 3] +``` +```js +units = [10, 20, 40, 30] +``` +```js +fruits = ["fig", "date", "plum", "plum"] +``` +```js +Plot.dot(index, {x: units, y: fruits}).plot() +``` + +Channel values can also be specified as numbers for constant values, say for a fixed baseline with an [area](#area). + +```js +Plot.area(aapl, {x1: "Date", y1: 0, y2: "Close"}).plot() +``` + +Missing and invalid data are handled specifically for each mark type and channel. In most cases, if the provided channel value for a given datum is null, undefined, or (strictly) NaN, the mark will implicitly filter the datum and not generate a corresponding output. In some cases, such as the radius (*r*) of a dot, the channel value must additionally be positive. Plot.line and Plot.area will stop the path before any invalid point and start again at the next valid point, thus creating interruptions rather than interpolating between valid points. Titles will only be added if they are non-empty. + +All marks support the following style options: + +* **fill** - fill color +* **fillOpacity** - fill opacity (a number between 0 and 1) +* **stroke** - stroke color +* **strokeWidth** - stroke width (in pixels) +* **strokeOpacity** - stroke opacity (a number between 0 and 1) +* **strokeLinejoin** - how to join lines (*bevel*, *miter*, *miter-clip*, or *round*) +* **strokeLinecap** - how to cap lines (*butt*, *round*, or *square*) +* **strokeMiterlimit** - to limit the length of *miter* joins +* **strokeDasharray** - a comma-separated list of dash lengths (typically in pixels) +* **strokeDashoffset** - the [stroke dash offset](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-dashoffset) (typically in pixels) +* **opacity** - object opacity (a number between 0 and 1) +* **mixBlendMode** - the [blend mode](https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode) (*e.g.*, *multiply*) +* **shapeRendering** - the [shape-rendering mode](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/shape-rendering) (*e.g.*, *crispEdges*) +* **paintOrder** - the [paint order](https://developer.mozilla.org/en-US/docs/Web/CSS/paint-order) (*e.g.*, *stroke*) +* **dx** - horizontal offset (in pixels; defaults to 0) +* **dy** - vertical offset (in pixels; defaults to 0) +* **target** - link target (e.g., “_blank” for a new window); for use with the **href** channel +* **ariaDescription** - a textual description of the mark’s contents +* **ariaHidden** - if true, hide this content from the accessibility tree +* **clip** - if true, the mark is clipped to the frame’s dimensions + +For all marks except [text](#plottextdata-options), the **dx** and **dy** options are rendered as a transform property, possibly including a 0.5px offset on low-density screens. + +All marks support the following optional channels: + +* **fill** - a fill color; bound to the *color* scale +* **fillOpacity** - a fill opacity; bound to the *opacity* scale +* **stroke** - a stroke color; bound to the *color* scale +* **strokeOpacity** - a stroke opacity; bound to the *opacity* scale +* **strokeWidth** - a stroke width (in pixels) +* **opacity** - an object opacity; bound to the *opacity* scale +* **title** - a tooltip (a string of text, possibly with newlines) +* **href** - a URL to link to +* **ariaLabel** - a short label representing the value in the accessibility tree + +The **fill**, **fillOpacity**, **stroke**, **strokeWidth**, **strokeOpacity**, and **opacity** options can be specified as either channels or constants. When the fill or stroke is specified as a function or array, it is interpreted as a channel; when the fill or stroke is specified as a string, it is interpreted as a constant if a valid CSS color and otherwise it is interpreted as a column name for a channel. Similarly when the fill opacity, stroke opacity, object opacity, stroke width, or radius is specified as a number, it is interpreted as a constant; otherwise it is interpreted as a channel. + +The **title**, **href**, and **ariaLabel** options can *only* be specified as channels. When these options are specified as a string, the string refers to the name of a column in the mark’s associated data. If you’d like every instance of a particular mark to have the same value, specify the option as a function that returns the desired value, *e.g.* `() => "Hello, world!"`. + +The rectangular marks ([bar](#bar), [cell](#cell), and [rect](#rect)) support insets and rounded corner constant options: + +* **insetTop** - inset the top edge +* **insetRight** - inset the right edge +* **insetBottom** - inset the bottom edge +* **insetLeft** - inset the left edge +* **rx** - the [*x*-radius](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/rx) for rounded corners +* **ry** - the [*y*-radius](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/ry) for rounded corners + +Insets are specified in pixels. Corner radii are specified in either pixels or percentages (strings). Both default to zero. Insets are typically used to ensure a one-pixel gap between adjacent bars; note that the [bin transform](#bin) provides default insets, and that the [band scale padding](#position-options) defaults to 0.1, which also provides separation. + +For marks that support the **frameAnchor** option, it may be specified as one of the four sides (*top*, *right*, *bottom*, *left*), one of the four corners (*top-left*, *top-right*, *bottom-right*, *bottom-left*), or the *middle* of the frame. + +#### *mark*.plot(*options*) + +Given a *mark*, such as the result of calling [Plot.barY](#plotbarydata-options), you can call *mark*.plot to render a plot. This is [shorthand](https://observablehq.com/@observablehq/plot-shorthand?collection=@observablehq/plot) for calling [Plot.plot](#plotplotoptions) where the *marks* option specifies this single mark. + +```js +const mark = Plot.barY(alphabet, {x: "letter", y: "frequency"}); +return mark.plot(); +``` + +More commonly this shorthand is written as a single expression: + +```js +Plot.barY(alphabet, {x: "letter", y: "frequency"}).plot() +``` + +This is equivalent to: + +```js +Plot.plot({marks: [Plot.barY(alphabet, {x: "letter", y: "frequency"})]}) +``` + +If needed, you can pass additional *options* to *mark*.plot, which is equivalent to passing *options* to Plot.plot. (If the *marks* option is used, additional marks are concatenated with the shorthand *mark*.) + +```js +Plot.barY(alphabet, {x: "letter", y: "frequency"}).plot({width: 1024}) +``` + +#### Plot.marks(...*marks*) + +A convenience method for composing a mark from a series of other marks. Returns an array of marks that implements the *mark*.plot function. See the [box mark implementation](./src/marks/box.js) for an example. + +### Area + +[an area chart](https://observablehq.com/@observablehq/plot-area) + +[Source](./src/marks/area.js) · [Examples](https://observablehq.com/@observablehq/plot-area) · Draws regions formed by a baseline (*x1*, *y1*) and a topline (*x2*, *y2*) as in an area chart. Often the baseline represents *y* = 0. While not required, typically the *x* and *y* scales are both quantitative. + +The following channels are required: + +* **x1** - the horizontal position of the baseline; bound to the *x* scale +* **y1** - the vertical position of the baseline; bound to the *y* scale + +In addition to the [standard mark options](#marks), the following optional channels are supported: + +* **x2** - the horizontal position of the topline; bound to the *x* scale +* **y2** - the vertical position of the topline; bound to the *y* scale +* **z** - a categorical value to group data into series + +If **x2** is not specified, it defaults to **x1**. If **y2** is not specified, it defaults to **y1**. These defaults facilitate sharing *x* or *y* coordinates between the baseline and topline. See also the implicit stack transform and shorthand **x** and **y** options supported by [Plot.areaY](#plotareaydata-options) and [Plot.areaX](#plotareaxdata-options). + +By default, the data is assumed to represent a single series (a single value that varies over time, *e.g.*). If the **z** channel is specified, data is grouped by *z* to form separate series. Typically *z* is a categorical value such as a series name. If **z** is not specified, it defaults to **fill** if a channel, or **stroke** if a channel. + +The **stroke** defaults to none. The **fill** defaults to currentColor if the stroke is none, and to none otherwise. If the fill is defined as a channel, the area will be broken into contiguous overlapping segments when the fill color changes; the fill color will apply to the interval spanning the current data point and the following data point. This behavior also applies to the **fillOpacity**, **stroke**, **strokeOpacity**, **strokeWidth**, **opacity**, **href**, **title**, and **ariaLabel** channels. When any of these channels are used, setting an explicit **z** channel (possibly to null) is strongly recommended. The **strokeLinecap** and **strokeLinejoin** default to *round*, and the **strokeMiterlimit** defaults to 1. + +Points along the baseline and topline are connected in input order. Likewise, if there are multiple series via the *z*, *fill*, or *stroke* channel, the series are drawn in input order such that the last series is drawn on top. Typically, the data is already in sorted order, such as chronological for time series; if sorting is needed, consider a [sort transform](#transforms). + +The area mark supports [curve options](#curves) to control interpolation between points. If any of the *x1*, *y1*, *x2*, or *y2* values are invalid (undefined, null, or NaN), the baseline and topline will be interrupted, resulting in a break that divides the area shape into multiple segments. (See [d3-shape’s *area*.defined](https://github.com/d3/d3-shape/blob/master/README.md#area_defined) for more.) If an area segment consists of only a single point, it may appear invisible unless rendered with rounded or square line caps. In addition, some curves such as *cardinal-open* only render a visible segment if it contains multiple points. + +#### Plot.area(*data*, *options*) + +```js +Plot.area(aapl, {x1: "Date", y1: 0, y2: "Close"}) +``` + +Returns a new area with the given *data* and *options*. Plot.area is rarely used directly; it is only needed when the baseline and topline have neither common *x* nor *y* values. [Plot.areaY](#plotareaydata-options) is used in the common horizontal orientation where the baseline and topline share *x* values, while [Plot.areaX](#plotareaxdata-options) is used in the vertical orientation where the baseline and topline share *y* values. + +#### Plot.areaX(*data*, *options*) + +```js +Plot.areaX(aapl, {y: "Date", x: "Close"}) +``` + +Returns a new area with the given *data* and *options*. This constructor is used when the baseline and topline share *y* values, as in a time-series area chart where time goes up↑. If neither the **x1** nor **x2** option is specified, the **x** option may be specified as shorthand to apply an implicit [stackX transform](#plotstackxstack-options); this is the typical configuration for an area chart with a baseline at *x* = 0. If the **x** option is not specified, it defaults to the identity function. The **y** option specifies the **y1** channel; and the **y1** and **y2** options are ignored. + +If the **interval** option is specified, the [binY transform](#bin) is implicitly applied to the specified *options*. The reducer of the output *x* channel may be specified via the **reduce** option, which defaults to *first*. To default to zero instead of showing gaps in data, as when the observed value represents a quantity, use the *sum* reducer. + +```js +Plot.areaX(observations, {y: "date", x: "temperature", interval: d3.utcDay}) +``` + +The **interval** option is recommended to “regularize” sampled data; for example, if your data represents timestamped temperature measurements and you expect one sample per day, use d3.utcDay as the interval. + +#### Plot.areaY(*data*, *options*) + +```js +Plot.areaY(aapl, {x: "Date", y: "Close"}) +``` + +Returns a new area with the given *data* and *options*. This constructor is used when the baseline and topline share *x* values, as in a time-series area chart where time goes right→. If neither the **y1** nor **y2** option is specified, the **y** option may be specified as shorthand to apply an implicit [stackY transform](#plotstackystack-options); this is the typical configuration for an area chart with a baseline at *y* = 0. If the **y** option is not specified, it defaults to the identity function. The **x** option specifies the **x1** channel; and the **x1** and **x2** options are ignored. + +If the **interval** option is specified, the [binX transform](#bin) is implicitly applied to the specified *options*. The reducer of the output *y* channel may be specified via the **reduce** option, which defaults to *first*. To default to zero instead of showing gaps in data, as when the observed value represents a quantity, use the *sum* reducer. + +```js +Plot.areaY(observations, {x: "date", y: "temperature", interval: d3.utcDay) +``` + +The **interval** option is recommended to “regularize” sampled data; for example, if your data represents timestamped temperature measurements and you expect one sample per day, use d3.utcDay as the interval. + +### Arrow + +[a scatterplot with arrows](https://observablehq.com/@observablehq/plot-arrow) + +[Source](./src/marks/arrow.js) · [Examples](https://observablehq.com/@observablehq/plot-arrow) · Draws (possibly swoopy) arrows connecting pairs of points. + +The following channels are required: + +* **x1** - the starting horizontal position; bound to the *x* scale +* **y1** - the starting vertical position; bound to the *y* scale +* **x2** - the ending horizontal position; bound to the *x* scale +* **y2** - the ending vertical position; bound to the *y* scale + +For vertical or horizontal arrows, the **x** option can be specified as shorthand for **x1** and **x2**, and the **y** option can be specified as shorthand for **y1** and **y2**, respectively. + +The arrow mark supports the [standard mark options](#marks). The **stroke** defaults to currentColor. The **fill** defaults to none. The **strokeWidth** and **strokeMiterlimit** default to one. The following additional options are supported: + +* **bend** - the bend angle, in degrees; defaults to zero +* **headAngle** - the arrowhead angle, in degrees; defaults to 22.5° +* **headLength** - the arrowhead scale; defaults to 8 +* **insetEnd** - inset at the end of the arrow (useful if the arrow points to a dot) +* **insetStart** - inset at the start of the arrow +* **inset** - shorthand for the two insets + +The **bend** option sets the angle between the straight line between the two points and the outgoing direction of the arrow from the start point. It must be within ±90°. A positive angle will produce a clockwise curve; a negative angle will produce a counterclockwise curve; zero will produce a straight line. The **headAngle** determines how pointy the arrowhead is; it is typically between 0° and 180°. The **headLength** determines the scale of the arrowhead relative to the stroke width. Assuming the default of stroke width 1.5px, the **headLength** is the length of the arrowhead’s side in pixels. + +#### Plot.arrow(*data*, *options*) + +```js +Plot.arrow(inequality, {x1: "POP_1980", y1: "R90_10_1980", x2: "POP_2015", y2: "R90_10_2015", bend: true}) +``` + +Returns a new arrow with the given *data* and *options*. + +### Bar + +[a bar chart](https://observablehq.com/@observablehq/plot-bar) + +[Source](./src/marks/bar.js) · [Examples](https://observablehq.com/@observablehq/plot-bar) · Draws rectangles where *x* is ordinal and *y* is quantitative ([Plot.barY](#plotbarydata-options)) or *y* is ordinal and *x* is quantitative ([Plot.barX](#plotbarxdata-options)). If one dimension is temporal and the other is quantitative, as in a time-series bar chart, use the [rect mark](#rect) with the *interval* option instead. There is usually one ordinal value associated with each bar, such as a name, and two quantitative values defining a lower and upper bound. The lower bound is often not specified explicitly because it defaults to zero as in a conventional bar chart. + +For the required channels, see [Plot.barX](#plotbarxdata-options) and [Plot.barY](#plotbarydata-options). The bar mark supports the [standard mark options](#marks), including insets and rounded corners. The **stroke** defaults to none. The **fill** defaults to currentColor if the stroke is none, and to none otherwise. + +#### Plot.barX(*data*, *options*) + +```js +Plot.barX(alphabet, {y: "letter", x: "frequency"}) +``` + +Returns a new horizontal bar↔︎ with the given *data* and *options*. The following channels are required: + +* **x1** - the starting horizontal position; bound to the *x* scale +* **x2** - the ending horizontal position; bound to the *x* scale + +If neither the **x1** nor **x2** option is specified, the **x** option may be specified as shorthand to apply an implicit [stackX transform](#plotstackxstack-options); this is the typical configuration for a horizontal bar chart with bars aligned at *x* = 0. If the **x** option is not specified, it defaults to the identity function. If *options* is undefined, then it defaults to **x2** as the identity function and **y** as the index of data; this allows an array of numbers to be passed to Plot.barX to make a quick sequential bar chart. + +If an **interval** is specified, such as d3.utcDay, **x1** and **x2** can be derived from **x**: *interval*.floor(*x*) is invoked for each *x* to produce *x1*, and *interval*.offset(*x1*) is invoked for each *x1* to produce *x2*. If the interval is specified as a number *n*, *x1* and *x2* are taken as the two consecutive multiples of *n* that bracket *x*. + +In addition to the [standard bar channels](#bar), the following optional channels are supported: + +* **y** - the vertical position; bound to the *y* scale, which must be *band* + +If the **y** channel is not specified, the bar will span the full vertical extent of the plot (or facet). + +#### Plot.barY(*data*, *options*) + +```js +Plot.barY(alphabet, {x: "letter", y: "frequency"}) +``` + +Returns a new vertical bar↕︎ with the given *data* and *options*. The following channels are required: + +* **y1** - the starting vertical position; bound to the *y* scale +* **y2** - the ending vertical position; bound to the *y* scale + +If neither the **y1** nor **y2** option is specified, the **y** option may be specified as shorthand to apply an implicit [stackY transform](#plotstackystack-options); this is the typical configuration for a vertical bar chart with bars aligned at *y* = 0. If the **y** option is not specified, it defaults to the identity function. If *options* is undefined, then it defaults to **y2** as the identity function and **x** as the index of data; this allows an array of numbers to be passed to Plot.barY to make a quick sequential bar chart. + +If an **interval** is specified, such as d3.utcDay, **y1** and **y2** can be derived from **y**: *interval*.floor(*y*) is invoked for each *y* to produce *y1*, and *interval*.offset(*y1*) is invoked for each *y1* to produce *y2*. If the interval is specified as a number *n*, *y1* and *y2* are taken as the two consecutive multiples of *n* that bracket *y*. + +In addition to the [standard bar channels](#bar), the following optional channels are supported: + +* **x** - the horizontal position; bound to the *x* scale, which must be *band* + +If the **x** channel is not specified, the bar will span the full horizontal extent of the plot (or facet). + +### Box + +[a boxplot of Michelson’s 1879 measurements of the speed of light](https://observablehq.com/@observablehq/plot-box) + +[Source](./src/marks/box.js) · [Examples](https://observablehq.com/@observablehq/plot-box) · Draws either horizontal boxplots where *x* is quantitative and *y* is ordinal (if present) or vertical boxplots where *y* is quantitative and *x* is ordinal (if present). Boxplots are often used to visualize one-dimensional distributions as an alternative to a histogram. (See also the [bin transform](#bin).) + +The box mark is a composite mark consisting of four marks: + +* a [rule](#rule) representing the extreme values (not including outliers) +* a [bar](#bar) representing the interquartile range (trimmed to the data) +* a [tick](#tick) represent the median value, and +* a [dot](#dot) representing outliers, if any + +The given *options* are passed through to these underlying marks, with the exception of the following options: + +* **fill** - the fill color of the bar; defaults to gray +* **fillOpacity** - the fill opacity of the bar; defaults to 1 +* **stroke** - the stroke color of the rule, tick, and dot; defaults to *currentColor* +* **strokeOpacity** - the stroke opacity of the rule, tick, and dot; defaults to 1 +* **strokeWidth** - the stroke width of the tick; defaults to 1 + +#### Plot.boxX(*data*, *options*) + +```js +Plot.boxX(simpsons.map(d => d.imdb_rating)) +``` + +Returns a horizontal boxplot mark. If the **x** option is not specified, it defaults to the identity function, as when *data* is an array of numbers. If the **y** option is not specified, it defaults to null; if the **y** option is specified, it should represent an ordinal (discrete) value. + +#### Plot.boxY(*data*, *options*) + +```js +Plot.boxY(simpsons.map(d => d.imdb_rating)) +``` + +Returns a vertical boxplot mark. If the **y** option is not specified, it defaults to the identity function, as when *data* is an array of numbers. If the **x** option is not specified, it defaults to null; if the **x** option is specified, it should represent an ordinal (discrete) value. + +### Cell + +[a heatmap](https://observablehq.com/@observablehq/plot-cell) + +[Source](./src/marks/cell.js) · [Examples](https://observablehq.com/@observablehq/plot-cell) · Draws rectangles where both *x* and *y* are ordinal, typically in conjunction with a *fill* channel to encode value. Cells are often used in conjunction with a [group transform](#group). If both dimensions are temporal or quantitative, as in a heatmap, use the [rect mark](#rect) with the [bin transform](#bin) instead. + +In addition to the [standard mark options](#marks), including insets and rounded corners, the following optional channels are supported: + +* **x** - the horizontal position; bound to the *x* scale, which must be *band* +* **y** - the vertical position; bound to the *y* scale, which must be *band* + +If the **x** channel is not specified, the cell will span the full horizontal extent of the plot (or facet). Likewise if the **y** channel is not specified, the cell will span the full vertical extent of the plot (or facet). Typically either *x*, *y*, or both are specified; see [Plot.frame](#frame) if you want a simple frame decoration around the plot. + +The **stroke** defaults to none. The **fill** defaults to currentColor if the stroke is none, and to none otherwise. + +#### Plot.cell(*data*, *options*) + +```js +Plot.cell(simpsons, {x: "number_in_season", y: "season", fill: "imdb_rating"}) +``` + +Returns a new cell with the given *data* and *options*. If neither the **x** nor **y** options are specified, *data* is assumed to be an array of pairs [[*x₀*, *y₀*], [*x₁*, *y₁*], [*x₂*, *y₂*], …] such that **x** = [*x₀*, *x₁*, *x₂*, …] and **y** = [*y₀*, *y₁*, *y₂*, …]. + +#### Plot.cellX(*data*, *options*) + +```js +Plot.cellX(simpsons.map(d => d.imdb_rating)) +``` + +Equivalent to [Plot.cell](#plotcelldata-options), except that if the **x** option is not specified, it defaults to [0, 1, 2, …], and if the **fill** option is not specified and **stroke** is not a channel, the fill defaults to the identity function and assumes that *data* = [*x₀*, *x₁*, *x₂*, …]. + +#### Plot.cellY(*data*, *options*) + +```js +Plot.cellY(simpsons.map(d => d.imdb_rating)) +``` + +Equivalent to [Plot.cell](#plotcelldata-options), except that if the **y** option is not specified, it defaults to [0, 1, 2, …], and if the **fill** option is not specified and **stroke** is not a channel, the fill defaults to the identity function and assumes that *data* = [*y₀*, *y₁*, *y₂*, …]. + +### Dot + +[a scatterplot](https://observablehq.com/@observablehq/plot-dot) + +[Source](./src/marks/dot.js) · [Examples](https://observablehq.com/@observablehq/plot-dot) · Draws circles, or other symbols, as in a scatterplot. + +In addition to the [standard mark options](#marks), the following optional channels are supported: + +* **x** - the horizontal position; bound to the *x* scale +* **y** - the vertical position; bound to the *y* scale +* **r** - the radius (area); bound to the *radius* scale, which defaults to *sqrt* +* **rotate** - the rotation angle in degrees clockwise +* **symbol** - the categorical symbol; bound to the *symbol* scale + +If either of the **x** or **y** channels are not specified, the corresponding position is controlled by the **frameAnchor** option. + +The following dot-specific constant options are also supported: + +* **r** - the effective radius (length); a number in pixels +* **rotate** - the rotation angle in degrees clockwise; defaults to 0 +* **symbol** - the categorical symbol; defaults to circle +* **frameAnchor** - the [frame anchor](#frameanchor); defaults to *middle* + +The **r** option can be specified as either a channel or constant. When the radius is specified as a number, it is interpreted as a constant; otherwise it is interpreted as a channel. The radius defaults to 4.5 pixels when using the **symbol** channel, and otherwise 3 pixels. Dots with a nonpositive radius are not drawn. + +The **stroke** defaults to none. The **fill** defaults to currentColor if the stroke is none, and to none otherwise. The **strokeWidth** defaults to 1.5. The **rotate** and **symbol** options can be specified as either channels or constants. When rotate is specified as a number, it is interpreted as a constant; otherwise it is interpreted as a channel. When symbol is a valid symbol name or symbol object (implementing the draw method), it is interpreted as a constant; otherwise it is interpreted as a channel. + +The built-in **symbol** types are: *circle*, *cross*, *diamond*, *square*, *star*, *triangle*, and *wye* (for fill) and *circle*, *plus*, *times*, *triangle2*, *asterisk*, *square2*, and *diamond2* (for stroke, based on [Heman Robinson’s research](https://www.tandfonline.com/doi/abs/10.1080/10618600.2019.1637746)). You can also specify a D3 or custom symbol type as an object that implements the [*symbol*.draw(*context*, *size*)](https://github.com/d3/d3-shape/blob/main/README.md#custom-symbol-types) method. + +Dots are drawn in input order, with the last data drawn on top. If sorting is needed, say to mitigate overplotting by drawing the smallest dots on top, consider a [sort and reverse transform](#transforms). + +#### Plot.dot(*data*, *options*) + +```js +Plot.dot(sales, {x: "units", y: "fruit"}) +``` + +Returns a new dot with the given *data* and *options*. If neither the **x** nor **y** nor **frameAnchor** options are specified, *data* is assumed to be an array of pairs [[*x₀*, *y₀*], [*x₁*, *y₁*], [*x₂*, *y₂*], …] such that **x** = [*x₀*, *x₁*, *x₂*, …] and **y** = [*y₀*, *y₁*, *y₂*, …]. + +#### Plot.dotX(*data*, *options*) + +```js +Plot.dotX(cars.map(d => d["economy (mpg)"])) +``` + +Equivalent to [Plot.dot](#plotdotdata-options) except that if the **x** option is not specified, it defaults to the identity function and assumes that *data* = [*x₀*, *x₁*, *x₂*, …]. + +#### Plot.dotY(*data*, *options*) + +```js +Plot.dotY(cars.map(d => d["economy (mpg)"])) +``` + +Equivalent to [Plot.dot](#plotdotdata-options) except that if the **y** option is not specified, it defaults to the identity function and assumes that *data* = [*y₀*, *y₁*, *y₂*, …]. + +### Image + +[a scatterplot of Presidential portraits](https://observablehq.com/@observablehq/plot-image) + +[Source](./src/marks/image.js) · [Examples](https://observablehq.com/@observablehq/plot-image) · Draws images as in a scatterplot. The required **src** option specifies the URL (or relative path) of each image. If **src** is specified as a string that starts with a dot, slash, or URL protocol (*e.g.*, “https:”) it is assumed to be a constant; otherwise it is interpreted as a channel. + +In addition to the [standard mark options](#marks), the following optional channels are supported: + +* **x** - the horizontal position; bound to the *x* scale +* **y** - the vertical position; bound to the *y* scale +* **width** - the image width (in pixels) +* **height** - the image height (in pixels) + +If either of the **x** or **y** channels are not specified, the corresponding position is controlled by the **frameAnchor** option. + +The **width** and **height** options default to 16 pixels and can be specified as either a channel or constant. When the width or height is specified as a number, it is interpreted as a constant; otherwise it is interpreted as a channel. Images with a nonpositive width or height are not drawn. If a **width** is specified but not a **height**, or *vice versa*, the one defaults to the other. Images do not support either a fill or a stroke. + +The following image-specific constant options are also supported: + +* **frameAnchor** - the [frame anchor](#frameanchor); defaults to *middle* +* **preserveAspectRatio** - the [aspect ratio](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/preserveAspectRatio); defaults to “xMidYMid meet” +* **crossOrigin** - the [cross-origin](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/crossorigin) behavior + +To crop the image instead of scaling it to fit, set **preserveAspectRatio** to “xMidYMid slice”. + +Images are drawn in input order, with the last data drawn on top. If sorting is needed, say to mitigate overplotting, consider a [sort and reverse transform](#transforms). + +#### Plot.image(*data*, *options*) + +```js +Plot.image(presidents, {x: "inauguration", y: "favorability", src: "portrait"}) +``` + +Returns a new image with the given *data* and *options*. If neither the **x** nor **y** nor **frameAnchor** options are specified, *data* is assumed to be an array of pairs [[*x₀*, *y₀*], [*x₁*, *y₁*], [*x₂*, *y₂*], …] such that **x** = [*x₀*, *x₁*, *x₂*, …] and **y** = [*y₀*, *y₁*, *y₂*, …]. + +### Line + +[a line chart](https://observablehq.com/@observablehq/plot-line) + +[Source](./src/marks/line.js) · [Examples](https://observablehq.com/@observablehq/plot-line) · Draws two-dimensional lines as in a line chart. + +The following channels are required: + +* **x** - the horizontal position; bound to the *x* scale +* **y** - the vertical position; bound to the *y* scale + +In addition to the [standard mark options](#marks), the following optional channels are supported: + +* **z** - a categorical value to group data into series + +By default, the data is assumed to represent a single series (a single value that varies over time, *e.g.*). If the **z** channel is specified, data is grouped by *z* to form separate series. Typically *z* is a categorical value such as a series name. If **z** is not specified, it defaults to **stroke** if a channel, or **fill** if a channel. + +The **fill** defaults to none. The **stroke** defaults to currentColor if the fill is none, and to none otherwise. If the stroke is defined as a channel, the line will be broken into contiguous overlapping segments when the stroke color changes; the stroke color will apply to the interval spanning the current data point and the following data point. This behavior also applies to the **fill**, **fillOpacity**, **strokeOpacity**, **strokeWidth**, **opacity**, **href**, **title**, and **ariaLabel** channels. When any of these channels are used, setting an explicit **z** channel (possibly to null) is strongly recommended. The **strokeWidth** defaults to 1.5, the **strokeLinecap** and **strokeLinejoin** default to *round*, and the **strokeMiterlimit** defaults to 1. + +Points along the line are connected in input order. Likewise, if there are multiple series via the *z*, *fill*, or *stroke* channel, the series are drawn in input order such that the last series is drawn on top. Typically, the data is already in sorted order, such as chronological for time series; if sorting is needed, consider a [sort transform](#transforms). + +The line mark supports [curve options](#curves) to control interpolation between points, and [marker options](#markers) to add a marker (such as a dot or an arrowhead) on each of the control points. If any of the *x* or *y* values are invalid (undefined, null, or NaN), the line will be interrupted, resulting in a break that divides the line shape into multiple segments. (See [d3-shape’s *line*.defined](https://github.com/d3/d3-shape/blob/master/README.md#line_defined) for more.) If a line segment consists of only a single point, it may appear invisible unless rendered with rounded or square line caps. In addition, some curves such as *cardinal-open* only render a visible segment if it contains multiple points. + +#### Plot.line(*data*, *options*) + +```js +Plot.line(aapl, {x: "Date", y: "Close"}) +``` + +Returns a new line with the given *data* and *options*. If neither the **x** nor **y** options are specified, *data* is assumed to be an array of pairs [[*x₀*, *y₀*], [*x₁*, *y₁*], [*x₂*, *y₂*], …] such that **x** = [*x₀*, *x₁*, *x₂*, …] and **y** = [*y₀*, *y₁*, *y₂*, …]. + +#### Plot.lineX(*data*, *options*) + +```js +Plot.lineX(aapl.map(d => d.Close)) +``` + +Similar to [Plot.line](#plotlinedata-options) except that if the **x** option is not specified, it defaults to the identity function and assumes that *data* = [*x₀*, *x₁*, *x₂*, …]. If the **y** option is not specified, it defaults to [0, 1, 2, …]. + +If the **interval** option is specified, the [binY transform](#bin) is implicitly applied to the specified *options*. The reducer of the output *x* channel may be specified via the **reduce** option, which defaults to *first*. To default to zero instead of showing gaps in data, as when the observed value represents a quantity, use the *sum* reducer. + +```js +Plot.lineX(observations, {y: "date", x: "temperature", interval: d3.utcDay}) +``` + +The **interval** option is recommended to “regularize” sampled data; for example, if your data represents timestamped temperature measurements and you expect one sample per day, use d3.utcDay as the interval. + +#### Plot.lineY(*data*, *options*) + +```js +Plot.lineY(aapl.map(d => d.Close)) +``` + +Similar to [Plot.line](#plotlinedata-options) except that if the **y** option is not specified, it defaults to the identity function and assumes that *data* = [*y₀*, *y₁*, *y₂*, …]. If the **x** option is not specified, it defaults to [0, 1, 2, …]. + +If the **interval** option is specified, the [binX transform](#bin) is implicitly applied to the specified *options*. The reducer of the output *y* channel may be specified via the **reduce** option, which defaults to *first*. To default to zero instead of showing gaps in data, as when the observed value represents a quantity, use the *sum* reducer. + +```js +Plot.lineY(observations, {x: "date", y: "temperature", interval: d3.utcDay}) +``` + +The **interval** option is recommended to “regularize” sampled data; for example, if your data represents timestamped temperature measurements and you expect one sample per day, use d3.utcDay as the interval. + +### Link + +[a chart with links](https://observablehq.com/@observablehq/plot-link) + +[Source](./src/marks/link.js) · [Examples](https://observablehq.com/@observablehq/plot-link) · Draws line segments (or curves) connecting pairs of points. + +The following channels are required: + +* **x1** - the starting horizontal position; bound to the *x* scale +* **y1** - the starting vertical position; bound to the *y* scale +* **x2** - the ending horizontal position; bound to the *x* scale +* **y2** - the ending vertical position; bound to the *y* scale + +For vertical or horizontal links, the **x** option can be specified as shorthand for **x1** and **x2**, and the **y** option can be specified as shorthand for **y1** and **y2**, respectively. + +The link mark supports the [standard mark options](#marks). The **stroke** defaults to currentColor. The **fill** defaults to none. The **strokeWidth** and **strokeMiterlimit** default to one. + +The link mark supports [curve options](#curves) to control interpolation between points, and [marker options](#markers) to add a marker (such as a dot or an arrowhead) on each of the control points. Since a link always has two points by definition, only the following curves (or a custom curve) are recommended: *linear*, *step*, *step-after*, *step-before*, *bump-x*, or *bump-y*. Note that the *linear* curve is incapable of showing a fill since a straight line has zero area. For a curved link, you can use a bent [arrow](#arrow) (with no arrowhead, if desired). + +#### Plot.link(*data*, *options*) + +```js +Plot.link(inequality, {x1: "POP_1980", y1: "R90_10_1980", x2: "POP_2015", y2: "R90_10_2015"}) +``` + +Returns a new link with the given *data* and *options*. + +### Rect + +[a histogram](https://observablehq.com/@observablehq/plot-rect) + +[Source](./src/marks/rect.js) · [Examples](https://observablehq.com/@observablehq/plot-rect) · Draws rectangles where both *x* and *y* are quantitative as in a histogram. Both pairs of quantitative values represent lower and upper bounds, and often one of the lower bounds is implicitly zero. If one of the dimensions is ordinal, use a [bar](#bar) instead; if both dimensions are ordinal, use a [cell](#cell) instead. Rects are often used in conjunction with a [bin transform](#bin). + +The following channels are optional: + +* **x1** - the starting horizontal position; bound to the *x* scale +* **y1** - the starting vertical position; bound to the *y* scale +* **x2** - the ending horizontal position; bound to the *x* scale +* **y2** - the ending vertical position; bound to the *y* scale + +Typically either **x1** and **x2** are specified, or **y1** and **y2**, or both. + +If an **interval** is specified, such as d3.utcDay, **x1** and **x2** can be derived from **x**: *interval*.floor(*x*) is invoked for each *x* to produce *x1*, and *interval*.offset(*x1*) is invoked for each *x1* to produce *x2*. The same is true for *y*, *y1*, and *y2*, respectively. If the interval is specified as a number *n*, *x1* and *x2* are taken as the two consecutive multiples of *n* that bracket *x*. The interval may be specified either as as {x, interval} or x: {value, interval} to apply different intervals to x and y. + +The rect mark supports the [standard mark options](#marks), including insets and rounded corners. The **stroke** defaults to none. The **fill** defaults to currentColor if the stroke is none, and to none otherwise. + +#### Plot.rect(*data*, *options*) + +```js +Plot.rect(athletes, Plot.bin({fill: "count"}, {x: "weight", y: "height"})) +``` + +Returns a new rect with the given *data* and *options*. + +#### Plot.rectX(*data*, *options*) + +```js +Plot.rectX(athletes, Plot.binY({x: "count"}, {y: "weight"})) +``` + +Equivalent to [Plot.rect](#plotrectdata-options), except that if neither the **x1** nor **x2** option is specified, the **x** option may be specified as shorthand to apply an implicit [stackX transform](#plotstackxstack-options); this is the typical configuration for a histogram with rects aligned at *x* = 0. If the **x** option is not specified, it defaults to the identity function. + +#### Plot.rectY(*data*, *options*) + +```js +Plot.rectY(athletes, Plot.binX({y: "count"}, {x: "weight"})) +``` + +Equivalent to [Plot.rect](#plotrectdata-options), except that if neither the **y1** nor **y2** option is specified, the **y** option may be specified as shorthand to apply an implicit [stackY transform](#plotstackystack-options); this is the typical configuration for a histogram with rects aligned at *y* = 0. If the **y** option is not specified, it defaults to the identity function. + +### Rule + +[a line chart with a highlighted rule](https://observablehq.com/@observablehq/plot-rule) + +[Source](./src/marks/rule.js) · [Examples](https://observablehq.com/@observablehq/plot-rule) · Draws an orthogonal line at the given horizontal ([Plot.ruleX](#plotrulexdata-options)) or vertical ([Plot.ruleY](#plotruleydata-options)) position, either across the entire plot (or facet) or bounded in the opposite dimension. Rules are often used with hard-coded data to annotate special values such as *y* = 0, though they can also be used to visualize data as in a lollipop chart. + +For the required channels, see [Plot.ruleX](#plotrulexdata-options) and [Plot.ruleY](#plotruleydata-options). The rule mark supports the [standard mark options](#marks), including insets along its secondary dimension. The **stroke** defaults to currentColor. + +#### Plot.ruleX(*data*, *options*) + +```js +Plot.ruleX([0]) // as annotation +``` +```js +Plot.ruleX(alphabet, {x: "letter", y: "frequency"}) // like barY +``` + +Returns a new rule↕︎ with the given *data* and *options*. In addition to the [standard mark options](#marks), the following channels are optional: + +* **x** - the 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 + +If the **x** option is not specified, it defaults to the identity function and assumes that *data* = [*x₀*, *x₁*, *x₂*, …]. If a **y** option is specified, it is shorthand for the **y2** option with **y1** equal to zero; this is the typical configuration for a vertical lollipop chart with rules aligned at *y* = 0. If the **y1** channel is not specified, the rule will start at the top of the plot (or facet). If the **y2** channel is not specified, the rule will end at the bottom of the plot (or facet). + +If an **interval** is specified, such as d3.utcDay, **y1** and **y2** can be derived from **y**: *interval*.floor(*y*) is invoked for each *y* to produce *y1*, and *interval*.offset(*y1*) is invoked for each *y1* to produce *y2*. If the interval is specified as a number *n*, *y1* and *y2* are taken as the two consecutive multiples of *n* that bracket *y*. + +#### Plot.ruleY(*data*, *options*) + +```js +Plot.ruleY([0]) // as annotation +``` +```js +Plot.ruleY(alphabet, {y: "letter", x: "frequency"}) // like barX +``` + +Returns a new rule↔︎ with the given *data* and *options*. In addition to the [standard mark options](#marks), the following channels are optional: + +* **y** - the vertical position; bound to the *y* scale +* **x1** - the starting horizontal position; bound to the *x* scale +* **x2** - the ending horizontal position; bound to the *x* scale + +If the **y** option is not specified, it defaults to the identity function and assumes that *data* = [*y₀*, *y₁*, *y₂*, …]. If the **x** option is specified, it is shorthand for the **x2** option with **x1** equal to zero; this is the typical configuration for a horizontal lollipop chart with rules aligned at *x* = 0. If the **x1** channel is not specified, the rule will start at the left edge of the plot (or facet). If the **x2** channel is not specified, the rule will end at the right edge of the plot (or facet). + +If an **interval** is specified, such as d3.utcDay, **x1** and **x2** can be derived from **x**: *interval*.floor(*x*) is invoked for each *x* to produce *x1*, and *interval*.offset(*x1*) is invoked for each *x1* to produce *x2*. If the interval is specified as a number *n*, *x1* and *x2* are taken as the two consecutive multiples of *n* that bracket *x*. + +### Text + +[a bar chart with text labels](https://observablehq.com/@observablehq/plot-text) + +[Source](./src/marks/text.js) · [Examples](https://observablehq.com/@observablehq/plot-text) · Draws a text label at the specified position. + +The following channels are required: + +* **text** - the text contents (a string, possibly with multiple lines) + +If the **text** contains `\n`, `\r\n`, or `\r`, it will be rendered as multiple lines via tspan elements. If the **text** is specified as numbers or dates, a default formatter will automatically be applied, and the **fontVariant** will default to tabular-nums instead of normal. For more control over number and date formatting, consider [*number*.toLocaleString](https://observablehq.com/@mbostock/number-formatting), [*date*.toLocaleString](https://observablehq.com/@mbostock/date-formatting), [d3-format](https://github.com/d3/d3-format), or [d3-time-format](https://github.com/d3/d3-time-format). If **text** is not specified, it defaults to the identity function for primitive data (such as numbers, dates, and strings), and to the zero-based index [0, 1, 2, …] for objects (so that something identifying is visible by default). + +In addition to the [standard mark options](#marks), the following optional channels are supported: + +* **x** - the horizontal position; bound to the *x* scale +* **y** - the vertical position; bound to the *y* scale +* **fontSize** - the font size in pixels +* **rotate** - the rotation angle in degrees clockwise + +If either of the **x** or **y** channels are not specified, the corresponding position is controlled by the **frameAnchor** option. + +The following text-specific constant options are also supported: + +* **textAnchor** - the [text anchor](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/text-anchor) for horizontal position; start, end, or middle +* **lineAnchor** - the line anchor for vertical position; top, bottom, or middle +* **lineHeight** - the line height in ems; defaults to 1 +* **lineWidth** - the line width in ems, for wrapping; defaults to Infinity +* **monospace** - if true, changes the default fontFamily and metrics to monospace +* **fontFamily** - the font name; defaults to [system-ui](https://drafts.csswg.org/css-fonts-4/#valdef-font-family-system-ui) +* **fontSize** - the font size in pixels; defaults to 10 +* **fontStyle** - the [font style](https://developer.mozilla.org/en-US/docs/Web/CSS/font-style); defaults to normal +* **fontVariant** - the [font variant](https://developer.mozilla.org/en-US/docs/Web/CSS/font-variant); defaults to normal +* **fontWeight** - the [font weight](https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight); defaults to normal +* **frameAnchor** - the [frame anchor](#frameanchor); defaults to *middle* +* **rotate** - the rotation angle in degrees clockwise; defaults to 0 + +If a **lineWidth** is specified, input text values will be wrapped as needed to fit while preserving existing newlines. The line wrapping implementation is rudimentary; for non-ASCII, non-U.S. English text, or for when a different font is used, you may get better results by hard-wrapping the text yourself (by supplying newlines in the input). If the **monospace** option is truthy, the default **fontFamily** changes to “ui-monospace, monospace”, and the **lineWidth** option is interpreted as characters (ch) rather than ems. + +The **fontSize** and **rotate** options can be specified as either channels or constants. When fontSize or rotate is specified as a number, it is interpreted as a constant; otherwise it is interpreted as a channel. + +If the **frameAnchor** option is not specified, then **textAnchor** and **lineAnchor** default to middle. Otherwise, **textAnchor** defaults to start if **frameAnchor** is on the left, end if **frameAnchor** is on the right, and otherwise middle. Similarly, **lineAnchor** defaults to top if **frameAnchor** is on the top, bottom if **frameAnchor** is on the bottom, and otherwise middle. + +The **paintOrder** option defaults to “stroke” and the **strokeWidth** option defaults to 3. By setting **fill** to the foreground color and **stroke** to the background color (such as black and white, respectively), you can surround text with a “halo” which may improve legibility against a busy background. + +#### Plot.text(*data*, *options*) + +Returns a new text mark with the given *data* and *options*. If neither the **x** nor **y** nor **frameAnchor** options are specified, *data* is assumed to be an array of pairs [[*x₀*, *y₀*], [*x₁*, *y₁*], [*x₂*, *y₂*], …] such that **x** = [*x₀*, *x₁*, *x₂*, …] and **y** = [*y₀*, *y₁*, *y₂*, …]. + +#### Plot.textX(*data*, *options*) + +Equivalent to [Plot.text](#plottextdata-options), except **x** defaults to the identity function and assumes that *data* = [*x₀*, *x₁*, *x₂*, …]. + +#### Plot.textY(*data*, *options*) + +Equivalent to [Plot.text](#plottextdata-options), except **y** defaults to the identity function and assumes that *data* = [*y₀*, *y₁*, *y₂*, …]. + +### Tick + +[a barcode plot](https://observablehq.com/@observablehq/plot-tick) + +[Source](./src/marks/tick.js) · [Examples](https://observablehq.com/@observablehq/plot-tick) · Draws an orthogonal line at the given horizontal ([Plot.tickX](#plottickxdata-options)) or vertical ([Plot.tickY](#plottickydata-options)) position, with an optional secondary position dimension along a band scale. (If the secondary dimension is quantitative instead of ordinal, use a [rule](#rule).) Ticks are often used to visualize distributions as in a “barcode” plot. + +For the required channels, see [Plot.tickX](#plottickxdata-options) and [Plot.tickY](#plottickydata-options). The tick mark supports the [standard mark options](#marks), including insets. The **stroke** defaults to currentColor. + +#### Plot.tickX(*data*, *options*) + +```js +Plot.tickX(stateage, {x: "population", y: "age"}) +``` + +Returns a new tick↕︎ with the given *data* and *options*. The following channels are required: + +* **x** - the horizontal position; bound to the *x* scale + +The following optional channels are supported: + +* **y** - the vertical position; bound to the *y* scale, which must be *band* + +If the **y** channel is not specified, the tick will span the full vertical extent of the plot (or facet). + +#### Plot.tickY(*data*, *options*) + +```js +Plot.tickY(stateage, {y: "population", x: "age"}) +``` + +Returns a new tick↔︎ with the given *data* and *options*. The following channels are required: + +* **y** - the vertical position; bound to the *y* scale + +The following optional channels are supported: + +* **x** - the horizontal position; bound to the *x* scale, which must be *band* + +If the **x** channel is not specified, the tick will span the full vertical extent of the plot (or facet). + +### Vector + +[a vector field](https://observablehq.com/@observablehq/plot-vector) + +[Source](./src/marks/vector.js) · [Examples](https://observablehq.com/@observablehq/plot-vector) · Draws little arrows as in a vector field. + +In addition to the [standard mark options](#marks), the following optional channels are supported: + +* **x** - the horizontal position; bound to the *x* scale +* **y** - the vertical position; bound to the *y* scale +* **length** - the length in pixels; bound to the *length* scale; defaults to 12 +* **rotate** - the rotation angle in degrees clockwise; defaults to 0 + +If either of the **x** or **y** channels are not specified, the corresponding position is controlled by the **frameAnchor** option. + +The following options are also supported: + +* **anchor** - one of *start*, *middle*, or *end*; defaults to *middle* +* **frameAnchor** - the [frame anchor](#frameanchor); defaults to *middle* + +If the **anchor** is *start*, the arrow will start at the given *xy* position and point in the direction given by the rotation angle. If the **anchor** is *end*, the arrow will maintain the same orientation, but be positioned such that it ends in the given *xy* position. If the **anchor** is *middle*, the arrow will be likewise be positioned such that its midpoint intersects the given *xy* position. + +If the **x** channel is not specified, vectors will be horizontally centered in the plot (or facet). Likewise if the **y** channel is not specified, vectors will be vertically centered in the plot (or facet). Typically either *x*, *y*, or both are specified. + +The **rotate** and **length** options can be specified as either channels or constants. When specified as a number, it is interpreted as a constant; otherwise it is interpreted as a channel. The length defaults to 12 pixels, and the rotate defaults to 0 degrees (pointing up↑). Vectors with a negative length will be drawn inverted. Positive angles proceed clockwise from noon. + +The **stroke** defaults to currentColor. The **strokeWidth** defaults to 1.5, and the **strokeLinecap** defaults to *round*. + +Vectors are drawn in input order, with the last data drawn on top. If sorting is needed, say to mitigate overplotting by drawing the smallest vectors on top, consider a [sort and reverse transform](#transforms). + +#### Plot.vector(*data*, *options*) + +```js +Plot.vector(wind, {x: "longitude", y: "latitude", length: "speed", rotate: "direction"}) +``` + +Returns a new vector with the given *data* and *options*. If neither the **x** nor **y** options are specified, *data* is assumed to be an array of pairs [[*x₀*, *y₀*], [*x₁*, *y₁*], [*x₂*, *y₂*], …] such that **x** = [*x₀*, *x₁*, *x₂*, …] and **y** = [*y₀*, *y₁*, *y₂*, …]. + +#### Plot.vectorX(*data*, *options*) + +Equivalent to Plot.vector except that if the **x** option is not specified, it defaults to the identity function and assumes that *data* = [*x₀*, *x₁*, *x₂*, …]. + +#### Plot.vectorY(*data*, *options*) + +Equivalent to Plot.vector except that if the **y** option is not specified, it defaults to the identity function and assumes that *data* = [*y₀*, *y₁*, *y₂*, …]. + +## Decorations + +Decorations are static marks that do not represent data. Currently this includes only [Plot.frame](#frame), although internally Plot’s axes are implemented as decorations and may in the future be exposed here for more flexible configuration. + +### Frame + +[a faceted scatterplot with a frame around each facet](https://observablehq.com/@observablehq/plot-frame) + +[Source](./src/marks/frame.js) · [Examples](https://observablehq.com/@observablehq/plot-frame) · Draws a simple frame around the entire plot (or facet). + +The frame mark supports the [standard mark options](#marks), but does not accept any data or support channels. The default **stroke** is currentColor, and the default **fill** is none. + +#### Plot.frame(*options*) + +```js +Plot.frame({stroke: "red"}) +``` + +Returns a new frame with the specified *options*. + +## Transforms + +Plot’s transforms provide a convenient mechanism for transforming data as part of a plot specification. All marks support the following basic transforms: + +* **filter** - filters data according to the specified accessor or values +* **sort** - sorts data according to the specified comparator, accessor, or values +* **reverse** - reverses the sorted (or if not sorted, the input) data order + +For example, to draw bars only for letters that commonly form vowels: + +```js +Plot.barY(alphabet, {filter: d => /[aeiou]/i.test(d.letter), x: "letter", y: "frequency"}) +``` + +The **filter** transform is similar to filtering the data with [*array*.filter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter), except that it will preserve [faceting](#faceting) and will not affect inferred [scale domains](#scale-options); domains are inferred from the unfiltered channel values. + +```js +Plot.barY(alphabet.filter(d => /[aeiou]/i.test(d.letter)), {x: "letter", y: "frequency"}) +``` + +Together the **sort** and **reverse** transforms allow control over *z*-order, which can be important when addressing overplotting. If the sort option is a function but does not take exactly one argument, it is assumed to be a [comparator function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#description); otherwise, the sort option is interpreted as a channel value definition and thus may be either as a column name, accessor function, or array of values. + +For greater control, you can also implement a [custom transform function](#custom-transforms): + +* **transform** - a function that returns transformed *data* and *index* + +The basic transforms are composable: the *filter* transform is applied first, then *sort*, then *reverse*. If a custom *transform* option is specified directly, it supersedes any basic transforms (*i.e.*, the *filter*, *sort* and *reverse* options are ignored). However, the *transform* option is rarely used directly; instead an option transform is used. These option transforms automatically compose with the basic *filter*, *sort* and *reverse* transforms. + +Plot’s option transforms, listed below, do more than populate the **transform** function: they derive new mark options and channels. These transforms take a mark’s *options* object (and possibly transform-specific options as the first argument) and return a new, transformed, *options*. Option transforms are composable: you can pass an *options* objects through more than one transform before passing it to a mark. You can also reuse the same transformed *options* on multiple marks. + +The *filter*, *sort* and *reverse* transforms are also available as functions, allowing the order of operations to be specified explicitly. For example, sorting before binning results in sorted data inside bins, whereas sorting after binning results affects the *z*-order of rendered marks. + +#### Plot.sort(*order*, *options*) + +```js +Plot.sort("body_mass_g", options) // show data in ascending body mass order +``` + +Sorts the data by the specified *order*, which can be an accessor function, a comparator function, or a channel value definition such as a field name. + +#### Plot.shuffle(*options*) + +```js +Plot.shuffle(options) // show data in random order +``` + +Shuffles the data randomly. If a *seed* option is specified, a linear congruential generator with the given seed is used to generate random numbers deterministically; otherwise, Math.random is used. + +#### Plot.reverse(*options*) + +```js +Plot.reverse(options) // reverse the input order +``` + +Reverses the order of the data. + +#### Plot.filter(*test*, *options*) + +```js +Plot.filter(d => d.body_mass_g > 3000, options) // show data whose body mass is greater than 3kg +``` + +Filters the data given the specified *test*. The test can be given as an accessor function (which receives the datum and index), or as a channel value definition such as a field name; truthy values are retained. + +### Bin + +[a histogram of athletes by weight](https://observablehq.com/@observablehq/plot-bin) + +[Source](./src/transforms/bin.js) · [Examples](https://observablehq.com/@observablehq/plot-bin) · Aggregates continuous data—quantitative or temporal values such as temperatures or times—into discrete bins and then computes summary statistics for each bin such as a count or sum. The bin transform is like a continuous [group transform](#group) and is often used to make histograms. There are separate transforms depending on which dimensions need binning: [Plot.binX](#plotbinxoutputs-options) for *x*; [Plot.binY](#plotbinyoutputs-options) for *y*; and [Plot.bin](#plotbinoutputs-options) for both *x* and *y*. + +Given input *data* = [*d₀*, *d₁*, *d₂*, …], by default the resulting binned data is an array of arrays where each inner array is a subset of the input data [[*d₀₀*, *d₀₁*, …], [*d₁₀*, *d₁₁*, …], [*d₂₀*, *d₂₁*, …], …]. Each inner array is in input order. The outer array is in ascending order according to the associated dimension (*x* then *y*). Empty bins are skipped. By specifying a different aggregation method for the *data* output, as described below, you can change how the binned data is computed. The outputs may also include *filter* and *sort* options specified as aggregation methods, and a *reverse* option to reverse the order of generated bins. By default, empty bins are omitted, and non-empty bins are generated in ascending threshold order. + +While it is possible to compute channel values on the binned data by defining channel values as a function, more commonly channel values are computed directly by the bin transform, either implicitly or explicitly. In addition to data, the following channels are automatically aggregated: + +* **x1** - the starting horizontal position of the bin +* **x2** - the ending horizontal position of the bin +* **x** - the horizontal center of the bin +* **y1** - the starting vertical position of the bin +* **y2** - the ending vertical position of the bin +* **y** - the vertical center of the bin +* **z** - the first value of the *z* channel, if any +* **fill** - the first value of the *fill* channel, if any +* **stroke** - the first value of the *stroke* channel, if any + +The **x1**, **x2**, and **x** output channels are only computed by the Plot.binX and Plot.bin transform; similarly the **y1**, **y2**, and **y** output channels are only computed by the Plot.binY and Plot.bin transform. The **x** and **y** output channels are lazy: they are only computed if needed by a downstream mark or transform. Conversely, the *x1* and *x2* outputs default to undefined if *x* is explicitly defined; and the *y1* and *y2* outputs default to undefined if *y* is explicitly defined. + +You can declare additional channels to aggregate by specifying the channel name and desired aggregation method in the *outputs* object which is the first argument to the transform. For example, to use [Plot.binX](#plotbinxoutputs-options) to generate a **y** channel of bin counts as in a frequency histogram: + +```js +Plot.binX({y: "count"}, {x: "culmen_length_mm"}) +``` + +The following aggregation methods are supported: + +* *first* - the first value, in input order +* *last* - the last value, in input order +* *count* - the number of elements (frequency) +* *distinct* - the number of distinct values +* *sum* - the sum of values +* *proportion* - the sum proportional to the overall total (weighted frequency) +* *proportion-facet* - the sum proportional to the facet total +* *min* - the minimum value +* *min-index* - the zero-based index of the minimum value +* *max* - the maximum value +* *max-index* - the zero-based index of the maximum value +* *mean* - the mean value (average) +* *median* - the median value +* *mode* - the value with the most occurrences +* *pXX* - the percentile value, where XX is a number in [00,99] +* *deviation* - the standard deviation +* *variance* - the variance per [Welford’s algorithm](https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Welford's_online_algorithm) +* *x* - the middle the bin’s *x*-extent (when binning on *x*) +* *x1* - the lower bound of the bin’s *x*-extent (when binning on *x*) +* *x2* - the upper bound of the bin’s *x*-extent (when binning on *x*) +* *y* - the middle the bin’s *y*-extent (when binning on *y*) +* *y1* - the lower bound of the bin’s *y*-extent (when binning on *y*) +* *y2* - the upper bound of the bin’s *y*-extent (when binning on *y*) +* a function to be passed the array of values for each bin and the extent of the bin +* an object with a *reduce* method, and optionally a *scope* + +In the last case, the *reduce* method is repeatedly passed three arguments: the index for each bin (an array of integers), the input channel’s array of values, and the extent of the bin (an object {x1, x2, y1, y2}); it must then return the corresponding aggregate value for the bin. If the reducer object’s *scope* is “data”, then the *reduce* method is first invoked for the full data; the return value of the *reduce* method is then made available as a third argument (making the extent the fourth argument). Similarly if the *scope* is “facet”, then the *reduce* method is invoked for each facet, and the resulting reduce value is made available while reducing the facet’s bins. (This optional *scope* is used by the *proportion* and *proportion-facet* reducers.) + +Most aggregation methods require binding the output channel to an input channel; for example, if you want the **y** output channel to be a *sum* (not merely a count), there should be a corresponding **y** input channel specifying which values to sum. If there is not, *sum* will be equivalent to *count*. + +```js +Plot.binX({y: "sum"}, {x: "culmen_length_mm", y: "body_mass_g"}) +``` + +You can control whether a channel is computed before or after binning. If a channel is declared only in *options* (and it is not a special group-eligible channel such as *x*, *y*, *z*, *fill*, or *stroke*), it will be computed after binning and be passed the binned data: each datum is the array of input data corresponding to the current bin. + +```js +Plot.binX({y: "count"}, {x: "economy (mpg)", title: bin => bin.map(d => d.name).join("\n")}) +``` + +This is equivalent to declaring the channel only in *outputs*. + +```js +Plot.binX({y: "count", title: bin => bin.map(d => d.name).join("\n")}, {x: "economy (mpg)"}) +``` + +However, if a channel is declared in both *outputs* and *options*, then the channel in *options* is computed before binning and can then be aggregated using any built-in reducer (or a custom reducer function) during the bin transform. + +```js +Plot.binX({y: "count", title: names => names.join("\n")}, {x: "economy (mpg)", title: "name"}) +``` + +To control how the quantitative dimensions *x* and *y* are divided into bins, the following options are supported: + +* **thresholds** - the threshold values; see below +* **interval** - an alternative method of specifying thresholds +* **domain** - values outside the domain will be omitted +* **cumulative** - if positive, each bin will contain all lesser bins + +These options may be specified either on the *options* or *outputs* object. If the **domain** option is not specified, it defaults to the minimum and maximum of the corresponding dimension (*x* or *y*), possibly niced to match the threshold interval to ensure that the first and last bin have the same width as other bins. If **cumulative** is negative (-1 by convention), each bin will contain all *greater* bins rather than all *lesser* bins, representing the [complementary cumulative distribution](https://en.wikipedia.org/wiki/Cumulative_distribution_function#Complementary_cumulative_distribution_function_.28tail_distribution.29). + +To pass separate binning options for *x* and *y*, the **x** and **y** input channels can be specified as an object with the options above and a **value** option to specify the input channel values. + +```js +Plot.binX({y: "count"}, {x: {thresholds: 20, value: "culmen_length_mm"}}) +``` + +The **thresholds** option may be specified as a named method or a variety of other ways: + +* *auto* (default) - Scott’s rule, capped at 200 +* *freedman-diaconis* - the [Freedman–Diaconis rule](https://en.wikipedia.org/wiki/Freedman–Diaconis_rule) +* *scott* - [Scott’s normal reference rule](https://en.wikipedia.org/wiki/Histogram#Scott.27s_normal_reference_rule) +* *sturges* - [Sturges’ formula](https://en.wikipedia.org/wiki/Histogram#Sturges.27_formula) +* a count (hint) representing the desired number of bins +* an array of *n* threshold values for *n* + 1 bins +* an interval or time interval (for temporal binning; see below) +* a function that returns an array, count, or time interval + +If the **thresholds** option is specified as a function, it is passed three arguments: the array of input values, the domain minimum, and the domain maximum. If a number, [d3.ticks](https://github.com/d3/d3-array/blob/main/README.md#ticks) or [d3.utcTicks](https://github.com/d3/d3-time/blob/master/README.md#ticks) is used to choose suitable nice thresholds. If an interval, it must expose an *interval*.floor(*value*), *interval*.ceil(*value*), *interval*.offset(*value*), and *interval*.range(*start*, *stop*) methods. If the interval is a time interval such as d3.utcDay, or if the thresholds are specified as an array of dates, then the binned values are implicitly coerced to dates. Time intervals are intervals that are also functions that return a Date instance when called with no arguments. + +If the **interval** option is used instead of **thresholds**, it may be either an interval, a time interval, or a number. If a number *n*, threshold values are consecutive multiples of *n* that span the domain; otherwise, the **interval** option is equivalent to the **thresholds** option. When the thresholds are specified as an interval, and the default **domain** is used, the domain will automatically be extended to start and end to align with the interval. + +The bin transform supports grouping in addition to binning: you can subdivide bins by up to two additional ordinal or categorical dimensions (not including faceting). If any of **z**, **fill**, or **stroke** is a channel, the first of these channels will be used to subdivide bins. Similarly, Plot.binX will group on **y** if **y** is not an output channel, and Plot.binY will group on **x** if **x** is not an output channel. For example, for a stacked histogram: + +```js +Plot.binX({y: "count"}, {x: "body_mass_g", fill: "species"}) +``` + +Lastly, the bin transform changes the default [mark insets](#marks): rather than defaulting to zero, a pixel is reserved to separate adjacent bins. Plot.binX changes the defaults for **insetLeft** and **insetRight**; Plot.binY changes the defaults for **insetTop** and **insetBottom**; Plot.bin changes all four. + +#### Plot.bin(*outputs*, *options*) + +```js +Plot.rect(athletes, Plot.bin({fillOpacity: "count"}, {x: "weight", y: "height"})) +``` + +Bins on *x* and *y*. Also groups on the first channel of *z*, *fill*, or *stroke*, if any. + +#### Plot.binX(*outputs*, *options*) + +```js +Plot.rectY(athletes, Plot.binX({y: "count"}, {x: "weight"})) +``` + +Bins on *x*. Also groups on *y* and the first channel of *z*, *fill*, or *stroke*, if any. + +#### Plot.binY(*outputs*, *options*) + +```js +Plot.rectX(athletes, Plot.binY({x: "count"}, {y: "weight"})) +``` + +Bins on *y*. Also groups on *x* and first channel of *z*, *fill*, or *stroke*, if any. + +### Group + +[a histogram of penguins by species](https://observablehq.com/@observablehq/plot-group) + +[Source](./src/transforms/group.js) · [Examples](https://observablehq.com/@observablehq/plot-group) · Aggregates ordinal or categorical data—such as names—into groups and then computes summary statistics for each group such as a count or sum. The group transform is like a discrete [bin transform](#bin). There are separate transforms depending on which dimensions need grouping: [Plot.groupZ](#plotgroupzoutputs-options) for *z*; [Plot.groupX](#plotgroupxoutputs-options) for *x* and *z*; [Plot.groupY](#plotgroupyoutputs-options) for *y* and *z*; and [Plot.group](#plotgroupoutputs-options) for *x*, *y*, and *z*. + +Given input *data* = [*d₀*, *d₁*, *d₂*, …], by default the resulting grouped data is an array of arrays where each inner array is a subset of the input data [[*d₀₀*, *d₀₁*, …], [*d₁₀*, *d₁₁*, …], [*d₂₀*, *d₂₁*, …], …]. Each inner array is in input order. The outer array is in natural ascending order according to the associated dimension (*x* then *y*). Empty groups are skipped. By specifying a different aggregation method for the *data* output, as described below, you can change how the grouped data is computed. The outputs may also include *filter* and *sort* options specified as aggregation methods, and a *reverse* option to reverse the order of generated groups. By default, all (non-empty) groups are generated in ascending natural order. + +While it is possible to compute channel values on the grouped data by defining channel values as a function, more commonly channel values are computed directly by the group transform, either implicitly or explicitly. In addition to data, the following channels are automatically aggregated: + +* **x** - the horizontal position of the group +* **y** - the vertical position of the group +* **z** - the first value of the *z* channel, if any +* **fill** - the first value of the *fill* channel, if any +* **stroke** - the first value of the *stroke* channel, if any + +The **x** output channel is only computed by the Plot.groupX and Plot.group transform; similarly the **y** output channel is only computed by the Plot.groupY and Plot.group transform. + +You can declare additional channels to aggregate by specifying the channel name and desired aggregation method in the *outputs* object which is the first argument to the transform. For example, to use [Plot.groupX](#plotgroupxoutputs-options) to generate a **y** channel of group counts as in a frequency histogram: + +```js +Plot.groupX({y: "count"}, {x: "species"}) +``` + +The following aggregation methods are supported: + +* *first* - the first value, in input order +* *last* - the last value, in input order +* *count* - the number of elements (frequency) +* *sum* - the sum of values +* *proportion* - the sum proportional to the overall total (weighted frequency) +* *proportion-facet* - the sum proportional to the facet total +* *min* - the minimum value +* *min-index* - the zero-based index of the minimum value +* *max* - the maximum value +* *max-index* - the zero-based index of the maximum value +* *mean* - the mean value (average) +* *median* - the median value +* *pXX* - the percentile value, where XX is a number in [00,99] +* *deviation* - the standard deviation +* *variance* - the variance per [Welford’s algorithm](https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Welford's_online_algorithm) +* a function - passed the array of values for each group +* an object with a *reduce* method, an optionally a *scope* + +In the last case, the *reduce* method is repeatedly passed two arguments: the index for each group (an array of integers), and the input channel’s array of values; it must then return the corresponding aggregate value for the group. If the reducer object’s *scope* is “data”, then the *reduce* method is first invoked for the full data; the return value of the *reduce* method is then made available as a third argument. Similarly if the *scope* is “facet”, then the *reduce* method is invoked for each facet, and the resulting reduce value is made available while reducing the facet’s groups. (This optional *scope* is used by the *proportion* and *proportion-facet* reducers.) + +Most aggregation methods require binding the output channel to an input channel; for example, if you want the **y** output channel to be a *sum* (not merely a count), there should be a corresponding **y** input channel specifying which values to sum. If there is not, *sum* will be equivalent to *count*. + +```js +Plot.groupX({y: "sum"}, {x: "species", y: "body_mass_g"}) +``` + +You can control whether a channel is computed before or after grouping. If a channel is declared only in *options* (and it is not a special group-eligible channel such as *x*, *y*, *z*, *fill*, or stroke), it will be computed after grouping and be passed the grouped data: each datum is the array of input data corresponding to the current group. + +```js +Plot.groupX({y: "count"}, {x: "species", title: group => group.map(d => d.body_mass_g).join("\n")}) +``` + +This is equivalent to declaring the channel only in *outputs*. + +```js +Plot.groupX({y: "count", title: group => group.map(d => d.body_mass_g).join("\n")}, {x: "species"}) +``` + +However, if a channel is declared in both *outputs* and *options*, then the channel in *options* is computed before grouping and can be aggregated using any built-in reducer (or a custom reducer function) during the group transform. + +```js +Plot.groupX({y: "count", title: masses => masses.join("\n")}, {x: "species", title: "body_mass_g"}) +``` + +If any of **z**, **fill**, or **stroke** is a channel, the first of these channels is considered the *z* dimension and will be used to subdivide groups. + +#### Plot.group(*outputs*, *options*) + +```js +Plot.group({fill: "count"}, {x: "island", y: "species"}) +``` + +Groups on *x*, *y*, and the first channel of *z*, *fill*, or *stroke*, if any. + +#### Plot.groupX(*outputs*, *options*) + +```js +Plot.groupX({y: "sum"}, {x: "species", y: "body_mass_g"}) +``` + +Groups on *x* and the first channel of *z*, *fill*, or *stroke*, if any. + +#### Plot.groupY(*outputs*, *options*) + +```js +Plot.groupY({x: "sum"}, {y: "species", x: "body_mass_g"}) +``` + +Groups on *y* and the first channel of *z*, *fill*, or *stroke*, if any. + +#### Plot.groupZ(*outputs*, *options*) + +```js +Plot.groupZ({x: "proportion"}, {fill: "species"}) +``` + +Groups on the first channel of *z*, *fill*, or *stroke*, if any. If none of *z*, *fill*, or *stroke* are channels, then all data (within each facet) is placed into a single group. + +### Map + +[moving averages of daily highs and lows](https://observablehq.com/@observablehq/plot-map) + +[Source](./src/transforms/map.js) · [Examples](https://observablehq.com/@observablehq/plot-map) · Groups data into series and then applies a mapping function to each series’ values, say to normalize them relative to some basis or to apply a moving average. + +The map transform derives new output channels from corresponding input channels. The output channels have strictly the same length as the input channels; the map transform does not affect the mark’s data or index. The map transform is akin to running [*array*.map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) on the input channel’s values with the given function. However, the map transform is series-aware: the data are first grouped into series using the *z*, *fill*, or *stroke* channel in the same fashion as the [area](#area) and [line](#line) marks so that series are processed independently. + +Like the [group](#group) and [bin](#bin) transforms, the [Plot.map](#plotmapoutputs-options) transform takes two arguments: an *outputs* object that describes the output channels to compute, and an *options* object that describes the input channels and any additional options. The other map transforms, such as [Plot.normalizeX](#plotnormalizexbasis-options) and [Plot.windowX](#plotwindowxk-options), call Plot.map internally. + +The following map methods are supported: + +* *cumsum* - a cumulative sum +* *rank* - the rank of each value in the sorted array +* *quantile* - the rank, normalized between 0 and 1 +* a function to be passed an array of values, returning new values +* an object that implements the *map* method + +If a function is used, it must return an array of the same length as the given input. If a *map* method is used, it is repeatedly passed the index for each series (an array of integers), the corresponding input channel’s array of values, and the output channel’s array of values; it must populate the slots specified by the index in the output array. + +The Plot.normalizeX and Plot.normalizeY transforms normalize series values relative to the given basis. For example, if the series values are [*y₀*, *y₁*, *y₂*, …] and the *first* basis is used, the mapped series values would be [*y₀* / *y₀*, *y₁* / *y₀*, *y₂* / *y₀*, …] as in an index chart. The **basis** option specifies how to normalize the series values. The following basis methods are supported: + +* *first* - the first value, as in an index chart; the default +* *last* - the last value +* *min* - the minimum value +* *max* - the maximum value +* *mean* - the mean value (average) +* *median* - the median value +* *pXX* - the percentile value, where XX is a number in [00,99] +* *sum* - the sum of values +* *extent* - the minimum is mapped to zero, and the maximum to one +* *deviation* - each value is transformed by subtracting the mean and then dividing by the standard deviation +* a function to be passed an array of values, returning the desired basis + +The Plot.windowX and Plot.windowY transforms compute a moving window around each data point and then derive a summary statistic from values in the current window, say to compute rolling averages, rolling minimums, or rolling maximums. These transforms also take additional options: + +* **k** - the window size (the number of elements in the window) +* **anchor** - how to align the window: *start*, *middle*, or *end* +* **reduce** - the aggregation method (window reducer) + +The following window reducers are supported: + +* *min* - the minimum +* *max* - the maximum +* *mean* - the mean (average) +* *median* - the median +* *mode* - the mode (most common occurrence) +* *pXX* - the percentile value, where XX is a number in [00,99] +* *sum* - the sum of values +* *deviation* - the standard deviation +* *variance* - the variance per [Welford’s algorithm](https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Welford's_online_algorithm) +* *difference* - the difference between the last and first window value +* *ratio* - the ratio of the last and first window value +* *first* - the first value +* *last* - the last value +* a function to be passed an array of *k* values + +By default, **anchor** is *middle* and **reduce** is *mean*. + +#### Plot.map(*outputs*, *options*) + +```js +Plot.map({y: "cumsum"}, {y: d3.randomNormal()}) +``` + +Groups on the first channel of *z*, *fill*, or *stroke*, if any, and then for each channel declared in the specified *outputs* object, applies the corresponding map method. Each channel in *outputs* must have a corresponding input channel in *options*. + +#### Plot.mapX(*map*, *options*) + +```js +Plot.mapX("cumsum", {x: d3.randomNormal()}) +``` + +Equivalent to Plot.map({x: *map*, x1: *map*, x2: *map*}, *options*), but ignores any of **x**, **x1**, and **x2** not present in *options*. + +#### Plot.mapY(*map*, *options*) + +```js +Plot.mapY("cumsum", {y: d3.randomNormal()}) +``` + +Equivalent to Plot.map({y: *map*, y1: *map*, y2: *map*}, *options*), but ignores any of **y**, **y1**, and **y2** not present in *options*. + +#### Plot.normalize(*basis*) + +```js +Plot.map({y: Plot.normalize("first")}, {x: "Date", y: "Close", stroke: "Symbol"}) +``` + +Returns a normalize map method for the given *basis*, suitable for use with Plot.map. + +#### Plot.normalizeX(*basis*, *options*) + +```js +Plot.normalizeX("first", {y: "Date", x: "Close", stroke: "Symbol"}) +``` + +Like [Plot.mapX](#plotmapxmap-options), but applies the normalize map method with the given *basis*. + +#### Plot.normalizeY(*basis*, *options*) + +```js +Plot.normalizeY("first", {x: "Date", y: "Close", stroke: "Symbol"}) +``` + +Like [Plot.mapY](#plotmapymap-options), but applies the normalize map method with the given *basis*. + +#### Plot.window(*k*) + +```js +Plot.map({y: Plot.window(24)}, {x: "Date", y: "Close", stroke: "Symbol"}) +``` + +Returns a window map method for the given window size *k*, suitable for use with Plot.map. For additional options to the window transform, replace the number *k* with an object with properties *k*, *anchor*, or *reduce*. + +#### Plot.windowX(*k*, *options*) + +```js +Plot.windowX(24, {y: "Date", x: "Anomaly"}) +``` + +Like [Plot.mapX](#plotmapxmap-options), but applies the window map method with the given window size *k*. For additional options to the window transform, replace the number *k* with an object with properties *k*, *anchor*, or *reduce*. + +#### Plot.windowY(*k*, *options*) + +```js +Plot.windowY(24, {x: "Date", y: "Anomaly"}) +``` + +Like [Plot.mapY](#plotmapymap-options), but applies the window map method with the given window size *k*. For additional options to the window transform, replace the number *k* with an object with properties *k*, *anchor*, or *reduce*. + +### Select + +[a line chart of several stocks](https://observablehq.com/@observablehq/plot-select) + +[Source](./src/transforms/select.js) · [Examples](https://observablehq.com/@observablehq/plot-select) · Selects a value from each series, say to label a line or annotate extremes. + +The select transform derives a filtered mark index; it does not affect the mark’s data or channels. It is similar to the basic [filter transform](#transforms) except that provides convenient shorthand for pulling a single value out of each series. The data are grouped into series using the *z*, *fill*, or *stroke* channel in the same fashion as the [area](#area) and [line](#line) marks. + +#### Plot.select(*selector*, *options*) + +Selects the points of each series selected by the *selector*, which can be specified either as a function which receives as input the index of the series, the shorthand “first” or “last”, or as a {*key*: *value*} object with exactly one *key* being the name of a channel and the *value* being a function which receives as input the index of the series and the channel values. The *value* may alternatively be specified as the shorthand “min” and “max” which respectively select the minimum and maximum points for the specified channel. + +For example, to select the point within each series that is the closest to the median of the *y* channel: + +```js +Plot.select({ + y: (I, V) => { + const median = d3.median(I, i => V[i]); + const i = d3.least(I, i => Math.abs(V[i] - median)); + return [i]; + } +}, { + x: "year", + y: "revenue", + fill: "format" +}) +``` + +To pick three points at random in each series: + +```js +Plot.select(I => d3.shuffle(I.slice()).slice(0, 3), {z: "year", ...}) +``` + +To pick the point in each city with the highest temperature: + +```js +Plot.select({fill: "max"}, {x: "date", y: "city", fill: "temperature", z: "city"}) +``` + +#### Plot.selectFirst(*options*) + +Selects the first point of each series according to input order. + +#### Plot.selectLast(*options*) + +Selects the last point of each series according to input order. + +#### Plot.selectMinX(*options*) + +Selects the leftmost point of each series. + +#### Plot.selectMinY(*options*) + +Selects the lowest point of each series. + +#### Plot.selectMaxX(*options*) + +Selects the rightmost point of each series. + +#### Plot.selectMaxY(*options*) + +Selects the highest point of each series. + +### Stack + +[a stacked area chart of revenue by category](https://observablehq.com/@observablehq/plot-stack) + +[Source](./src/transforms/stack.js) · [Examples](https://observablehq.com/@observablehq/plot-stack) · Transforms a length channel into starting and ending position channels by “stacking” elements that share a given position, such as transforming the **y** input channel into **y1** and **y2** output channels after grouping on **x** as in a stacked area chart. The starting position of each element equals the ending position of the preceding element in the stack. + +The Plot.stackY transform groups on **x** and transforms **y** into **y1** and **y2**; the Plot.stackX transform groups on **y** and transforms **x** into **x1** and **x2**. If **y** is not specified for Plot.stackY, or if **x** is not specified for Plot.stackX, it defaults to the constant one, which is useful for constructing simple isotype charts (*e.g.*, stacked dots). + +The supported stack options are: + +- **offset** - the offset (or baseline) method +- **order** - the order in which stacks are layered +- **reverse** - true to reverse order + +The following **order** methods are supported: + +- null - input order (default) +- *value* - ascending value order (or descending with **reverse**) +- *sum* - order series by their total value +- *appearance* - order series by the position of their maximum value +- *inside-out* - order the earliest-appearing series on the inside +- a named field or function of data - order data by priority +- an array of *z* values + +The **reverse** option reverses the effective order. For the *value* order, Plot.stackY uses the *y*-value while Plot.stackX uses the *x*-value. For the *appearance* order, Plot.stackY uses the *x*-position of the maximum *y*-value while Plot.stackX uses the *y*-position of the maximum *x*-value. If an array of *z* values are specified, they should enumerate the *z* values for all series in the desired order; this array is typically hard-coded or computed with [d3.groupSort](https://github.com/d3/d3-array/blob/main/README.md#groupSort). Note that the input order (null) and *value* order can produce crossing paths: they do not guarantee a consistent series order across stacks. + +The stack transform supports diverging stacks: negative values are stacked below zero while positive values are stacked above zero. For Plot.stackY, the **y1** channel contains the value of lesser magnitude (closer to zero) while the **y2** channel contains the value of greater magnitude (farther from zero); the difference between the two corresponds to the input **y** channel value. For Plot.stackX, the same is true, except for **x1**, **x2**, and **x** respectively. + +After all values have been stacked from zero, an optional **offset** can be applied to translate or scale the stacks. The following **offset** methods are supported: + +- null - a zero baseline (default) +- *expand* (or *normalize*) - rescale each stack to fill [0, 1] +- *center* (or *silhouette*) - align the centers of all stacks +- *wiggle* - translate stacks to minimize apparent movement +- a function to be passed a nested index, and start, end, and *z* values + +If a given stack has zero total value, the *expand* offset will not adjust the stack’s position. Both the *center* and *wiggle* offsets ensure that the lowest element across stacks starts at zero for better default axes. The *wiggle* offset is recommended for streamgraphs, and if used, changes the default order to *inside-out*; see [Byron & Wattenberg](http://leebyron.com/streamgraph/). + +If the offset is specified as a function, it will receive four arguments: an index of stacks nested by facet and then stack, an array of start values, an array of end values, and an array of *z* values. For stackX, the start and end values correspond to *x1* and *x2*, while for stackY, the start and end values correspond to *y1* and *y2*. The offset function is then responsible for mutating the arrays of start and end values, such as by subtracting a common offset for each of the indices that pertain to the same stack. + +In addition to the **y1** and **y2** output channels, Plot.stackY computes a **y** output channel that represents the midpoint of **y1** and **y2**. Plot.stackX does the same for **x**. This can be used to position a label or a dot in the center of a stacked layer. The **x** and **y** output channels are lazy: they are only computed if needed by a downstream mark or transform. + +If two arguments are passed to the stack transform functions below, the stack-specific options (**offset**, **order**, and **reverse**) are pulled exclusively from the first *options* argument, while any channels (*e.g.*, **x**, **y**, and **z**) are pulled from second *options* argument. Options from the second argument that are not consumed by the stack transform will be passed through. Using two arguments is sometimes necessary is disambiguate the option recipient when chaining transforms. + +#### Plot.stackY([*stack*, ]*options*) + +```js +Plot.stackY({x: "year", y: "revenue", z: "format", fill: "group"}) +``` + +Creates new channels **y1** and **y2**, obtained by stacking the original **y** channel for data points that share a common **x** (and possibly **z**) value. A new **y** channel is also returned, which lazily computes the middle value of **y1** and **y2**. The input **y** channel defaults to a constant 1, resulting in a count of the data points. The stack options (*offset*, *order*, and *reverse*) may be specified as part of the *options* object, if the only argument, or as a separate *stack* options argument. + +#### Plot.stackY1([*stack*, ]*options*) + +```js +Plot.stackY1({x: "year", y: "revenue", z: "format", fill: "group"}) +``` + +Equivalent to [Plot.stackY](#plotstackystack-options), except that the **y1** channel is returned as the **y** channel. This can be used, for example, to draw a line at the bottom of each stacked area. + +#### Plot.stackY2([*stack*, ]*options*) + +```js +Plot.stackY2({x: "year", y: "revenue", z: "format", fill: "group"}) +``` + +Equivalent to [Plot.stackY](#plotstackystack-options), except that the **y2** channel is returned as the **y** channel. This can be used, for example, to draw a line at the top of each stacked area. + +#### Plot.stackX([*stack*, ]*options*) + +```js +Plot.stackX({y: "year", x: "revenue", z: "format", fill: "group"}) +``` + +See Plot.stackY, but with *x* as the input value channel, *y* as the stack index, *x1*, *x2* and *x* as the output channels. + +#### Plot.stackX1([*stack*, ]*options*) + +```js +Plot.stackX1({y: "year", x: "revenue", z: "format", fill: "group"}) +``` + +Equivalent to [Plot.stackX](#plotstackxstack-options), except that the **x1** channel is returned as the **x** channel. This can be used, for example, to draw a line at the left edge of each stacked area. + +#### Plot.stackX2([*stack*, ]*options*) + +```js +Plot.stackX2({y: "year", x: "revenue", z: "format", fill: "group"}) +``` + +Equivalent to [Plot.stackX](#plotstackxstack-options), except that the **x2** channel is returned as the **x** channel. This can be used, for example, to draw a line at the right edge of each stacked area. + +### Tree + +[a node-link tree diagram representing a software hierarchy](https://observablehq.com/@observablehq/plot-tree) + +[Source](./src/transforms/tree.js) · [Examples](https://observablehq.com/@observablehq/plot-tree) · Transforms a tabular dataset into a hierarchy according to the given **path** input channel, which is typically a slash-separated string; then executes a tree layout algorithm to compute **x** and **y** output channels; these channels can then be fed to other marks to construct a node-link diagram. + +The following options control how the tabular data is organized into a hierarchy: + +* **path** - a column specifying each node’s hierarchy location; defaults to identity +* **delimiter** - the path separator; defaults to forward slash (/) + +The **path** column is typically slash-separated, as with UNIX-based file systems or URLs. For example, given the following hierarchy: + +``` +└─ Total + ├─ Fossil Fuels + │ ├─ Coal + │ ├─ Natural Gas + │ └─ Crude Oil + ├─ Nuclear + └─ Renewable + ├─ Biomass + ├─ Geothermal + ├─ Hydroelectric + ├─ Solar + └─ Wind +``` + +You might use the following path strings: + +``` +/Total +/Total/Fossil Fuels +/Total/Fossil Fuels/Coal +/Total/Fossil Fuels/Natural Gas +/Total/Fossil Fuels/Crude Oil +/Total/Nuclear +/Total/Renewable +/Total/Renewable/Biomass +/Total/Renewable/Geothermal +/Total/Renewable/Hydroelectric +/Total/Renewable/Solar +/Total/Renewable/Wind +``` + +The following options control how the node-link diagram is laid out: + +* **treeLayout** - a tree layout algorithm; defaults to [d3.tree](https://github.com/d3/d3-hierarchy/blob/main/README.md#tree) +* **treeAnchor** - a tree layout orientation, either *left* or *right*; defaults to *left* +* **treeSort** - a node comparator, or null to preserve input order +* **treeSeparation** - a node separation function, or null for uniform separation + +The default **treeLayout** implements the Reingold–Tilford “tidy” algorithm based on Buchheim _et al._’s linear time approach. Use [d3.cluster](https://github.com/d3/d3-hierarchy/blob/main/README.md#cluster) instead to align leaf nodes; see also [Plot.cluster](#plotclusterdata-options). If the **treeAnchor** is *left*, the root of the tree will be aligned with the left side of the frame; if **treeAnchor** is *right*, the root of the tree will be aligned with the right side of the frame; use the **insetLeft** and **insetRight** [scale options](#scale-options) if horizontal padding is desired, say to make room for labels. If the **treeSort** option is not null, it is typically a function that is passed two nodes in the hierarchy and compares them, similar to [_array_.sort](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort); see [d3-hierarchy’s _node_.sort](https://github.com/d3/d3-hierarchy/blob/main/README.md#node_sort) for more. The **treeSort** option can also be specified as a string, in which case it refers either to a named column in data, or if it starts with “node:”, a node value (see below). If the **treeSeparation** is not null, it is a function that is passed two nodes in the hierarchy and returns the desired (relative) amount of separation; see [d3-hierarchy’s _tree_.separation](https://github.com/d3/d3-hierarchy/blob/main/README.md#tree_separation) for more. By default, non-siblings are at least twice as far apart as siblings. + +### Plot.treeNode(*options*) + +Based on the tree options described above, populates the **x** and **y** channels with the positions for each node. The following defaults are also applied: the default **frameAnchor** inherits the **treeAnchor**. This transform is intended to be used with [dot](#dot), [text](#text), and other point-based marks. This transform is rarely used directly; see the [Plot.tree compound mark](#plottreedata-options). + +The treeNode transform will derive output columns for any *options* that have one of the following named node values: + +* *node:name* - the node’s name (the last part of its path) +* *node:path* - the node’s full, normalized, slash-separated path +* *node:internal* - true if the node is internal, or false for leaves +* *node:depth* - the distance from the node to the root +* *node:height* - the distance from the node to its deepest descendant + +In addition, if any option value is specified as an object with a **node** method, a derived output column will be generated by invoking the **node** method for each node in the tree. + +### Plot.treeLink(*options*) + +Based on the tree options described above, populates the **x1**, **y1**, **x2**, and **y2** channels. The following defaults are also applied: the default **curve** is *bump-x*, the default **stroke** is #555, the default **strokeWidth** is 1.5, and the default **strokeOpacity** is 0.5. This transform is intended to be used with [link](#link), [arrow](#arrow), and other two-point-based marks. This transform is rarely used directly; see the [Plot.tree compound mark](#plottreedata-options). + +The treeLink transform will derive output columns for any *options* that have one of the following named link values: + +* *node:name* - the child node’s name (the last part of its path) +* *node:path* - the child node’s full, normalized, slash-separated path +* *node:internal* - true if the child node is internal, or false for leaves +* *node:depth* - the distance from the child node to the root +* *node:height* - the distance from the child node to its deepest descendant +* *parent:name* - the parent node’s name (the last part of its path) +* *parent:path* - the parent node’s full, normalized, slash-separated path +* *parent:depth* - the distance from the parent node to the root +* *parent:height* - the distance from the parent node to its deepest descendant + +In addition, if any option value is specified as an object with a **node** method, a derived output column will be generated by invoking the **node** method for each child node in the tree; likewise if any option value is specified as an object with a **link** method, a derived output column will be generated by invoking the **link** method for each link in the tree, being passed two node arguments, the child and the parent. + +### Plot.tree(*data*, *options*) + +A convenience compound mark for rendering a tree diagram, including a [link](#link) to render links from parent to child, an optional [dot](#dot) for nodes, and a [text](#text) for node labels. The link mark uses the [treeLink transform](#plottreelinkoptions), while the dot and text marks use the [treeNode transform](#plottreenodeoptions). The following options are supported: + +* **fill** - the dot and text fill color; defaults to *node:internal* +* **stroke** - the link stroke color; inherits **fill** by default +* **strokeWidth** - the link stroke width +* **strokeOpacity** - the link stroke opacity +* **strokeLinejoin** - the link stroke linejoin +* **strokeLinecap** - the link stroke linecap +* **strokeMiterlimit** - the link stroke miter limit +* **strokeDasharray** - the link stroke dash array +* **strokeDashoffset** - the link stroke dash offset +* **marker** - the link start and end marker +* **markerStart** - the link start marker +* **markerEnd** - the link end marker +* **dot** - if true, whether to render a dot; defaults to false if no link marker +* **title** - the text and dot title; defaults to *node:path* +* **text** - the text label; defaults to *node:name* +* **textStroke** - the text stroke; defaults to *white* +* **dx** - the text horizontal offset; defaults to 6 if left-anchored, or -6 if right-anchored +* **dy** - the text vertical offset; defaults to 0 + +Any additional *options* are passed through to the constituent link, dot, and text marks and their corresponding treeLink or treeNode transform. + +### Plot.cluster(*data*, *options*) + +Like Plot.tree, except sets the **treeLayout** option to D3’s cluster (dendrogram) algorithm, which aligns leaf nodes. + +### Custom transforms + +The **transform** option defines a custom transform function, allowing data, indexes, or channels to be derived prior to rendering. Custom transforms are rarely implemented directly; see the built-in transforms above. The transform function (if present) is passed two arguments, *data* and *facets*, representing the mark’s data and facet indexes; it must then return a {data, facets} object representing the resulting transformed data and facet indexes. The *facets* are represented as a nested array of arrays such as [[0, 1, 3, …], [2, 5, 10, …], …]; each element in *facets* specifies the zero-based indexes of elements in *data* that are in a given facet (*i.e.*, have a distinct value in the associated *fx* or *fy* dimension). + +While transform functions often produce new *data* or *facets*, they may return the passed-in *data* and *facets* as-is, and often have a side-effect of constructing derived channels. For example, the count of elements in a [groupX transform](#group) might be returned as a new *y* channel. In this case, the transform is typically expressed as an options transform: a function that takes a mark options object and returns a new, transformed options object, where the returned options object implements a *transform* function option. Transform functions should not mutate the input *data* or *facets*. Likewise options transforms should not mutate the input *options* object. + +Plot provides a few helpers for implementing transforms. + +#### Plot.transform(*options*, *transform*) + +Given an *options* object that may specify some basic transforms (*filter*, *sort*, or *reverse*) or a custom *transform* function, composes those transforms if any with the given *transform* function, returning a new *options* object. If a custom *transform* function is present on the given *options*, any basic transforms are ignored. Any additional input *options* are passed through in the returned *options* object. This method facilitates applying the basic transforms prior to applying the given custom *transform* and is used internally by Plot’s built-in transforms. + +#### Plot.column([*source*]) + +This helper for constructing derived columns returns a [*column*, *setColumn*] array. The *column* object implements *column*.transform, returning whatever value was most recently passed to *setColumn*. If *setColumn* is not called, then *column*.transform returns undefined. If a *source* is specified, then *column*.label exposes the given *source*’s label, if any: if *source* is a string as when representing a named field of data, then *column*.label is *source*; otherwise *column*.label propagates *source*.label. This allows derived columns to propagate a human-readable axis or legend label. + +Plot.column is typically used by options transforms to define new channels; the associated columns are populated (derived) when the **transform** option function is invoked. + +## Curves + +A curve defines how to turn a discrete representation of a line as a sequence of points [[*x₀*, *y₀*], [*x₁*, *y₁*], [*x₂*, *y₂*], …] into a continuous path; *i.e.*, how to interpolate between points. Curves are used by the [line](#line), [area](#area), and [link](#link) mark, and are implemented by [d3-shape](https://github.com/d3/d3-shape/blob/master/README.md#curves). + +The supported curve options are: + +* **curve** - the curve method, either a string or a function +* **tension** - the curve tension (for fine-tuning) + +The following named curve methods are supported: + +* *basis* - a cubic basis spline (repeating the end points) +* *basis-open* - an open cubic basis spline +* *basis-closed* - a closed cubic basis spline +* *bump-x* - a Bézier curve with horizontal tangents +* *bump-y* - a Bézier curve with vertical tangents +* *cardinal* - a cubic cardinal spline (with one-sided differences at the ends) +* *cardinal-open* - an open cubic cardinal spline +* *cardinal-closed* - an closed cubic cardinal spline +* *catmull-rom* - a cubic Catmull–Rom spline (with one-sided differences at the ends) +* *catmull-rom-open* - an open cubic Catmull–Rom spline +* *catmull-rom-closed* - a closed cubic Catmull–Rom spline +* *linear* - a piecewise linear curve (*i.e.*, straight line segments) +* *linear-closed* - a closed piecewise linear curve (*i.e.*, straight line segments) +* *monotone-x* - a cubic spline that preserves monotonicity in *x* +* *monotone-y* - a cubic spline that preserves monotonicity in *y* +* *natural* - a natural cubic spline +* *step* - a piecewise constant function where *y* changes at the midpoint of *x* +* *step-after* - a piecewise constant function where *y* changes after *x* +* *step-before* - a piecewise constant function where *x* changes after *y* + +If *curve* is a function, it will be invoked with a given *context* in the same fashion as a [D3 curve factory](https://github.com/d3/d3-shape/blob/master/README.md#custom-curves). + +The tension option only has an effect on cardinal and Catmull–Rom splines (*cardinal*, *cardinal-open*, *cardinal-closed*, *catmull-rom*, *catmull-rom-open*, and *catmull-rom-closed*). For cardinal splines, it corresponds to [tension](https://github.com/d3/d3-shape/blob/master/README.md#curveCardinal_tension); for Catmull–Rom splines, [alpha](https://github.com/d3/d3-shape/blob/master/README.md#curveCatmullRom_alpha). + +## Markers + +A [marker](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/marker) defines a graphic drawn on vertices of a [line](#line) or a [link](#link) mark. The supported marker options are: + +* **markerStart** - the marker for the starting point of a line segment +* **markerMid** - the marker for any intermediate point of a line segment +* **markerEnd** - the marker for the end point of a line segment +* **marker** - shorthand for setting the marker on all points + +The following named markers are supported: + +* *none* - no marker (default) +* *arrow* - an arrowhead +* *dot* - a filled *circle* without a stroke and 2.5px radius +* *circle*, equivalent to *circle-fill* - a filled circle with a white stroke and 3px radius +* *circle-stroke* - a hollow circle with a colored stroke and a white fill and 3px radius + +If *marker* is true, it defaults to *circle*. If *marker* is a function, it will be called with a given *color* and must return an SVG marker element. + +The primary color of a marker is inherited from the *stroke* of the associated mark. The *arrow* marker is [automatically oriented](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/orient) such that it points in the tangential direction of the path at the position the marker is placed. The *circle* markers are centered around the given vertex. Note that lines whose curve is not *linear* (the default), markers are not necessarily drawn at the data positions given by *x* and *y*; marker placement is determined by the (possibly Bézier) path segments generated by the curve. To ensure that symbols are drawn at a given *x* and *y* position, consider using a [dot](#dot). + +## Formats + +These helper functions are provided for use as a *scale*.tickFormat [axis option](#position-options), as the text option for [Plot.text](#plottextdata-options), or for general use. See also [d3-format](https://github.com/d3/d3-format), [d3-time-format](https://github.com/d3/d3-time-format), and JavaScript’s built-in [date formatting](https://observablehq.com/@mbostock/date-formatting) and [number formatting](https://observablehq.com/@mbostock/number-formatting). + +#### Plot.formatIsoDate(*date*) + +```js +Plot.formatIsoDate(new Date("2020-01-01T00:00.000Z")) // "2020-01-01" +``` + +Given a *date*, returns the shortest equivalent ISO 8601 UTC string. If the given *date* is not valid, returns `"Invalid Date"`. + +#### Plot.formatWeekday(*locale*, *format*) + +```js +Plot.formatWeekday("es-MX", "long")(0) // "domingo" +``` + +Returns a function that formats a given week day number (from 0 = Sunday to 6 = Saturday) according to the specified *locale* and *format*. The *locale* is a [BCP 47 language tag](https://tools.ietf.org/html/bcp47) and defaults to U.S. English. The *format* is a [weekday format](https://tc39.es/ecma402/#datetimeformat-objects): either *narrow*, *short*, or *long*; if not specified, it defaults to *short*. + +#### Plot.formatMonth(*locale*, *format*) + +```js +Plot.formatMonth("es-MX", "long")(0) // "enero" +``` + +Returns a function that formats a given month number (from 0 = January to 11 = December) according to the specified *locale* and *format*. The *locale* is a [BCP 47 language tag](https://tools.ietf.org/html/bcp47) and defaults to U.S. English. The *format* is a [month format](https://tc39.es/ecma402/#datetimeformat-objects): either *2-digit*, *numeric*, *narrow*, *short*, *long*; if not specified, it defaults to *short*. + +## Accessibility + +Plot supports several [ARIA properties](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA) to help build the accessibility tree. The accessibility tree is consumed by various assistive technology such as screen readers and browser add-ons to make web contents and web applications more accessible to people with disabilities. It can be inspected in the browser’s inspector. + +The aria-label and aria-description properties can be set on the SVG root element by specifying the top-level options **ariaLabel** and **ariaDescription**, which default to null. + +Positional axes are branded with an aria-label and an aria-description properties, which can likewise be specified as axis options. Set the aria-label with the **ariaLabel** axis option, which defaults to “x-axis” and “y-axis” for the corresponding axes (and “fx-axis” and “fy-axis” for facet axes). Set the aria-description with the **ariaDescription** axis option, which defaults to null. + +Marks are branded with an aria-label property with the mark’s name (*e.g.*, “dot”). You can also set an optional aria-description property by specifying the mark option **ariaDescription**. A short label can be specified for each of the individual elements—*e.g.*, individual dots in a dot mark—with the mark option **ariaLabel**. A mark can be hidden from the accessibility tree by specifying the mark option **ariaHidden** to true; this allows to hide decorative elements (such as rules) and repetitive marks (such as lines that support dots, or text marks that are also represented by symbols). diff --git a/content/libraries/d3-plot/v0.4.3/plot.umd.min.js b/content/libraries/d3-plot/v0.4.3/plot.umd.min.js new file mode 100644 index 0000000..880bef6 --- /dev/null +++ b/content/libraries/d3-plot/v0.4.3/plot.umd.min.js @@ -0,0 +1,2 @@ +// @observablehq/plot v0.4.3 Copyright 2020-2022 Observable, Inc. +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("d3@7.4.4/dist/d3.min.js")):"function"==typeof define&&define.amd?define(["exports","d3@7.4.4/dist/d3.min.js"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).Plot=t.Plot||{},t.d3)}(this,(function(t,e){"use strict";function n(t,e){if(t instanceof Date||(t=new Date(+t)),isNaN(t))return"function"==typeof e?e(t):e;const n=t.getUTCHours(),o=t.getUTCMinutes(),i=t.getUTCSeconds(),a=t.getUTCMilliseconds();return`${s=t.getUTCFullYear(),s<0?`-${r(-s,6)}`:s>9999?`+${r(s,6)}`:r(s,4)}-${r(t.getUTCMonth()+1,2)}-${r(t.getUTCDate(),2)}${n||o||i||a?`T${r(n,2)}:${r(o,2)}${i||a?`:${r(i,2)}${a?`.${r(a,3)}`:""}`:""}Z`:""}`;var s}function r(t,e){return`${t}`.padStart(e,"0")}const o=/^(?:[-+]\d{2})?\d{4}(?:-\d{2}(?:-\d{2})?)?(?:T\d{2}:\d{2}(?::\d{2}(?:\.\d{3})?)?(?:Z|[-+]\d{2}:?\d{2})?)?$/;function i(t,e){return o.test(t+="")?new Date(t):"function"==typeof e?e(t):e}const a=Object.getPrototypeOf(Uint8Array),s=Object.prototype.toString;function l(t,e,n){const r=void 0===n?Array:n,o=typeof e;return"string"===o?r.from(t,c(e)):"function"===o?r.from(t,e):"number"===o||e instanceof Date||"boolean"===o?r.from(t,v(e)):e&&"function"==typeof e.transform?M(e.transform(t),n):M(e,n)}const c=t=>e=>e[t],u=(t,e)=>e,f={transform:t=>t},d=()=>1,h=t=>null==t?t:`${t}`,p=t=>null==t?t:+t,m=t=>null==t?t:!!t,y=t=>t?t[0]:void 0,g=t=>t?t[1]:void 0,v=t=>()=>t;function x(t){const n=+`${t}`.slice(1)/100;return(t,r)=>e.quantile(t,n,r)}function w(t,e){return void 0===t&&(t=e),null===t?[void 0,"none"]:V(t)?[void 0,t]:[t,void 0]}function b(t,e){return void 0===t&&(t=e),null===t||"number"==typeof t?[void 0,t]:[t,void 0]}function k(t,e,n){if(null!=t)return $(t,e,n)}function $(t,e,n){const r=`${t}`.toLowerCase();if(!n.includes(r))throw new Error(`invalid ${e}: ${t}`);return r}function M(t,e){return null==t?t:void 0===e?t instanceof Array||t instanceof a?t:Array.from(t):t instanceof e?t:e.from(t)}function L(t){return t?.toString===s}function A(t){return L(t)&&(void 0!==t.type||void 0!==t.domain)}function R(t){return L(t)&&"function"!=typeof t.transform}function B(t,e,n,r=f){return void 0===e&&void 0===n?(e=0,n=void 0===t?r:t):void 0===e?e=void 0===t?0:t:void 0===n&&(n=void 0===t?0:t),[e,n]}function O(t,e){return void 0===t&&void 0===e?[y,g]:[t,e]}function C({z:t,fill:e,stroke:n}={}){return void 0===t&&([t]=w(e)),void 0===t&&([t]=w(n)),t}function S(t){return Uint32Array.from(t,u)}function z(t,e){return S(t).filter((n=>e(t[n],n,t)))}function N(t,e){return Array.from(e,(e=>t[e]))}function E(t){return null!==t&&"object"==typeof t?t.valueOf():t}function T(t,e){if(void 0!==e[t])return e[t];switch(t){case"x1":case"x2":t="x";break;case"y1":case"y2":t="y"}return e[t]}function D(t){let e;return[{transform:()=>e,label:Y(t)},t=>e=t]}function W(t){return null==t?[t]:D(t)}function Y(t,e){return"string"==typeof t?t:t&&void 0!==t.label?t.label:e}function P(t,e){return{transform(n){const r=t.transform(n),o=e.transform(n);return j(r)||j(o)?Array.from(r,((t,e)=>new Date((+r[e]+ +o[e])/2))):Float64Array.from(r,((t,e)=>(+r[e]+ +o[e])/2))},label:t.label}}function q(t){return void 0===t||R(t)?t:{value:t}}function _(t){for(const e of t)if(null!=e)return"object"!=typeof e||e instanceof Date}function F(t){for(const e of t){if(null==e)continue;const t=typeof e;return"string"===t||"boolean"===t}}function j(t){for(const e of t)if(null!=e)return e instanceof Date}function I(t){for(const e of t)if(null!=e)return"string"==typeof e&&isNaN(e)&&i(e)}function G(t){for(const e of t)if(null!=e&&""!==e)return"string"==typeof e&&!isNaN(e)}function X(t,e){for(const n of t)if(null!=n)return e(n)}function U(t,e){for(const n of t)if(null!=n&&!e(n))return!1;return!0}function V(t){return"string"==typeof t&&("none"===(t=t.toLowerCase().trim())||"currentcolor"===t||t.startsWith("url(")&&t.endsWith(")")||t.startsWith("var(")&&t.endsWith(")")||null!==e.color(t))}function H(t){return null==t||Z(t)}function Z(t){return/^\s*none\s*$/i.test(t)}const Q=new Map([["asterisk",e.symbolAsterisk],["circle",e.symbolCircle],["cross",e.symbolCross],["diamond",e.symbolDiamond],["diamond2",e.symbolDiamond2],["plus",e.symbolPlus],["square",e.symbolSquare],["square2",e.symbolSquare2],["star",e.symbolStar],["times",e.symbolX],["triangle",e.symbolTriangle],["triangle2",e.symbolTriangle2],["wye",e.symbolWye]]);function J(t){return t&&"function"==typeof t.draw}function K(t){return!!J(t)||"string"==typeof t&&Q.has(t.toLowerCase())}function tt(t){if(null==t||J(t))return t;const e=Q.get(`${t}`.toLowerCase());if(e)return e;throw new Error(`invalid symbol: ${t}`)}function et(t="middle"){return $(t,"frameAnchor",["middle","top-left","top","top-right","right","bottom-right","bottom","bottom-left","left"])}function nt(t){if(null==t)return;const n=t[0],r=t[t.length-1];return e.descending(n,r)}function rt(t){let e,n={};return(...r)=>((n.length!==r.length||n.some(((t,e)=>t!==r[e])))&&(n=r,e=t(...r)),e)}const ot=rt((t=>new Intl.NumberFormat(t))),it=rt(((t,e)=>new Intl.DateTimeFormat(t,{timeZone:"UTC",month:e}))),at=rt(((t,e)=>new Intl.DateTimeFormat(t,{timeZone:"UTC",weekday:e})));function st(t){return n(t,"Invalid Date")}const lt=function(t="en-US"){const e=function(t="en-US"){const e=ot(t);return t=>null==t||isNaN(t)?void 0:e.format(t)}(t);return t=>(t instanceof Date?st:"number"==typeof t?e:h)(t)}(),ct=Math.PI/180;function ut(t){return null!=t&&!Number.isNaN(t)}function ft(t,n){return ut(n)-ut(t)||e.ascending(t,n)}function dt(t){return null!=t&&""!=`${t}`}function ht(t){return isFinite(t)?t:NaN}function pt(t){return t>0&&isFinite(t)?t:NaN}function mt(t){return t<0&&isFinite(t)?t:NaN}let yt=0;function gt(t){console.warn(t),++yt}const vt="undefined"!=typeof window&&window.devicePixelRatio>1?0:.5;let xt=0;function wt(t,e){e&&t.text((t=>lt(e[t])))}function bt(t,e){e&&t.text((([t])=>lt(e[t])))}function kt(t,{target:e},{ariaLabel:n,title:r,fill:o,fillOpacity:i,stroke:a,strokeOpacity:s,strokeWidth:l,opacity:c,href:u}){n&&Bt(t,"aria-label",(t=>n[t])),o&&Bt(t,"fill",(t=>o[t])),i&&Bt(t,"fill-opacity",(t=>i[t])),a&&Bt(t,"stroke",(t=>a[t])),s&&Bt(t,"stroke-opacity",(t=>s[t])),l&&Bt(t,"stroke-width",(t=>l[t])),c&&Bt(t,"opacity",(t=>c[t])),u&&Rt(t,(t=>u[t]),e),function(t,e){e&&t.filter((t=>dt(e[t]))).append("title").call(wt,e)}(t,r)}function $t(t,{target:e},{ariaLabel:n,title:r,fill:o,fillOpacity:i,stroke:a,strokeOpacity:s,strokeWidth:l,opacity:c,href:u}){n&&Bt(t,"aria-label",(([t])=>n[t])),o&&Bt(t,"fill",(([t])=>o[t])),i&&Bt(t,"fill-opacity",(([t])=>i[t])),a&&Bt(t,"stroke",(([t])=>a[t])),s&&Bt(t,"stroke-opacity",(([t])=>s[t])),l&&Bt(t,"stroke-width",(([t])=>l[t])),c&&Bt(t,"opacity",(([t])=>c[t])),u&&Rt(t,(([t])=>u[t]),e),function(t,e){e&&t.filter((([t])=>dt(e[t]))).append("title").call(bt,e)}(t,r)}function*Mt(t,n,{z:r},o){const{z:i}=o,a=function({ariaLabel:t,title:e,fill:n,fillOpacity:r,stroke:o,strokeOpacity:i,strokeWidth:a,opacity:s,href:l}){return[t,e,n,r,o,i,a,s,l].filter((t=>void 0!==t))}(o),s=[...n,...a];for(const n of i?function(t,n,r){const o=e.group(t,(t=>n[t]));return void 0===r&&o.size>t.length>>1&>("Warning: the implicit z channel has high cardinality. This may occur when the fill or stroke channel is associated with quantitative data rather than ordinal or categorical data. You can suppress this warning by setting the z option explicitly; if this data represents a single series, set z to null."),o.values()}(t,i,r):[t]){let t,e;t:for(const r of n){for(const t of s)if(!ut(t[r])){e&&e.push(-1);continue t}if(void 0!==t){e.push(r);for(let n=0;nE(t[r]))),e=[r];continue t}}}else e&&(yield e),t=a.map((t=>E(t[r]))),e=[r]}e&&(yield e)}}function Lt(t,e,{width:n,height:r,marginLeft:o,marginRight:i,marginTop:a,marginBottom:s}){if(Bt(t,"aria-label",e.ariaLabel),Bt(t,"aria-description",e.ariaDescription),Bt(t,"aria-hidden",e.ariaHidden),Bt(t,"fill",e.fill),Bt(t,"fill-opacity",e.fillOpacity),Bt(t,"stroke",e.stroke),Bt(t,"stroke-width",e.strokeWidth),Bt(t,"stroke-opacity",e.strokeOpacity),Bt(t,"stroke-linejoin",e.strokeLinejoin),Bt(t,"stroke-linecap",e.strokeLinecap),Bt(t,"stroke-miterlimit",e.strokeMiterlimit),Bt(t,"stroke-dasharray",e.strokeDasharray),Bt(t,"stroke-dashoffset",e.strokeDashoffset),Bt(t,"shape-rendering",e.shapeRendering),Bt(t,"paint-order",e.paintOrder),"frame"===e.clip){const e="plot-clip-"+ ++xt;t.attr("clip-path",`url(#${e})`).append("clipPath").attr("id",e).append("rect").attr("x",o).attr("y",a).attr("width",n-i-o).attr("height",r-a-s)}}function At(t,e){!function(t,e,n){null!=n&&t.style(e,n)}(t,"mix-blend-mode",e.mixBlendMode),Bt(t,"opacity",e.opacity)}function Rt(t,n,r){t.each((function(t){const o=n(t);if(null!=o){const t=document.createElementNS(e.namespaces.svg,"a");t.setAttributeNS(e.namespaces.xlink,"href",o),null!=r&&t.setAttribute("target",r),this.parentNode.insertBefore(t,this).appendChild(this)}}))}function Bt(t,e,n){null!=n&&t.attr(e,n)}function Ot(t,e,n,r,o){e&&e.bandwidth&&(r+=e.bandwidth()/2),n&&n.bandwidth&&(o+=n.bandwidth()/2),(r||o)&&t.attr("transform",`translate(${r},${o})`)}function Ct(t,e){if((t=h(t))!==e)return t}function St(t,e){if((t=p(t))!==e)return t}const zt=/^-?([_a-z]|[\240-\377]|\\[0-9a-f]{1,6}(\r\n|[ \t\r\n\f])?|\\[^\r\n\f0-9a-f])([_a-z0-9-]|[\240-\377]|\\[0-9a-f]{1,6}(\r\n|[ \t\r\n\f])?|\\[^\r\n\f0-9a-f])*$/;function Nt(t){if(void 0===t)return`plot-${Math.random().toString(16).slice(2)}`;if(t=`${t}`,!zt.test(t))throw new Error(`invalid class name: ${t}`);return t}function Et(t,e){if("string"==typeof e)t.property("style",e);else if(null!=e)for(const n of t)Object.assign(n.style,e)}function Tt({frameAnchor:t},{width:e,height:n,marginTop:r,marginRight:o,marginBottom:i,marginLeft:a}){return[/left$/.test(t)?a:/right$/.test(t)?e-o:(a+e-o)/2,/^top/.test(t)?r:/^bottom/.test(t)?n-i:(r+n-i)/2]}class Dt{constructor({name:t="x",axis:e,ticks:n,tickSize:r=("fx"===t?0:6),tickPadding:o=(0===r?9:3),tickFormat:i,fontVariant:a,grid:s,label:l,labelAnchor:c,labelOffset:u,line:f,tickRotate:d,ariaLabel:y,ariaDescription:g}={}){this.name=t,this.axis=$(e,"axis",["top","bottom"]),this.ticks=Pt(n),this.tickSize=p(r),this.tickPadding=p(o),this.tickFormat=qt(i),this.fontVariant=Ct(a,"normal"),this.grid=m(s),this.label=h(l),this.labelAnchor=k(c,"labelAnchor",["center","left","right"]),this.labelOffset=p(u),this.line=m(f),this.tickRotate=p(d),this.ariaLabel=h(y),this.ariaDescription=h(g)}render(t,{[this.name]:n,fy:r},{width:o,height:i,marginTop:a,marginRight:s,marginBottom:l,marginLeft:c,offsetLeft:u=0,facetMarginTop:f,facetMarginBottom:d,labelMarginLeft:h=0,labelMarginRight:p=0}){const{axis:m,fontVariant:y,grid:g,label:v,labelAnchor:x,labelOffset:w,line:b,name:k,tickRotate:$}=this,M="top"===m?-1:1,L=M*("x"===k?0:"top"===m?a-f:l-d)+("top"===m?a:i-l);return e.create("svg:g").call(Yt,this).attr("transform",`translate(${u},${L})`).call(Ft("top"===m?e.axisTop:e.axisBottom,n,this)).call(jt,$).attr("font-size",null).attr("font-family",null).attr("font-variant",y).call(b?()=>{}:t=>t.select(".domain").remove()).call(g?r?function(t,e,n){const r=e.bandwidth(),o=e.domain();return i=>i.selectAll(".tick").append("path").attr("stroke","currentColor").attr("stroke-opacity",.1).attr("d",(t?N(o,t):o).map((t=>`M0,${e(t)+n}v${r}`)).join(""))}(t,r,-L):(A=M*(l+a-i),t=>t.selectAll(".tick line").clone(!0).attr("stroke-opacity",.1).attr("y2",A)):()=>{}).call(v?t=>t.append("text").attr("fill","currentColor").attr("transform",`translate(${"center"===x?(o+c-s)/2:"right"===x?o+p:-h},${w*M})`).attr("dy","top"===m?"1em":"-0.32em").attr("text-anchor","center"===x?"middle":"right"===x?"end":"start").text(v):()=>{}).node();var A}}class Wt{constructor({name:t="y",axis:e,ticks:n,tickSize:r=("fy"===t?0:6),tickPadding:o=(0===r?9:3),tickFormat:i,fontVariant:a,grid:s,label:l,labelAnchor:c,labelOffset:u,line:f,tickRotate:d,ariaLabel:y,ariaDescription:g}={}){this.name=t,this.axis=$(e,"axis",["left","right"]),this.ticks=Pt(n),this.tickSize=p(r),this.tickPadding=p(o),this.tickFormat=qt(i),this.fontVariant=Ct(a,"normal"),this.grid=m(s),this.label=h(l),this.labelAnchor=k(c,"labelAnchor",["center","top","bottom"]),this.labelOffset=p(u),this.line=m(f),this.tickRotate=p(d),this.ariaLabel=h(y),this.ariaDescription=h(g)}render(t,{[this.name]:n,fx:r},{width:o,height:i,marginTop:a,marginRight:s,marginBottom:l,marginLeft:c,offsetTop:u=0,facetMarginLeft:f,facetMarginRight:d}){const{axis:h,fontVariant:p,grid:m,label:y,labelAnchor:g,labelOffset:v,line:x,name:w,tickRotate:b}=this,k="left"===h?-1:1,$=k*("y"===w?0:"left"===h?c-f:s-d)+("right"===h?o-s:c);return e.create("svg:g").call(Yt,this).attr("transform",`translate(${$},${u})`).call(Ft("right"===h?e.axisRight:e.axisLeft,n,this)).call(jt,b).attr("font-size",null).attr("font-family",null).attr("font-variant",p).call(x?()=>{}:t=>t.select(".domain").remove()).call(m?r?function(t,e,n){const r=e.bandwidth(),o=e.domain();return i=>i.selectAll(".tick").append("path").attr("stroke","currentColor").attr("stroke-opacity",.1).attr("d",(t?N(o,t):o).map((t=>`M${e(t)+n},0h${r}`)).join(""))}(t,r,-$):(M=k*(c+s-o),t=>t.selectAll(".tick line").clone(!0).attr("stroke-opacity",.1).attr("x2",M)):()=>{}).call(y?t=>t.append("text").attr("fill","currentColor").attr("transform",`translate(${v*k},${"center"===g?(i+a-l)/2:"bottom"===g?i-l:a})${"center"===g?" rotate(-90)":""}`).attr("dy","center"===g?"right"===h?"-0.32em":"0.75em":"bottom"===g?"1.4em":"-1em").attr("text-anchor","center"===g?"middle":"right"===h?"end":"start").text(y):()=>{}).node();var M}}function Yt(t,{name:e,label:n,ariaLabel:r=`${e}-axis`,ariaDescription:o=n}){Bt(t,"aria-label",r),Bt(t,"aria-description",o)}function Pt(t){return null===t?[]:t}function qt(t){return null===t?()=>null:t}function _t(t,n){return void 0===t?j(n)?st:h:"function"==typeof t?t:("string"==typeof t?j(n)?e.utcFormat:e.format:v)(t)}function Ft(t,e,{ticks:n,tickSize:r,tickPadding:o,tickFormat:i}){return e.tickFormat||(i=_t(i,e.domain())),t(e).ticks(Array.isArray(n)?null:n,"function"==typeof i?null:i).tickFormat("function"==typeof i?i:null).tickSizeInner(r).tickSizeOuter(0).tickPadding(o).tickValues(Array.isArray(n)?n:null)}function jt(t,e){if(e=+e)for(const n of t.selectAll("text")){const t=+n.getAttribute("x"),r=+n.getAttribute("y");if(Math.abs(r)>Math.abs(t)){const t=Math.sign(r);n.setAttribute("transform",`translate(0, ${r+4*t*Math.cos(e*ct)}) rotate(${e})`),n.setAttribute("text-anchor",Math.abs(e)<10?"middle":e<0^t>0?"start":"end")}else{const r=Math.sign(t);n.setAttribute("transform",`translate(${t+4*r*Math.abs(Math.sin(e*ct))}, 0) rotate(${e})`),n.setAttribute("text-anchor",Math.abs(e)>60?"middle":r>0?"start":"end")}n.removeAttribute("x"),n.removeAttribute("y"),n.setAttribute("dy","0.32em")}}const It=Symbol("position"),Gt=Symbol("color"),Xt=Symbol("radius"),Ut=Symbol("length"),Vt=Symbol("opacity"),Ht=Symbol("symbol"),Zt=new Map([["x",It],["y",It],["fx",It],["fy",It],["r",Xt],["color",Gt],["opacity",Vt],["symbol",Ht],["length",Ut]]),Qt=new Map([["accent",e.schemeAccent],["category10",e.schemeCategory10],["dark2",e.schemeDark2],["paired",e.schemePaired],["pastel1",e.schemePastel1],["pastel2",e.schemePastel2],["set1",e.schemeSet1],["set2",e.schemeSet2],["set3",e.schemeSet3],["tableau10",e.schemeTableau10],["brbg",Kt(e.schemeBrBG,e.interpolateBrBG)],["prgn",Kt(e.schemePRGn,e.interpolatePRGn)],["piyg",Kt(e.schemePiYG,e.interpolatePiYG)],["puor",Kt(e.schemePuOr,e.interpolatePuOr)],["rdbu",Kt(e.schemeRdBu,e.interpolateRdBu)],["rdgy",Kt(e.schemeRdGy,e.interpolateRdGy)],["rdylbu",Kt(e.schemeRdYlBu,e.interpolateRdYlBu)],["rdylgn",Kt(e.schemeRdYlGn,e.interpolateRdYlGn)],["spectral",Kt(e.schemeSpectral,e.interpolateSpectral)],["burd",te(e.schemeRdBu,e.interpolateRdBu)],["buylrd",te(e.schemeRdYlBu,e.interpolateRdYlBu)],["blues",Jt(e.schemeBlues,e.interpolateBlues)],["greens",Jt(e.schemeGreens,e.interpolateGreens)],["greys",Jt(e.schemeGreys,e.interpolateGreys)],["oranges",Jt(e.schemeOranges,e.interpolateOranges)],["purples",Jt(e.schemePurples,e.interpolatePurples)],["reds",Jt(e.schemeReds,e.interpolateReds)],["turbo",ee(e.interpolateTurbo)],["viridis",ee(e.interpolateViridis)],["magma",ee(e.interpolateMagma)],["inferno",ee(e.interpolateInferno)],["plasma",ee(e.interpolatePlasma)],["cividis",ee(e.interpolateCividis)],["cubehelix",ee(e.interpolateCubehelixDefault)],["warm",ee(e.interpolateWarm)],["cool",ee(e.interpolateCool)],["bugn",Jt(e.schemeBuGn,e.interpolateBuGn)],["bupu",Jt(e.schemeBuPu,e.interpolateBuPu)],["gnbu",Jt(e.schemeGnBu,e.interpolateGnBu)],["orrd",Jt(e.schemeOrRd,e.interpolateOrRd)],["pubu",Jt(e.schemePuBu,e.interpolatePuBu)],["pubugn",Jt(e.schemePuBuGn,e.interpolatePuBuGn)],["purd",Jt(e.schemePuRd,e.interpolatePuRd)],["rdpu",Jt(e.schemeRdPu,e.interpolateRdPu)],["ylgn",Jt(e.schemeYlGn,e.interpolateYlGn)],["ylgnbu",Jt(e.schemeYlGnBu,e.interpolateYlGnBu)],["ylorbr",Jt(e.schemeYlOrBr,e.interpolateYlOrBr)],["ylorrd",Jt(e.schemeYlOrRd,e.interpolateYlOrRd)],["rainbow",ne(e.interpolateRainbow)],["sinebow",ne(e.interpolateSinebow)]]);function Jt(t,n){return({length:r})=>1===r?[t[3][1]]:2===r?[t[3][1],t[3][2]]:(r=Math.max(3,Math.floor(r)))>9?e.quantize(n,r):t[r]}function Kt(t,n){return({length:r})=>2===r?[t[3][0],t[3][2]]:(r=Math.max(3,Math.floor(r)))>11?e.quantize(n,r):t[r]}function te(t,n){return({length:r})=>2===r?[t[3][2],t[3][0]]:(r=Math.max(3,Math.floor(r)))>11?e.quantize((t=>n(1-t)),r):t[r].slice().reverse()}function ee(t){return({length:n})=>e.quantize(t,Math.max(2,Math.floor(n)))}function ne(t){return({length:n})=>e.quantize(t,Math.floor(n)+1).slice(0,-1)}function re(t){const e=`${t}`.toLowerCase();if(!Qt.has(e))throw new Error(`unknown scheme: ${e}`);return Qt.get(e)}function oe(t,e){const n=re(t),r="function"==typeof n?n({length:e}):n;return r.length!==e?r.slice(0,e):r}const ie=new Map([["brbg",e.interpolateBrBG],["prgn",e.interpolatePRGn],["piyg",e.interpolatePiYG],["puor",e.interpolatePuOr],["rdbu",e.interpolateRdBu],["rdgy",e.interpolateRdGy],["rdylbu",e.interpolateRdYlBu],["rdylgn",e.interpolateRdYlGn],["spectral",e.interpolateSpectral],["burd",t=>e.interpolateRdBu(1-t)],["buylrd",t=>e.interpolateRdYlBu(1-t)],["blues",e.interpolateBlues],["greens",e.interpolateGreens],["greys",e.interpolateGreys],["purples",e.interpolatePurples],["reds",e.interpolateReds],["oranges",e.interpolateOranges],["turbo",e.interpolateTurbo],["viridis",e.interpolateViridis],["magma",e.interpolateMagma],["inferno",e.interpolateInferno],["plasma",e.interpolatePlasma],["cividis",e.interpolateCividis],["cubehelix",e.interpolateCubehelixDefault],["warm",e.interpolateWarm],["cool",e.interpolateCool],["bugn",e.interpolateBuGn],["bupu",e.interpolateBuPu],["gnbu",e.interpolateGnBu],["orrd",e.interpolateOrRd],["pubugn",e.interpolatePuBuGn],["pubu",e.interpolatePuBu],["purd",e.interpolatePuRd],["rdpu",e.interpolateRdPu],["ylgnbu",e.interpolateYlGnBu],["ylgn",e.interpolateYlGn],["ylorbr",e.interpolateYlOrBr],["ylorrd",e.interpolateYlOrRd],["rainbow",e.interpolateRainbow],["sinebow",e.interpolateSinebow]]);function ae(t){const e=`${t}`.toLowerCase();if(!ie.has(e))throw new Error(`unknown scheme: ${e}`);return ie.get(e)}const se=t=>e=>t(1-e),le=[0,1],ce=new Map([["number",e.interpolateNumber],["rgb",e.interpolateRgb],["hsl",e.interpolateHsl],["hcl",e.interpolateHcl],["lab",e.interpolateLab]]);function ue(t){const e=`${t}`.toLowerCase();if(!ce.has(e))throw new Error(`unknown interpolator: ${e}`);return ce.get(e)}function fe(t,n,r,{type:o,nice:i,clamp:a,zero:s,domain:l=me(t,r),unknown:c,round:u,scheme:f,range:d=(Zt.get(t)===Xt?ge(r,l):Zt.get(t)===Ut?ve(r,l):Zt.get(t)===Vt?le:void 0),interpolate:h=(Zt.get(t)===Gt?null==f&&void 0!==d?e.interpolateRgb:ae(void 0!==f?f:"cyclical"===o?"rainbow":"turbo"):u?e.interpolateRound:e.interpolateNumber),reverse:p}){if("cyclical"!==o&&"sequential"!==o||(o="linear"),p=!!p,"function"!=typeof h&&(h=ue(h)),1===h.length?(p&&(h=se(h),p=!1),void 0===d&&2===(d=Float64Array.from(l,((t,e)=>e/(l.length-1)))).length&&(d=le),n.interpolate((d===le?v:be)(h))):n.interpolate(h),s){const[t,n]=e.extent(l);(t>0||n<0)&&(nt(l=Array.from(l))<0?l[l.length-1]=0:l[0]=0)}return p&&(l=e.reverse(l)),n.domain(l).unknown(c),i&&(n.nice(!0===i?void 0:i),l=n.domain()),void 0!==d&&n.range(d),a&&n.clamp(a),{type:o,domain:l,range:d,scale:n,interpolate:h}}function de(t,n,{exponent:r=1,...o}){return fe(t,e.scalePow().exponent(r),n,{...o,type:"pow"})}function he(t,n,{domain:r=[0],unknown:o,scheme:i="rdylbu",interpolate:a,range:s=(void 0!==a?e.quantize(a,r.length+1):Zt.get(t)===Gt?oe(i,r.length+1):void 0),reverse:l}){const c=nt(M(r));if(!e.pairs(r).every((([t,n])=>function(t,n,r){const o=e.descending(t,n);return 0===o||o===r}(t,n,c))))throw new Error(`the ${t} scale has a non-monotonic domain`);return l&&(s=e.reverse(s)),{type:"threshold",scale:e.scaleThreshold(c<0?e.reverse(r):r,void 0===s?[]:s).unknown(o),domain:r,range:s}}function pe(t,n=ht){return t.length?[e.min(t,(({value:t})=>void 0===t?t:e.min(t,n))),e.max(t,(({value:t})=>void 0===t?t:e.max(t,n)))]:[0,1]}function me(t,e){const n=Zt.get(t);return(n===Xt||n===Vt||n===Ut?ye:pe)(e)}function ye(t){return[0,t.length?e.max(t,(({value:t})=>void 0===t?t:e.max(t,ht))):1]}function ge(t,n){const r=e.quantile(t,.5,(({value:t})=>void 0===t?NaN:e.quantile(t,.25,pt))),o=n.map((t=>3*Math.sqrt(t/r))),i=30/e.max(o);return i<1?o.map((t=>t*i)):o}function ve(t,n){const r=e.median(t,(({value:t})=>void 0===t?NaN:e.median(t,Math.abs))),o=n.map((t=>12*t/r)),i=60/e.max(o);return i<1?o.map((t=>t*i)):o}function xe(t){for(const{value:e}of t)if(void 0!==e)for(let n of e){if(n=+n,n>0)return pe(t,pt);if(n<0)return pe(t,mt)}return[1,10]}function we(t){const e=[];for(const{value:n}of t)if(void 0!==n)for(const t of n)e.push(t);return e}function be(t){return(e,n)=>r=>t(e+r*(n-e))}function ke(t,n,r,o,{type:i,nice:a,clamp:s,domain:l=pe(o),unknown:c,pivot:u=0,scheme:f,range:d,symmetric:h=!0,interpolate:p=(Zt.get(t)===Gt?null==f&&void 0!==d?e.interpolateRgb:ae(void 0!==f?f:"rdbu"):e.interpolateNumber),reverse:m}){u=+u;let[y,g]=l;if(y=Math.min(y,u),g=Math.max(g,u),"function"!=typeof p&&(p=ue(p)),void 0!==d&&(p=1===p.length?be(p)(...d):e.piecewise(p,d)),m&&(p=se(p)),h){const t=r.apply(u),e=t-r.apply(y),n=r.apply(g)-t;en&&(g=r.invert(t+e))}return n.domain([y,u,g]).unknown(c).interpolator(p),s&&n.clamp(s),a&&n.nice(a),{type:i,domain:[y,g],pivot:u,interpolate:p,scale:n}}function $e(t,n,{exponent:r=1,...o}){return ke(t,e.scaleDivergingPow().exponent(r=+r),function(t){return.5===t?Re:{apply:e=>Math.sign(e)*Math.pow(Math.abs(e),t),invert:e=>Math.sign(e)*Math.pow(Math.abs(e),1/t)}}(r),n,{...o,type:"diverging-pow"})}function Me(t,n,{constant:r=1,...o}){return ke(t,e.scaleDivergingSymlog().constant(r=+r),function(t){return{apply:e=>Math.sign(e)*Math.log1p(Math.abs(e/t)),invert:e=>Math.sign(e)*Math.expm1(Math.abs(e))*t}}(r),n,o)}const Le={apply:t=>t,invert:t=>t},Ae={apply:Math.log,invert:Math.exp},Re={apply:t=>Math.sign(t)*Math.sqrt(Math.abs(t)),invert:t=>Math.sign(t)*(t*t)};function Be(t,e,n,r){return fe(t,e,n,r)}const Oe=Symbol("ordinal");function Ce(t,n,{type:r,domain:o=Ne(n),range:i,reverse:a,hint:s}){return"categorical"!==r&&r!==Oe||(r="ordinal"),a&&(o=e.reverse(o)),t.domain(o),void 0!==i&&("function"==typeof i&&(i=i(o)),t.range(i)),{type:r,domain:o,range:i,scale:t,hint:s}}function Se(t,n,{type:r,domain:o=Ne(n),range:i,scheme:a,unknown:s,...l}){let c;if(Zt.get(t)===Ht)c=function(t){const e={};for(const{hint:n}of t)for(const t of["fill","stroke"]){const r=n[t];t in e?e[t]!==r&&(e[t]=void 0):e[t]=r}return e}(n),i=void 0===i?function(t){return H(t.fill)?e.symbolsStroke:e.symbolsFill}(c):Array.from(i,tt);else if(Zt.get(t)===Gt&&(void 0!==i||"ordinal"!==r&&r!==Oe||(i=function(t,e="greys"){const n=new Set,[r,o]=oe(e,2);for(const e of t)if(null!=e)if(!0===e)n.add(o);else{if(!1!==e)return;n.add(r)}return[...n]}(o,a),void 0!==i&&(a=void 0)),void 0===a&&void 0===i&&(a="ordinal"===r?"turbo":"tableau10"),void 0!==a))if(void 0!==i){const t=ae(a),n=i[0],r=i[1]-i[0];i=({length:o})=>e.quantize((e=>t(n+r*e)),o)}else i=re(a);if(s===e.scaleImplicit)throw new Error("implicit unknown is not supported");return Ce(e.scaleOrdinal().unknown(s),n,{...l,type:r,domain:o,range:i,hint:c})}function ze(t,e,n){let{round:r}=n;return void 0!==r&&t.round(r=!!r),(t=Ce(t,e,n)).round=r,t}function Ne(t){const n=new e.InternSet;for(const{value:e,domain:r}of t){if(void 0!==r)return r();if(void 0!==e)for(const t of e)n.add(t)}return e.sort(n,ft)}function Ee(t,e){if(void 0===t.range){const{insetLeft:n,insetRight:r}=t,{width:o,marginLeft:i=0,marginRight:a=0}=e,s=i+n,l=o-a-r;t.range=[s,Math.max(s,l)],je(t)||(t.range=We(t)),t.scale.range(t.range)}De(t)}function Te(t,e){if(void 0===t.range){const{insetTop:n,insetBottom:r}=t,{height:o,marginTop:i=0,marginBottom:a=0}=e,s=i+n,l=o-a-r;t.range=[Math.max(s,l),s],je(t)?t.range.reverse():t.range=We(t),t.scale.range(t.range)}De(t)}function De(t){void 0===t.round&&function({type:t}){return"point"===t||"band"===t}(t)&&function({scale:t}){const e=t.domain().length,[n,r]=t.range(),o=t.paddingInner?t.paddingInner():1,i=t.paddingOuter?t.paddingOuter():t.padding(),a=e-o,s=Math.abs(r-n)/Math.max(1,a+2*i);return(s-Math.floor(s))*a}(t)<=30&&t.scale.round(!0)}function We(t){const e=t.scale.domain().length+function({type:t}){return"threshold"===t}(t);if(!(e>2))return t.range;const[n,r]=t.range;return Array.from({length:e},((t,o)=>n+o/(e-1)*(r-n)))}function Ye(t,e,n){return Pe(t,void 0===n?void 0:[{hint:n}],{...e})}function Pe(t,n=[],r={}){const o=function(t,e,{type:n,domain:r,range:o,scheme:i}){if("fx"===t||"fy"===t)return"band";for(const{type:t}of e)if(void 0!==t)if(void 0===n)n=t;else if(n!==t)throw new Error(`scale incompatible with channel: ${n} !== ${t}`);if(void 0!==n)return n;if(void 0===r&&!e.some((({value:t})=>void 0!==t)))return;const a=Zt.get(t);if(a===Gt&&void 0===o&&void 0===i&&Fe(r,e,V))return"identity";if(a===Ht&&void 0===o&&Fe(r,e,K))return"identity";if(a===Xt)return"sqrt";if(a===Vt||a===Ut)return"linear";if(a===Ht)return"ordinal";if((r||o||[]).length>2)return _e(a);if(void 0!==r)return F(r)?_e(a):j(r)?"utc":"linear";const s=e.map((({value:t})=>t)).filter((t=>void 0!==t));return s.some(F)?_e(a):s.some(j)?"utc":"linear"}(t,n,r);if(void 0===r.type&&void 0===r.domain&&void 0===r.range&&"fx"!==t&&"fy"!==t&&je({type:o})){const e=n.map((({value:t})=>t)).filter((t=>void 0!==t));e.some(j)?gt(`Warning: some data associated with the ${t} scale are dates. Dates are typically associated with a "utc" or "time" scale rather than a "${qe(o)}" scale. If you are using a bar mark, you probably want a rect mark with the interval option instead; if you are using a group transform, you probably want a bin transform instead. If you want to treat this data as ordinal, you can suppress this warning by setting the type of the ${t} scale to "${qe(o)}".`):e.some(I)?gt(`Warning: some data associated with the ${t} scale are strings that appear to be dates (e.g., YYYY-MM-DD). If these strings represent dates, you should parse them to Date objects. Dates are typically associated with a "utc" or "time" scale rather than a "${qe(o)}" scale. If you are using a bar mark, you probably want a rect mark with the interval option instead; if you are using a group transform, you probably want a bin transform instead. If you want to treat this data as ordinal, you can suppress this warning by setting the type of the ${t} scale to "${qe(o)}".`):e.some(G)&>(`Warning: some data associated with the ${t} scale are strings that appear to be numbers. If these strings represent numbers, you should parse or coerce them to numbers. Numbers are typically associated with a "linear" scale rather than a "${qe(o)}" scale. If you want to treat this data as ordinal, you can suppress this warning by setting the type of the ${t} scale to "${qe(o)}".`)}switch(r.type=o,o){case"diverging":case"diverging-sqrt":case"diverging-pow":case"diverging-log":case"diverging-symlog":case"cyclical":case"sequential":case"linear":case"sqrt":case"threshold":case"quantile":case"pow":case"log":case"symlog":r=Ue(n,r,He,Float64Array);break;case"identity":switch(Zt.get(t)){case It:r=Ue(n,r,He,Float64Array);break;case Ht:r=Ue(n,r,tt)}break;case"utc":case"time":r=Ue(n,r,Ze)}switch(o){case"diverging":return function(t,n,r){return ke(t,e.scaleDiverging(),Le,n,r)}(t,n,r);case"diverging-sqrt":return function(t,e,n){return $e(t,e,{...n,exponent:.5})}(t,n,r);case"diverging-pow":return $e(t,n,r);case"diverging-log":return function(t,n,{base:r=10,pivot:o=1,domain:i=pe(n,o<0?mt:pt),...a}){return ke(t,e.scaleDivergingLog().base(r=+r),Ae,n,{domain:i,pivot:o,...a})}(t,n,r);case"diverging-symlog":return Me(t,n,r);case"categorical":case"ordinal":case Oe:return Se(t,n,r);case"cyclical":case"sequential":case"linear":return function(t,n,r){return fe(t,e.scaleLinear(),n,r)}(t,n,r);case"sqrt":return function(t,e,n){return de(t,e,{...n,exponent:.5})}(t,n,r);case"threshold":return he(t,0,r);case"quantile":return function(t,n,{range:r,quantiles:o=(void 0===r?5:(r=[...r]).length),n:i=o,scheme:a="rdylbu",domain:s=we(n),interpolate:l,reverse:c}){return void 0===r&&(r=void 0!==l?e.quantize(l,i):Zt.get(t)===Gt?oe(a,i):void 0),he(t,0,{domain:e.scaleQuantile(s,void 0===r?{length:i}:r).quantiles(),range:r,reverse:c})}(t,n,r);case"quantize":return function(t,n,{range:r,n:o=(void 0===r?5:(r=[...r]).length),scheme:i="rdylbu",domain:a=me(t,n),interpolate:s,reverse:l}){const[c,u]=e.extent(a);let f;return void 0===r?(f=e.ticks(c,u,o),f[0]<=c&&f.splice(0,1),f[f.length-1]>=u&&f.pop(),o=f.length+1,r=void 0!==s?e.quantize(s,o):Zt.get(t)===Gt?oe(i,o):void 0):(f=e.quantize(e.interpolateNumber(c,u),o+1).slice(1,-1),c instanceof Date&&(f=f.map((t=>new Date(t))))),nt(M(a))<0&&f.reverse(),he(t,0,{domain:f,range:r,reverse:l})}(t,n,r);case"pow":return de(t,n,r);case"log":return function(t,n,{base:r=10,domain:o=xe(n),...i}){return fe(t,e.scaleLog().base(r),n,{...i,domain:o})}(t,n,r);case"symlog":return function(t,n,{constant:r=1,...o}){return fe(t,e.scaleSymlog().constant(r),n,o)}(t,n,r);case"utc":return function(t,n,r){return Be(t,e.scaleUtc(),n,r)}(t,n,r);case"time":return function(t,n,r){return Be(t,e.scaleTime(),n,r)}(t,n,r);case"point":return function(t,n,{align:r=.5,padding:o=.5,...i}){return ze(e.scalePoint().align(r).padding(o),n,i)}(0,n,r);case"band":return function(t,n,{align:r=.5,padding:o=.1,paddingInner:i=o,paddingOuter:a=("fx"===t||"fy"===t?0:o),...s}){return ze(e.scaleBand().align(r).paddingInner(i).paddingOuter(a),n,s)}(t,n,r);case"identity":return Zt.get(t)===It?{type:"identity",scale:e.scaleIdentity()}:{type:"identity"};case void 0:return;default:throw new Error(`unknown scale type: ${o}`)}}function qe(t){return"symbol"==typeof t?t.description:t}function _e(t){switch(t){case It:return"point";case Gt:return Oe;default:return"ordinal"}}function Fe(t,e,n){return void 0!==t?X(t,n)&&U(t,n):e.some((({value:t})=>void 0!==t&&X(t,n)))&&e.every((({value:t})=>void 0===t||U(t,n)))}function je({type:t}){return"ordinal"===t||"point"===t||"band"===t||t===Oe}function Ie({range:t,domain:e=t}){return Math.sign(nt(e))*Math.sign(nt(t))}function Ge(t,e){const n=Object.create(null);for(let[r,{value:o,scale:i}]of t)void 0!==r&&(void 0!==i&&(i=e[i],void 0!==i&&(o=Array.from(o,i))),n[r]=o);return n}function Xe(t){const e=t.domain(),n=t(e[0]);for(let r=1,o=e.length;rt,invert:t=>t};const c=t.unknown?t.unknown():void 0;return{type:e,domain:Array.from(n),...void 0!==r&&{range:Array.from(r)},...void 0!==a&&{transform:a},...s&&{percent:s},...void 0!==o&&{label:o},...void 0!==c&&{unknown:c},...void 0!==i&&{interpolate:i},...t.clamp&&{clamp:t.clamp()},...void 0!==l&&{pivot:l,symmetric:!1},...t.base&&{base:t.base()},...t.exponent&&{exponent:t.exponent()},...t.constant&&{constant:t.constant()},...t.align&&{align:t.align(),round:t.round()},...t.padding&&(t.paddingInner?{paddingInner:t.paddingInner(),paddingOuter:t.paddingOuter()}:{padding:t.padding()}),...t.bandwidth&&{bandwidth:t.bandwidth(),step:t.step()},apply:e=>t(e),...t.invert&&{invert:e=>t.invert(e)}}}function Je(t,n,r){if(void 0===n.ticks){const[o,i]=e.extent(t.scale.range());n.ticks=(i-o)/r}}function Ke(t,e,n){void 0===t.labelAnchor&&(t.labelAnchor=je(e)?"center":Ie(e)<0?"left":"right"),void 0===t.label&&(t.label=nn(n,e,t,"x")),e.label=t.label}function tn(t,e,n,r){void 0===t.labelAnchor&&(t.labelAnchor=je(n)?"center":e&&"top"===e.axis?"bottom":"top"),void 0===t.label&&(t.label=nn(r,n,t,"y")),n.label=t.label}function en(t,e,n,r){r&&(e.label=r.label),void 0===e.label&&(e.label=nn(n,e,null,t))}function nn(t=[],e,n,r){let o;for(const{label:e}of t)if(void 0!==e)if(void 0===o)o=e;else if(o!==e)return;if(void 0!==o){if(function({type:t}){return"time"===t||"utc"===t}(e)&&/^(date|time|year)$/i.test(o))return;if(!je(e)&&(e.percent&&(o=`${o} (%)`),"x"===r||"y"===r)){const t=Ie(e);t&&(o="x"===r||n&&"center"===n.labelAnchor?"x"===r==t<0?`← ${o}`:`${o} →`:`${t<0?"↑ ":"↓ "}${o}`)}}return o}function rn(t){return je(t)?void 0:"tabular-nums"}function on({filter:t,sort:e,reverse:n,transform:r,...o}={},i){return void 0===r&&(null!=t&&(r=sn(t)),null==e||R(e)||(r=an(r,cn(e))),n&&(r=an(r,ln))),{...o,...R(e)&&{sort:e},transform:an(r,i)}}function an(t,e){return null==t?null===e?void 0:e:null==e?null===t?void 0:t:(n,r)=>(({data:n,facets:r}=t(n,r)),e(M(n),r))}function sn(t){return(e,n)=>{const r=l(e,t);return{data:e,facets:n.map((t=>t.filter((t=>r[t]))))}}}function ln(t,e){return{data:t,facets:e.map((t=>t.slice().reverse()))}}function cn(t){return("function"==typeof t&&1!==t.length?un:fn)(t)}function un(t){return(e,n)=>{const r=(n,r)=>t(e[n],e[r]);return{data:e,facets:n.map((t=>t.slice().sort(r)))}}}function fn(t){return(e,n)=>{const r=l(e,t),o=(t,e)=>ft(r[t],r[e]);return{data:e,facets:n.map((t=>t.slice().sort(o)))}}}function dn(t,e){return mn(null,null,t,e)}function hn(t={y:"count"},e={}){const{x:n=f}=e;if(null==n)throw new Error("missing channel: x");return mn(n,null,t,e)}function pn(t={x:"count"},e={}){const{y:n=f}=e;if(null==n)throw new Error("missing channel: y");return mn(null,n,t,e)}function mn(t,e,{data:n=Ln,filter:r,sort:o,reverse:i,...a}={},s={}){a=gn(a,s),n=bn(n,f),o=null==o?void 0:vn("sort",o,s),r=null==r?void 0:xn("filter",r,s);const[c,u]=W(t),[d,h]=W(e),{z:p,fill:m,stroke:y,x1:g,x2:v,y1:x,y2:b,...k}=s,[$,M]=W(p),[L]=w(m),[A]=w(y),[R=m,B]=W(L),[O=y,C]=W(A);return{..."z"in s&&{z:$||p},..."fill"in s&&{fill:R||m},..."stroke"in s&&{stroke:O||y},...on(k,((s,c)=>{const f=l(s,t),d=l(s,e),m=l(s,p),y=l(s,L),g=l(s,A),v=kn(a,m,y,g),x=[],w=[],b=f&&u([]),k=d&&h([]),$=m&&M([]),R=y&&B([]),O=g&&C([]);let S=0;for(const t of a)t.initialize(s);o&&o.initialize(s),r&&r.initialize(s);for(const t of c){const e=[];for(const e of a)e.scope("facet",t);o&&o.scope("facet",t),r&&r.scope("facet",t);for(const[i,l]of wn(t,v))for(const[t,c]of wn(l,d))for(const[l,u]of wn(c,f))if(!r||r.reduce(u)){e.push(S++),w.push(n.reduce(u,s)),f&&b.push(l),d&&k.push(t),m&&$.push(v===m?i:m[u[0]]),y&&R.push(v===y?i:y[u[0]]),g&&O.push(v===g?i:g[u[0]]);for(const t of a)t.reduce(u);o&&o.reduce(u)}x.push(e)}return $n(x,o,i),{data:w,facets:x}})),...!yn(a,"x")&&(c?{x:c}:{x1:g,x2:v}),...!yn(a,"y")&&(d?{y:d}:{y1:x,y2:b}),...Object.fromEntries(a.map((({name:t,output:e})=>[t,e])))}}function yn(t,...e){for(const{name:n}of t)if(e.includes(n))return!0;return!1}function gn(t,e){const n=Object.entries(t);return null!=e.title&&void 0===t.title&&n.push(["title",Rn]),null!=e.href&&void 0===t.href&&n.push(["href",An]),n.map((([t,n])=>null==n?{name:t,initialize(){},scope(){},reduce(){}}:vn(t,n,e)))}function vn(t,e,n){const r=xn(t,e,n),[o,i]=D(r.label);let a;return{name:t,output:o,initialize(t){r.initialize(t),a=i([])},scope(t,e){r.scope(t,e)},reduce(t,e){a.push(r.reduce(t,e))}}}function xn(t,e,n){const r=T(t,n),o=bn(e,r);let i,a;return{label:Y(o===On?null:r,o.label),initialize(t){i=void 0===r?t:l(t,r),"data"===o.scope&&(a=o.reduce(S(t),i))},scope(t,e){o.scope===t&&(a=o.reduce(e,i))},reduce:(t,e)=>null==o.scope?o.reduce(t,i,e):o.reduce(t,i,a,e)}}function wn(t,n){return n?e.sort(e.group(t,(t=>n[t])),y):[[,t]]}function bn(t,n){if(t&&"function"==typeof t.reduce)return t;if("function"==typeof t)return r=t,{reduce:(t,e,n)=>r(N(e,t),n)};var r;if(/^p\d{2}$/i.test(t))return Mn(x(t));switch(`${t}`.toLowerCase()){case"first":return An;case"last":return Bn;case"count":return On;case"distinct":return Cn;case"sum":return null==n?On:Sn;case"proportion":return zn(n,"data");case"proportion-facet":return zn(n,"facet");case"deviation":return Mn(e.deviation);case"min":return Mn(e.min);case"min-index":return Mn(e.minIndex);case"max":return Mn(e.max);case"max-index":return Mn(e.maxIndex);case"mean":return Mn(e.mean);case"median":return Mn(e.median);case"variance":return Mn(e.variance);case"mode":return Mn(e.mode);case"x":return En;case"x1":return Dn;case"x2":return Wn;case"y":return Tn;case"y1":return Yn;case"y2":return Pn}throw new Error(`invalid reduce: ${t}`)}function kn(t,e,n,r){return function(...t){for(const e of t)if(void 0!==e)return e}(t.some((t=>"z"===t.name))?void 0:e,t.some((t=>"fill"===t.name))?void 0:n,t.some((t=>"stroke"===t.name))?void 0:r)}function $n(t,e,n){if(e){const n=e.output.transform(),r=(t,e)=>ft(n[t],n[e]);t.forEach((t=>t.sort(r)))}n&&t.forEach((t=>t.reverse()))}function Mn(t){return{reduce:(e,n)=>t(e,(t=>n[t]))}}const Ln={reduce:(t,e)=>N(e,t)},An={reduce:(t,e)=>e[t[0]]},Rn={reduce(t,n){const r=e.sort(e.rollup(t,(t=>t.length),(t=>n[t])),g),o=r.slice(-5).reverse();if(o.length`${t} (${e.toLocaleString("en-US")})`)).join("\n")}},Bn={reduce:(t,e)=>e[t[t.length-1]]},On={label:"Frequency",reduce:t=>t.length},Cn={label:"Distinct",reduce:(t,n)=>{const r=new e.InternSet;for(const e of t)r.add(n[e]);return r.size}},Sn=Mn(e.sum);function zn(t,n){return null==t?{scope:n,label:"Frequency",reduce:(t,e,n=1)=>t.length/n}:{scope:n,reduce:(t,n,r=1)=>e.sum(t,(t=>n[t]))/r}}function Nn(t,e){const n=(+t+ +e)/2;return t instanceof Date?new Date(n):n}const En={reduce:(t,e,{x1:n,x2:r})=>Nn(n,r)},Tn={reduce:(t,e,{y1:n,y2:r})=>Nn(n,r)},Dn={reduce:(t,e,{x1:n})=>n},Wn={reduce:(t,e,{x2:n})=>n},Yn={reduce:(t,e,{y1:n})=>n},Pn={reduce:(t,e,{y2:n})=>n};function qn(t,{scale:e,type:n,value:r,filter:o,hint:i}){return{scale:e,type:n,value:l(t,r),label:Y(r),filter:o,hint:i}}function _n(t,e,n){const r=Fn(t,e),o=Fn(t,n);return Float64Array.from(o,((t,e)=>Math.abs(t-r[e])))}function Fn(t,e,n){let r=t.find((([t])=>t===e));if(r||void 0===n||(r=t.find((([t])=>t===n))),r)return r[1].value;throw new Error(`missing channel: ${e}`)}function jn([t,n],[r,o]){return e.ascending(n,o)||e.ascending(t,r)}function In([t,n],[r,o]){return e.descending(n,o)||e.ascending(t,r)}function Gn({y:t,fy:e,fx:n}){const r=e?e.scale.domain().length:1,o=t?je(t)?t.scale.domain().length:Math.max(7,17/r):1;return!(!t&&!e)*Math.max(1,Math.min(60,o*r))*20+30*!!n+60}function Xn(t,{label:n=t.label,tickSize:r=6,width:o=240,height:i=44+r,marginTop:a=18,marginRight:s=0,marginBottom:l=16+r,marginLeft:c=0,style:u,ticks:f=(o-c-s)/64,tickFormat:d,fontVariant:h=rn(t),round:p=!0,className:m}){m=Nt(m),null===d&&(d=()=>null);const y=e.create("svg").attr("class",m).attr("font-family","system-ui, sans-serif").attr("font-size",10).attr("width",o).attr("height",i).attr("viewBox",`0 0 ${o} ${i}`).call((t=>t.append("style").text(`\n .${m} {\n display: block;\n background: white;\n height: auto;\n height: intrinsic;\n max-width: 100%;\n overflow: visible;\n }\n .${m} text {\n white-space: pre;\n }\n `))).call(Et,u);let g,v=t=>t.selectAll(".tick line").attr("y1",a+l-i);const x=p?(t,e)=>t.rangeRound(e):(t,e)=>t.range(e),{type:w,domain:b,range:k,interpolate:$,scale:M,pivot:L}=t;if($){const t=void 0===k?$:e.piecewise(1===$.length?be($):$,k);g=x(M.copy(),e.quantize(e.interpolateNumber(c,o-s),Math.min(b.length+(void 0!==L),void 0===k?1/0:k.length))),y.append("image").attr("x",c).attr("y",a).attr("width",o-c-s).attr("height",i-a-l).attr("preserveAspectRatio","none").attr("xlink:href",function(t,n=256){const r=e.create("canvas").attr("width",n).attr("height",1).node(),o=r.getContext("2d");for(let e=0;et:"string"==typeof d?e.format(d):d;g=x(e.scaleLinear().domain([-1,k.length-1]),[c,o-s]),y.append("g").selectAll().data(k).enter().append("rect").attr("x",((t,e)=>g(e-1))).attr("y",a).attr("width",((t,e)=>g(e)-g(e-1))).attr("height",i-a-l).attr("fill",(t=>t)),f=Array.from(t,((t,e)=>e)),d=e=>n(t[e],e)}else g=x(e.scaleBand().domain(b),[c,o-s]),y.append("g").selectAll().data(b).enter().append("rect").attr("x",g).attr("y",a).attr("width",Math.max(0,g.bandwidth()-1)).attr("height",i-a-l).attr("fill",M),v=()=>{};return y.append("g").attr("transform",`translate(0,${i-l})`).call(e.axisBottom(g).ticks(Array.isArray(f)?null:f,"string"==typeof d?d:void 0).tickFormat("function"==typeof d?d:void 0).tickSize(r).tickValues(Array.isArray(f)?f:null)).attr("font-size",null).attr("font-family",null).attr("font-variant",Ct(h,"normal")).call(v).call((t=>t.select(".domain").remove())).call(void 0===n?()=>{}:t=>t.append("text").attr("x",c).attr("y",a+l-i-6).attr("fill","currentColor").attr("text-anchor","start").attr("font-weight","bold").text(n)),y.node()}function Un(t,e){if(null==e)return e;const n=t(e);if(!n)throw new Error(`scale not found: ${e}`);return n}function Vn(t,{columns:n,tickFormat:r,fontVariant:o=rn(t),swatchSize:i=15,swatchWidth:a=i,swatchHeight:s=i,marginLeft:l=0,className:c,style:u,width:f}={},d,h){c=Nt(c),r=_t(r,t.domain);const p=e.create("div").attr("class",c).attr("style",`\n --swatchWidth: ${+a}px;\n --swatchHeight: ${+s}px;\n `);let m;return null!=n?(m=`\n .${c}-swatch {\n display: flex;\n align-items: center;\n break-inside: avoid;\n padding-bottom: 1px;\n }\n .${c}-swatch::before {\n flex-shrink: 0;\n }\n .${c}-label {\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n `,p.style("columns",n).selectAll().data(t.domain).enter().append("div").attr("class",`${c}-swatch`).call(d,t).call((t=>t.append("div").attr("class",`${c}-label`).attr("title",r).text(r)))):(m=`\n .${c} {\n display: flex;\n align-items: center;\n min-height: 33px;\n flex-wrap: wrap;\n }\n .${c}-swatch {\n display: inline-flex;\n align-items: center;\n margin-right: 1em;\n }\n `,p.selectAll().data(t.domain).enter().append("span").attr("class",`${c}-swatch`).call(d,t).append((function(){return document.createTextNode(r.apply(this,arguments))}))),p.call((t=>t.insert("style","*").text(`\n .${c} {\n font-family: system-ui, sans-serif;\n font-size: 10px;\n margin-bottom: 0.5em;${void 0===l?"":`\n margin-left: ${+l}px;`}${void 0===f?"":`\n width: ${f}px;`}\n }\n ${h(c)}\n ${m}\n `))).style("font-variant",Ct(o,"normal")).call(Et,u).node()}const Hn=new Map([["symbol",function(t,{fill:n=(void 0!==t.hint?.fill?t.hint.fill:"none"),fillOpacity:r=1,stroke:o=(void 0!==t.hint?.stroke?t.hint.stroke:H(n)?"currentColor":"none"),strokeOpacity:i=1,strokeWidth:a=1.5,r:s=4.5,...l}={},c){const[u,f]=w(n),[d,h]=w(o),p=Un(c,u),m=Un(c,d),y=s*s*Math.PI;return r=b(r)[1],i=b(i)[1],a=b(a)[1],Vn(t,l,(n=>n.append("svg").attr("viewBox","-8 -8 16 16").attr("fill","color"===u?t=>p.scale(t):null).attr("stroke","color"===d?t=>m.scale(t):null).append("path").attr("d",(n=>{const r=e.path();return t.scale(n).draw(r,y),r}))),(t=>`.${t}-swatch > svg {\n width: var(--swatchWidth);\n height: var(--swatchHeight);\n margin-right: 0.5em;\n overflow: visible;\n fill: ${f};\n fill-opacity: ${r};\n stroke: ${h};\n stroke-width: ${a}px;\n stroke-opacity: ${i};\n }`))}],["color",Qn],["opacity",function({type:t,interpolate:n,...r},{legend:o=!0,color:i=e.rgb(0,0,0),...a}){if(!n)throw new Error(`${t} opacity scales are not supported`);!0===o&&(o="ramp");if("ramp"!==`${o}`.toLowerCase())throw new Error(`${o} opacity legends are not supported`);return Qn({type:t,...r,interpolate:Jn(i)},{legend:o,...a})}]]);function Zn({label:t,ticks:e,tickFormat:n}={},r={}){return{label:t,ticks:e,tickFormat:n,...r}}function Qn(t,{legend:e=!0,...n}){if(!0===e&&(e="ordinal"===t.type?"swatches":"ramp"),void 0!==t.domain)switch(`${e}`.toLowerCase()){case"swatches":return function(t,e){return Vn(t,e,(e=>e.style("--color",t.scale)),(t=>`.${t}-swatch::before {\n content: "";\n width: var(--swatchWidth);\n height: var(--swatchHeight);\n margin-right: 0.5em;\n background: var(--color);\n }`))}(t,n);case"ramp":return Xn(t,n);default:throw new Error(`unknown legend type: ${e}`)}}function Jn(t){const{r:n,g:r,b:o}=e.rgb(t)||e.rgb(0,0,0);return t=>`rgba(${n},${r},${o},${t})`}function Kn(t={}){const{facet:n,style:r,caption:o,ariaLabel:i,ariaDescription:a}=t,s=Nt(t.className),l=void 0===t.marks?[]:t.marks.flat(1/0).map(nr),c=new Map,u=new Map;let f,d,h,p,m;if(void 0!==n){const{x:t,y:e}=n;if(null!=t||null!=e){const r=M(n.data);if(h=[],null!=t){const e=qn(r,{value:t,scale:"fx"});h.push(["fx",e]),u.set("fx",[e])}if(null!=e){const t=qn(r,{value:e,scale:"fy"});h.push(["fy",t]),u.set("fy",[t])}d=S(r),y=d,f=((v=h).length>1?ar:ir)(y,...v),p=Array.from(f,g)}}var y,v;for(const t of l){if(c.has(t))throw new Error("duplicate mark; each mark must be unique");const r=void 0===f?void 0:"auto"===t.facet?t.data===n.data?p:void 0:"include"===t.facet?p:"exclude"===t.facet?m||(m=p.map((t=>Uint32Array.from(e.difference(d,t))))):void 0,{index:o,channels:i}=t.initialize(r,h);for(const[,t]of i){const{scale:e}=t;if(void 0!==e){const n=u.get(e);void 0!==n?n.push(t):u.set(e,[t])}}c.set(t,{index:o,channels:i,faceted:void 0!==r})}for(const[e,n]of u){const{percent:r,transform:o=(r?t=>100*t:void 0)}=t[e]||{};if(null!=o)for(const t of n)t.value=Array.from(t.value,o)}const x=function(t,{inset:e=0,insetTop:n=e,insetRight:r=e,insetBottom:o=e,insetLeft:i=e,round:a,nice:s,clamp:l,align:c,padding:u,...f}={}){const d={};for(const e of Zt.keys()){const h=t.get(e),p=f[e];if(h||p){const t=Pe(e,h,{round:Zt.get(e)===It?a:void 0,nice:s,clamp:l,align:c,padding:u,...p});if(t){let{percent:a,transform:s,inset:l,insetTop:c=(void 0!==l?l:"y"===e?n:0),insetRight:u=(void 0!==l?l:"x"===e?r:0),insetBottom:f=(void 0!==l?l:"y"===e?o:0),insetLeft:h=(void 0!==l?l:"x"===e?i:0)}=p||{};if(null==s)s=void 0;else if("function"!=typeof s)throw new Error("invalid scale transform; not a function");t.percent=!!a,t.transform=s,"x"===e||"fx"===e?(t.insetLeft=+h,t.insetRight=+u):"y"!==e&&"fy"!==e||(t.insetTop=+c,t.insetBottom=+f),d[e]=t}}}return d}(u,t),w=function(t){return Object.fromEntries(Object.entries(t).map((([t,{scale:e}])=>[t,e])))}(x),b=function({x:t,y:e,fx:n,fy:r},{x:o={},y:i={},fx:a={},fy:s={},axis:l=!0,grid:c,line:u,label:f,facet:{axis:d=l,grid:h,label:p=f}={}}={}){let{axis:m=l}=o,{axis:y=l}=i,{axis:g=d}=a,{axis:v=d}=s;return t?!0===m&&(m="bottom"):m=null,e?!0===y&&(y="left"):y=null,n?!0===g&&(g="bottom"===m?"top":"bottom"):g=null,r?!0===v&&(v="left"===y?"right":"left"):v=null,{...m&&{x:new Dt({grid:c,line:u,label:f,fontVariant:rn(t),...o,axis:m})},...y&&{y:new Wt({grid:c,line:u,label:f,fontVariant:rn(e),...i,axis:y})},...g&&{fx:new Dt({name:"fx",grid:h,label:p,...a,axis:g})},...v&&{fy:new Wt({name:"fy",grid:h,label:p,...s,axis:v})}}}(x,t),k=function(t,{x:{axis:e}={},y:{axis:n}={},fx:{axis:r}={},fy:{axis:o}={}},{width:i=640,height:a=Gn(t),facet:{margin:s,marginTop:l=(void 0!==s?s:"top"===r?30:0),marginRight:c=(void 0!==s?s:"right"===o?40:0),marginBottom:u=(void 0!==s?s:"bottom"===r?30:0),marginLeft:f=(void 0!==s?s:"left"===o?40:0)}={},margin:d,marginTop:h=(void 0!==d?d:Math.max(("top"===e?30:0)+l,n||o?20:.5-vt)),marginRight:p=(void 0!==d?d:Math.max(("right"===n?40:0)+c,e||r?20:.5+vt)),marginBottom:m=(void 0!==d?d:Math.max(("bottom"===e?30:0)+u,n||o?20:.5+vt)),marginLeft:y=(void 0!==d?d:Math.max(("left"===n?40:0)+f,e||r?20:.5-vt))}={}){return{width:i,height:a,marginTop:h,marginRight:p,marginBottom:m,marginLeft:y,facetMarginTop:l,facetMarginRight:c,facetMarginBottom:u,facetMarginLeft:f}}(x,b,t);!function({x:t,y:e,fx:n,fy:r},o){n&&Ee(n,o),r&&Te(r,o),t&&Ee(t,n?{width:n.scale.bandwidth()}:o),e&&Te(e,r?{height:r.scale.bandwidth()}:o)}(x,k),function(t,e,{x:n,y:r,fx:o,fy:i},a,s){if(o&&(Ke(o,e.fx,t.get("fx")),void 0===o.labelOffset)){const{facetMarginTop:t,facetMarginBottom:e}=a;o.labelOffset="top"===o.axis?t:e}if(i&&(tn(i,o,e.fy,t.get("fy")),void 0===i.labelOffset)){const{facetMarginLeft:t,facetMarginRight:e}=a;i.labelOffset="left"===i.axis?t:e}if(n&&(Ke(n,e.x,t.get("x")),void 0===n.labelOffset)){const{marginTop:t,marginBottom:e,facetMarginTop:r,facetMarginBottom:o}=a;n.labelOffset="top"===n.axis?t-r:e-o}if(r&&(tn(r,n,e.y,t.get("y")),void 0===r.labelOffset)){const{marginRight:t,marginLeft:e,facetMarginLeft:n,facetMarginRight:o}=a;r.labelOffset="left"===r.axis?e-n:t-o}for(const[n,r]of Zt)r!==It&&e[n]&&en(n,e[n],t.get(n),s[n])}(u,x,b,k,t),function({x:t,y:e,fx:n,fy:r},{x:o,y:i,fx:a,fy:s}){a&&Je(n,a,80),s&&Je(r,s,35),o&&Je(t,o,80),i&&Je(e,i,35)}(x,b);for(const t of c.values())t.values=Ge(t.channels,w);const{width:$,height:L}=k,A=e.create("svg").attr("class",s).attr("fill","currentColor").attr("font-family","system-ui, sans-serif").attr("font-size",10).attr("text-anchor","middle").attr("width",$).attr("height",L).attr("viewBox",`0 0 ${$} ${L}`).attr("aria-label",i).attr("aria-description",a).call((t=>t.append("style").text(`\n .${s} {\n display: block;\n background: white;\n height: auto;\n height: intrinsic;\n max-width: 100%;\n }\n .${s} text,\n .${s} tspan {\n white-space: pre;\n }\n `))).call(Et,r).node(),{fx:R,fy:B}=w,O=b[void 0!==f&&B?"fy":"y"],C=b[void 0!==f&&R?"fx":"x"];if(O&&A.appendChild(O.render(null,w,k)),C&&A.appendChild(C.render(null,w,k)),void 0!==f){const t=B&&B.domain(),n=R&&R.domain(),r=B&&{marginTop:0,marginBottom:0,height:B.bandwidth()},o=R&&{marginRight:0,marginLeft:0,width:R.bandwidth()},i={...k,...o,...r},a=function(t){return new(t.length>1?lr:sr)}(h);f.forEach((([t],e)=>a.set(t,e)));const s=e.select(A);if(B&&b.y){const e=b.y,o=or(e),i="bottom"===e.labelAnchor?t.length-1:"center"===e.labelAnchor?t.length>>1:0;s.selectAll().data(t).enter().append(((t,s)=>(s===i?e:o).render(R&&z(n,(e=>a.has([e,t]))),w,{...k,...r,offsetTop:B(t)})))}if(R&&b.x){const e=b.x,r=or(e),i="right"===e.labelAnchor?n.length-1:"center"===e.labelAnchor?n.length>>1:0,{marginLeft:l,marginRight:c}=k;s.selectAll().data(n).enter().append(((n,s)=>(s===i?e:r).render(B&&z(t,(t=>a.has([n,t]))),w,{...k,...o,labelMarginLeft:l,labelMarginRight:c,offsetLeft:R(n)})))}s.selectAll().data(function({fx:t,fy:n}){return t&&n?e.cross(t.domain(),n.domain()):t?t.domain():n.domain()}(w).filter(a.has,a)).enter().append("g").attr("aria-label","facet").attr("transform",function(t,e){return t&&e?([n,r])=>`translate(${t(n)},${e(r)})`:t?e=>`translate(${t(e)},0)`:t=>`translate(0,${e(t)})`}(R,B)).each((function(t){const e=a.get(t);for(const[t,{channels:n,values:r,index:o,faceted:a}]of c){const s=t.filter(a?o[e]:o,n,r),l=t.render(s,w,r,i);null!=l&&this.appendChild(l)}}))}else for(const[t,{channels:e,values:n,index:r}]of c){const o=t.filter(r,e,n),i=t.render(o,w,n,k);null!=i&&A.appendChild(i)}let N=A;const E=function(t,e){const n=[];for(const[r,o]of Hn){const i=e[r];if(i?.legend&&r in t){const e=o(t[r],Zn(t[r],i),(e=>t[e]));null!=e&&n.push(e)}}return n}(x,t);if((null!=o||E.length>0)&&(N=document.createElement("figure"),N.style.maxWidth="initial",N.append(...E,A),null!=o)){const t=document.createElement("figcaption");t.append(o),N.append(t)}N.scale=function(t){return e=>{if(!Zt.has(e=`${e}`))throw new Error(`unknown scale: ${e}`);return e in t?Qe(t[e]):void 0}}(x),N.legend=function(t,e={}){return(n,r)=>{if(!Hn.has(n))throw new Error(`unknown legend type: ${n}`);if(n in t)return Hn.get(n)(t[n],Zn(e[n],r),(e=>t[e]))}}(x,t);const T=function(){const t=yt;return yt=0,t}();return T>0&&e.select(A).append("text").attr("x",$).attr("y",20).attr("dy","-1em").attr("text-anchor","end").attr("font-family","initial").text("⚠️").append("title").text(`${T.toLocaleString("en-US")} warning${1===T?"":"s"}. Please check the console.`),N}class tr{constructor(t,e=[],n={},r){const{facet:o="auto",sort:i,dx:a,dy:s,clip:l}=n,c=new Set;this.data=t,this.sort=R(i)?i:null,this.facet=null==o||!1===o?null:$(!0===o?"include":o,"facet",["auto","include","exclude"]);const{transform:u}=on(n);this.transform=u,void 0!==r&&(e=function(t,{title:e,href:n,ariaLabel:r,ariaDescription:o,ariaHidden:i,target:a,fill:s,fillOpacity:l,stroke:c,strokeWidth:u,strokeOpacity:f,strokeLinejoin:d,strokeLinecap:p,strokeMiterlimit:m,strokeDasharray:y,strokeDashoffset:g,opacity:v,mixBlendMode:x,paintOrder:k,shapeRendering:$},M,{ariaLabel:L,fill:A="currentColor",fillOpacity:R,stroke:B="none",strokeOpacity:O,strokeWidth:C,strokeLinecap:S,strokeLinejoin:z,strokeMiterlimit:N,paintOrder:E}){null===A&&(s=null,l=null),null===B&&(c=null,f=null),H(A)?H(B)||H(s)||(B="none"):H(B)&&!H(c)&&(A="none");const[T,D]=w(s,A),[W,Y]=b(l,R),[P,q]=w(c,B),[_,F]=b(f,O),[j,I]=b(v);Z(q)||(void 0===u&&(u=C),void 0===p&&(p=S),void 0===d&&(d=z),void 0!==m||/^\s*round\s*$/i.test(d)||(m=N),Z(D)||void 0!==k||(k=E));const[G,X]=b(u);return null!==A&&(t.fill=Ct(D,"currentColor"),t.fillOpacity=St(Y,1)),null!==B&&(t.stroke=Ct(q,"none"),t.strokeWidth=St(X,1),t.strokeOpacity=St(F,1),t.strokeLinejoin=Ct(d,"miter"),t.strokeLinecap=Ct(p,"butt"),t.strokeMiterlimit=St(m,4),t.strokeDasharray=Ct(y,"none"),t.strokeDashoffset=Ct(g,"0")),t.target=h(a),t.ariaLabel=h(L),t.ariaDescription=h(o),t.ariaHidden=h(i),t.opacity=St(I,1),t.mixBlendMode=Ct(x,"normal"),t.paintOrder=Ct(k,"normal"),t.shapeRendering=Ct($,"auto"),[...M,{name:"title",value:e,optional:!0},{name:"href",value:n,optional:!0},{name:"ariaLabel",value:r,optional:!0},{name:"fill",value:T,scale:"color",optional:!0},{name:"fillOpacity",value:W,scale:"opacity",optional:!0},{name:"stroke",value:P,scale:"color",optional:!0},{name:"strokeOpacity",value:_,scale:"opacity",optional:!0},{name:"strokeWidth",value:G,optional:!0},{name:"opacity",value:j,scale:"opacity",optional:!0}]}(this,n,e,r)),this.channels=e.filter((t=>{const{name:e,value:n,optional:r}=t;if(null==n){if(r)return!1;throw new Error(`missing channel value: ${e}`)}if(null==e)throw new Error("missing channel name");const o=`${e}`;if("__proto__"===o)throw new Error(`illegal channel name: ${o}`);if(c.has(o))throw new Error(`duplicate channel: ${o}`);return c.add(o),!0})),this.dx=+a||0,this.dy=+s||0,this.clip=function(t){if(!0===t)return"frame";if(null==t||!1===t)return!1;throw new Error(`invalid clip method: ${t}`)}(l)}initialize(t,n){let r=M(this.data),o=void 0===t&&null!=r?S(r):t;void 0!==r&&void 0!==this.transform&&(void 0===t&&(o=o.length?[o]:[]),({facets:o,data:r}=this.transform(r,o)),r=M(r),void 0===t&&o.length&&([o]=o));const i=this.channels.map((t=>{const{name:e}=t;return[null==e?void 0:`${e}`,qn(r,t)]}));return null!=this.sort&&function(t,n,r,o){const{reverse:i,reduce:a=!0,limit:s}=o;for(const l in o){if(!Zt.has(l))continue;let{value:c,reverse:u=i,reduce:f=a,limit:d=s}=q(o[l]);if(void 0===u&&(u="width"===c||"height"===c),null==f||!1===f)continue;const h=t.find((([,{scale:t}])=>t===l))||n&&n.find((([,{scale:t}])=>t===l));if(!h)throw new Error(`missing channel for scale: ${l}`);const p=h[1].value,[m=0,g=1/0]=d&&"function"==typeof d[Symbol.iterator]?d:d<0?[d]:[0,d];if(null==c)h[1].domain=()=>{let t=p;return u&&(t=t.slice().reverse()),0===m&&g===1/0||(t=t.slice(m,g)),t};else{const n="data"===c?r:"height"===c?_n(t,"y1","y2"):"width"===c?_n(t,"x1","x2"):Fn(t,c,"y"===c?"y2":"x"===c?"x2":void 0),o=bn(!0===f?"max":f,n);h[1].domain=()=>{let t=e.rollup(S(p),(t=>o.reduce(t,n)),(t=>p[t]));return t=e.sort(t,u?In:jn),0===m&&g===1/0||(t=t.slice(m,g)),t.map(y)}}}}(i,n,r,this.sort),{index:o,channels:i}}filter(t,e,n){for(const[r,{filter:o=ut}]of e)if(void 0!==r&&null!==o){const e=n[r];t=t.filter((t=>o(e[t])))}return t}plot({marks:t=[],...e}={}){return Kn({...e,marks:[...t,this]})}}function er(...t){return t.plot=tr.prototype.plot,t}function nr(t){return t instanceof tr?t:new rr(t)}class rr extends tr{constructor(t){if(super(),null!=t){if("function"!=typeof t)throw new TypeError("invalid mark; missing render function");this.render=t}}render(){}}function or(t){return void 0===t||void 0===t.label?t:Object.assign(Object.create(t),{label:void 0})}function ir(t,[,{value:n}]){return e.groups(t,(t=>n[t]))}function ar(t,[,{value:n}],[,{value:r}]){return e.groups(t,(t=>n[t]),(t=>r[t])).flatMap((([t,e])=>e.map((([e,n])=>[[t,e],n]))))}class sr{constructor(){this._=new e.InternMap}has(t){return this._.has(t)}get(t){return this._.get(t)}set(t,e){return this._.set(t,e),this}}class lr extends sr{has([t,e]){const n=super.get(t);return!!n&&n.has(e)}get([t,e]){const n=super.get(t);return n&&n.get(e)}set([t,n],r){const o=super.get(t);return o?o.set(n,r):super.set(t,new e.InternMap([[n,r]])),this}}const cr=new Map([["basis",e.curveBasis],["basis-closed",e.curveBasisClosed],["basis-open",e.curveBasisOpen],["bundle",e.curveBundle],["bump-x",e.curveBumpX],["bump-y",e.curveBumpY],["cardinal",e.curveCardinal],["cardinal-closed",e.curveCardinalClosed],["cardinal-open",e.curveCardinalOpen],["catmull-rom",e.curveCatmullRom],["catmull-rom-closed",e.curveCatmullRomClosed],["catmull-rom-open",e.curveCatmullRomOpen],["linear",e.curveLinear],["linear-closed",e.curveLinearClosed],["monotone-x",e.curveMonotoneX],["monotone-y",e.curveMonotoneY],["natural",e.curveNatural],["step",e.curveStep],["step-after",e.curveStepAfter],["step-before",e.curveStepBefore]]);function ur(t=e.curveLinear,n){if("function"==typeof t)return t;const r=cr.get(`${t}`.toLowerCase());if(!r)throw new Error(`unknown curve: ${t}`);if(void 0!==n)switch(r){case e.curveBundle:return r.beta(n);case e.curveCardinalClosed:case e.curveCardinalOpen:case e.curveCardinal:return r.tension(n);case e.curveCatmullRomClosed:case e.curveCatmullRomOpen:case e.curveCatmullRom:return r.alpha(n)}return r}function fr({inset:t,insetLeft:e,insetRight:n,...r}={}){return[e,n]=hr(t,e,n),{inset:t,insetLeft:e,insetRight:n,...r}}function dr({inset:t,insetTop:e,insetBottom:n,...r}={}){return[e,n]=hr(t,e,n),{inset:t,insetTop:e,insetBottom:n,...r}}function hr(t,e,n){return void 0===t&&void 0===e&&void 0===n?vt?[1,0]:[.5,.5]:[e,n]}function pr(t){if(null!=t){if("number"==typeof t){const n=t;return{floor:t=>n*Math.floor(t/n),offset:t=>t+n,range:(t,r)=>e.range(Math.ceil(t/n),r/n).map((t=>n*t))}}if("function"!=typeof t.floor||"function"!=typeof t.offset)throw new Error("invalid interval; missing floor or offset function");return t}}function mr(t,e,n,r){const{[t]:o,[`${t}1`]:i,[`${t}2`]:a}=n,{value:s,interval:c}=function(t,{interval:e}){return(t={...q(t)}).interval=pr(void 0===t.interval?e:t.interval),t}(o,n);if(null==s||null==c&&!r)return n;const u=Y(o);if(null==c){let e;const r={transform:t=>e||(e=l(t,s)),label:u};return{...n,[t]:void 0,[`${t}1`]:void 0===i?r:i,[`${t}2`]:void 0===a?r:a}}let f;const d=t=>f||(f=l(t,s).map((t=>c.floor(t))));return e({...n,[t]:void 0,[`${t}1`]:void 0===i?{transform:d,label:u}:i,[`${t}2`]:void 0===a?{transform:t=>d(t).map((t=>c.offset(t))),label:u}:a})}function yr(t={}){return mr("x",fr,t,!0)}function gr(t={}){return mr("y",dr,t,!0)}function vr(t={}){return mr("x",fr,t)}function xr(t={}){return mr("y",dr,t)}function wr(t={y:"count"},e={}){[t,e]=Ar(t,e);const{x:n,y:r}=e;return Lr(Rr(n,e,f),null,null,r,t,fr(e))}function br(t={x:"count"},e={}){[t,e]=Ar(t,e);const{x:n,y:r}=e;return Lr(null,Rr(r,e,f),n,null,t,dr(e))}function kr(t,e,n){return null==n?.interval?n:t({[e]:void 0===n?.reduce?An:n.reduce,filter:null},n)}function $r(t){return kr(wr,"y",t)}function Mr(t){return kr(br,"x",t)}function Lr(t,e,n,r,{data:o=Ln,filter:i=On,sort:a,reverse:s,...c}={},u={}){t=Br(t),e=Br(e),c=gn(c,u),o=bn(o,f),a=null==a?void 0:vn("sort",a,u),i=null==i?void 0:xn("filter",i,u),null!=n&&yn(c,"x","x1","x2")&&(n=null),null!=r&&yn(c,"y","y1","y2")&&(r=null);const[d,h]=W(t),[p,m]=W(t),[y,g]=W(e),[v,x]=W(e),[b,k]=null!=n?[n,"x"]:null!=r?[r,"y"]:[],[$,M]=W(b),{x:L,y:A,z:R,fill:B,stroke:O,x1:C,x2:S,y1:z,y2:N,domain:E,cumulative:T,thresholds:D,interval:Y,...q}=u,[_,F]=W(R),[j]=w(B),[I]=w(O),[G=B,X]=W(j),[U=O,V]=W(I);return{..."z"in u&&{z:_||R},..."fill"in u&&{fill:G||B},..."stroke"in u&&{stroke:U||O},...on(q,((n,r)=>{const u=l(n,b),f=l(n,R),d=l(n,j),p=l(n,I),y=kn(c,f,d,p),v=[],w=[],k=u&&M([]),$=f&&F([]),L=d&&X([]),A=p&&V([]),B=t?t(n):[[,,t=>t]],O=e?e(n):[[,,t=>t]],C=t&&h([]),S=t&&m([]),z=e&&g([]),N=e&&x([]);let E=0;for(const t of c)t.initialize(n);a&&a.initialize(n),i&&i.initialize(n);for(const t of r){const e=[];for(const e of c)e.scope("facet",t);a&&a.scope("facet",t),i&&i.scope("facet",t);for(const[r,s]of wn(t,y))for(const[t,l]of wn(s,u))for(const[s,h,m]of B){const g=m(l);for(const[l,m,v]of O){const x={x1:s,x2:h,y1:l,y2:m},b=v(g);if(!i||i.reduce(b,x)){e.push(E++),w.push(o.reduce(b,n,x)),u&&k.push(t),f&&$.push(y===f?r:f[b[0]]),d&&L.push(y===d?r:d[b[0]]),p&&A.push(y===p?r:p[b[0]]),C&&(C.push(s),S.push(h)),z&&(z.push(l),N.push(m));for(const t of c)t.reduce(b,x);a&&a.reduce(b)}}}v.push(e)}return $n(v,a,s),{data:w,facets:v}})),...!yn(c,"x")&&(d?{x1:d,x2:p,x:P(d,p)}:{x:L,x1:C,x2:S}),...!yn(c,"y")&&(y?{y1:y,y2:v,y:P(y,v)}:{y:A,y1:z,y2:N}),...$&&{[k]:$},...Object.fromEntries(c.map((({name:t,output:e})=>[t,e])))}}function Ar({cumulative:t,domain:e,thresholds:n,interval:r,...o},i){return[o,{cumulative:t,domain:e,thresholds:n,interval:r,...i}]}function Rr(t,{cumulative:n,domain:r,thresholds:o,interval:i},a){return void 0===(t={...q(t)}).domain&&(t.domain=r),void 0===t.cumulative&&(t.cumulative=n),void 0===t.thresholds&&(t.thresholds=o),void 0===t.interval&&(t.interval=i),void 0===t.value&&(t.value=a),t.thresholds=function(t,n){if(void 0===t)return void 0===n?Or:function(t){if(!Cr(t=pr(t)))throw new Error(`invalid interval: ${t}`);return t}(n);if("string"==typeof t){switch(t.toLowerCase()){case"freedman-diaconis":return e.thresholdFreedmanDiaconis;case"scott":return e.thresholdScott;case"sturges":return e.thresholdSturges;case"auto":return Or}throw new Error(`invalid thresholds: ${t}`)}return t}(t.thresholds,t.interval),t}function Br(t){if(null==t)return;const{value:n,cumulative:r,domain:o=e.extent,thresholds:i}=t,a=t=>{let a=l(t,n,Array);const s=e.bin().value((t=>a[t]));if(j(a)||(function(t){return Cr(t)&&"function"==typeof t&&t()instanceof Date}(c=i)||c&&c[Symbol.iterator]&&j(c))){a=a.map(Ze);let[t,n]="function"==typeof o?o(a):o,r="function"!=typeof i||Cr(i)?i:i(a,t,n);"number"==typeof r&&(r=e.utcTickInterval(t,n,r)),Cr(r)&&(o===e.extent&&(t=r.floor(t),n=r.ceil(new Date(+n+1))),r=r.range(t,n)),s.thresholds(r).domain([t,n])}else{a=a.map(He);let t=o,n=i;if(Cr(n)){let[r,o]="function"==typeof t?t(a):t;t===e.extent&&(r=n.floor(r),o=n.offset(n.floor(o)),t=[r,o]),n=n.range(r,o)}s.thresholds(n).domain(t)}var c;let u=s(S(t)).map(Sr);return r&&(u=(r<0?u.reverse():u).map(zr)),u.map(Nr)};return a.label=Y(n),a}function Or(t,n,r){return Math.min(200,e.thresholdScott(t,n,r))}function Cr(t){return!!t&&"function"==typeof t.range}function Sr(t){return[t,new Set(t)]}function zr([t],e,n){return[t,{get size(){for(let t=0;t<=e;++t)if(n[t][1].size)return 1;return 0},has(t){for(let r=0;r<=e;++r)if(n[r][1].has(t))return!0;return!1}}]}function Nr([{x0:t,x1:e},n]){return[t,e,n.size?t=>t.filter(n.has,n):Er]}function Er(){return new Uint32Array(0)}function Tr(t={}){const{x:e,x1:n,x2:r}=t;return void 0===n&&void 0===r&&void 0===e?{...t,x:f}:t}function Dr(t={}){const{y:e,y1:n,y2:r}=t;return void 0===n&&void 0===r&&void 0===e?{...t,y:f}:t}function Wr(t={},e={}){1===arguments.length&&([t,e]=_r(t));const{y1:n,y:r=n,x:o,...i}=e,[a,s,l,c]=Fr(r,o,"x",t,i);return{...a,y1:n,y:s,x1:l,x2:c,x:P(l,c)}}function Yr(t={},e={}){1===arguments.length&&([t,e]=_r(t));const{x1:n,x:r=n,y:o,...i}=e,[a,s,l,c]=Fr(r,o,"y",t,i);return{...a,x1:n,x:s,y1:l,y2:c,y:P(l,c)}}function Pr({x:t,x1:e,x2:n,...r}={}){return void 0===e&&void 0===n?Wr({x:t,...r}):([e,n]=B(t,e,n),{...r,x1:e,x2:n})}function qr({y:t,y1:e,y2:n,...r}={}){return void 0===e&&void 0===n?Yr({y:t,...r}):([e,n]=B(t,e,n),{...r,y1:e,y2:n})}function _r(t){const{offset:e,order:n,reverse:r,...o}=t;return[{offset:e,order:n,reverse:r},o]}function Fr(t,n=d,r,{offset:o,order:i,reverse:a},s){const u=C(s),[f,h]=W(t),[p,m]=D(n),[y,g]=D(n);return o=function(t){if(null==t)return;if("function"==typeof t)return t;switch(`${t}`.toLowerCase()){case"expand":case"normalize":return Ir;case"center":case"silhouette":return Gr;case"wiggle":return Xr}throw new Error(`unknown offset: ${t}`)}(o),i=function(t,e,n){if(void 0===t&&e===Xr)return Kr;if(null==t)return;if("string"==typeof t){switch(t.toLowerCase()){case"value":case n:return Hr;case"z":return Zr;case"sum":return Qr;case"appearance":return Jr;case"inside-out":return Kr}return to(c(t))}if("function"==typeof t)return to(t);if(Array.isArray(t))return r=t,(t,e,n,o)=>eo(o,r);var r;throw new Error(`invalid order: ${t}`)}(i,o,r),[on(s,((r,s)=>{const c=null==t?void 0:h(l(r,t)),f=l(r,n,Float64Array),d=l(r,u),p=i&&i(r,c,f,d),y=r.length,v=m(new Float64Array(y)),x=g(new Float64Array(y)),w=[];for(const t of s){const n=c?Array.from(e.group(t,(t=>c[t])).values()):[t];p&&no(n,p);for(const t of n){let e=0,n=0;a&&t.reverse();for(const r of t){const t=f[r];t<0?e=x[r]=(v[r]=e)+t:t>0?n=x[r]=(v[r]=n)+t:x[r]=v[r]=n}}w.push(n)}return o&&o(w,v,x,d),{data:r,facets:s}})),f,p,y]}function jr(t,e){let n=0,r=0;for(const o of t){const t=e[o];tr&&(r=t)}return[n,r]}function Ir(t,e,n){for(const r of t)for(const t of r){const[r,o]=jr(t,n);for(const i of t){const t=1/(o-r||1);e[i]=t*(e[i]-r),n[i]=t*(n[i]-r)}}}function Gr(t,e,n){for(const r of t){for(const t of r){const[r,o]=jr(t,n);for(const i of t){const t=(o+r)/2;e[i]-=t,n[i]-=t}}Ur(r,e,n)}Vr(t,e,n)}function Xr(t,n,r,o){for(const i of t){const t=new e.InternMap;let a=0;for(const s of i){let i=-1;const l=s.map((t=>Math.abs(r[t]-n[t]))),c=s.map((e=>{i=o?o[e]:++i;const a=r[e]-n[e],s=t.has(i)?a-t.get(i):0;return t.set(i,a),s})),u=[0,...e.cumsum(c)];for(const t of s)n[t]+=a,r[t]+=a;const f=e.sum(l);f&&(a-=e.sum(l,((t,e)=>(c[e]/2+u[e])*t))/f)}Ur(i,n,r)}Vr(t,n,r)}function Ur(t,n,r){const o=e.min(t,(t=>e.min(t,(t=>n[t]))));for(const e of t)for(const t of e)n[t]-=o,r[t]-=o}function Vr(t,n,r){const o=t.length;if(1===o)return;const i=t.map((t=>t.flat())),a=i.map((t=>(e.min(t,(t=>n[t]))+e.max(t,(t=>r[t])))/2)),s=e.min(a);for(let t=0;te.sum(t,(t=>r[t]))),(t=>o[t])))}function Jr(t,n,r,o){return eo(o,e.groupSort(S(t),(t=>n[e.greatest(t,(t=>r[t]))]),(t=>o[t])))}function Kr(t,n,r,o){const i=S(t),a=e.groupSort(i,(t=>n[e.greatest(t,(t=>r[t]))]),(t=>o[t])),s=e.rollup(i,(t=>e.sum(t,(t=>r[t]))),(t=>o[t])),l=[],c=[];let u=0;for(const t of a)u<0?(u+=s.get(t),l.push(t)):(u-=s.get(t),c.push(t));return eo(o,c.reverse().concat(l))}function to(t){return e=>l(e,t)}function eo(t,n){return n=new e.InternMap(n.map(((t,e)=>[t,e]))),t.map((t=>n.get(t)))}function no(t,e){for(const n of t)n.sort(((t,n)=>ft(e[t],e[n])))}const ro={ariaLabel:"area",strokeWidth:1,strokeLinecap:"round",strokeLinejoin:"round",strokeMiterlimit:1};class oo extends tr{constructor(t,e={}){const{x1:n,y1:r,x2:o,y2:i,z:a,curve:s,tension:l}=e;super(t,[{name:"x1",value:n,scale:"x"},{name:"y1",value:r,scale:"y"},{name:"x2",value:o,scale:"x",optional:!0},{name:"y2",value:i,scale:"y",optional:!0},{name:"z",value:C(e),optional:!0}],e,ro),this.z=a,this.curve=ur(s,l)}filter(t){return t}render(t,{x:n,y:r},o,i){const{x1:a,y1:s,x2:l=a,y2:c=s}=o,{dx:u,dy:f}=this;return e.create("svg:g").call(Lt,this,i).call(Ot,n,r,u,f).call((n=>n.selectAll().data(Mt(t,[a,s,l,c],this,o)).enter().append("path").call(At,this).call($t,this,o).attr("d",e.area().curve(this.curve).defined((t=>t>=0)).x0((t=>a[t])).y0((t=>s[t])).x1((t=>l[t])).y1((t=>c[t]))))).node()}}function io(t,e){const{x:n=u,...r}=$r(e);return new oo(t,qr(Dr({...r,x1:n,x2:void 0})))}function ao(t,{marker:e,markerStart:n=e,markerMid:r=e,markerEnd:o=e}={}){t.markerStart=so(n),t.markerMid=so(r),t.markerEnd=so(o)}function so(t){if(null==t||!1===t)return null;if(!0===t)return uo;if("function"==typeof t)return t;switch(`${t}`.toLowerCase()){case"none":return null;case"arrow":return lo;case"dot":return co;case"circle":case"circle-fill":return uo;case"circle-stroke":return fo}throw new Error(`invalid marker: ${t}`)}function lo(t){return e.create("svg:marker").attr("viewBox","-5 -5 10 10").attr("markerWidth",6.67).attr("markerHeight",6.67).attr("orient","auto").attr("fill","none").attr("stroke",t).attr("stroke-width",1.5).attr("stroke-linecap","round").attr("stroke-linejoin","round").call((t=>t.append("path").attr("d","M-1.5,-3l3,3l-3,3"))).node()}function co(t){return e.create("svg:marker").attr("viewBox","-5 -5 10 10").attr("markerWidth",6.67).attr("markerHeight",6.67).attr("fill",t).attr("stroke","none").call((t=>t.append("circle").attr("r",2.5))).node()}function uo(t){return e.create("svg:marker").attr("viewBox","-5 -5 10 10").attr("markerWidth",6.67).attr("markerHeight",6.67).attr("fill",t).attr("stroke","white").attr("stroke-width",1.5).call((t=>t.append("circle").attr("r",3))).node()}function fo(t){return e.create("svg:marker").attr("viewBox","-5 -5 10 10").attr("markerWidth",6.67).attr("markerHeight",6.67).attr("fill","white").attr("stroke",t).attr("stroke-width",1.5).call((t=>t.append("circle").attr("r",3))).node()}let ho=0;function po(t,e,{stroke:n}){return yo(t,e,n&&(t=>n[t]))}function mo(t,e,{stroke:n}){return yo(t,e,n&&(([t])=>n[t]))}function yo(t,{markerStart:e,markerMid:n,markerEnd:r,stroke:o},i=(()=>o)){const a=new Map;function s(t){return function(e){const n=i(e);let r=a.get(t);r||a.set(t,r=new Map);let o=r.get(n);if(!o){const e=this.parentNode.insertBefore(t(n),this),i="plot-marker-"+ ++ho;e.setAttribute("id",i),r.set(n,o=`url(#${i})`)}return o}}e&&t.attr("marker-start",s(e)),n&&t.attr("marker-mid",s(n)),r&&t.attr("marker-end",s(r))}const go={ariaLabel:"link",fill:"none",stroke:"currentColor",strokeMiterlimit:1};class vo extends tr{constructor(t,e={}){const{x1:n,y1:r,x2:o,y2:i,curve:a,tension:s}=e;super(t,[{name:"x1",value:n,scale:"x"},{name:"y1",value:r,scale:"y"},{name:"x2",value:o,scale:"x",optional:!0},{name:"y2",value:i,scale:"y",optional:!0}],e,go),this.curve=ur(a,s),ao(this,e)}render(t,{x:n,y:r},o,i){const{x1:a,y1:s,x2:l=a,y2:c=s}=o,{dx:u,dy:f,curve:d}=this;return e.create("svg:g").call(Lt,this,i).call(Ot,n,r,vt+u,vt+f).call((n=>n.selectAll().data(t).enter().append("path").call(At,this).attr("d",(t=>{const n=e.path(),r=d(n);return r.lineStart(),r.point(a[t],s[t]),r.point(l[t],c[t]),r.lineEnd(),n})).call(kt,this,o).call(po,this,o))).node()}}function xo(t,{x:e,x1:n,x2:r,y:o,y1:i,y2:a,...s}={}){return[n,r]=wo(e,n,r),[i,a]=wo(o,i,a),new vo(t,{...s,x1:n,x2:r,y1:i,y2:a})}function wo(t,e,n){if(void 0===t){if(void 0===e){if(void 0!==n)return[n]}else if(void 0===n)return[e]}else{if(void 0===e)return void 0===n?[t]:[t,n];if(void 0===n)return[t,e]}return[e,n]}const bo={ariaLabel:"arrow",fill:"none",stroke:"currentColor",strokeLinecap:"round",strokeMiterlimit:1,strokeWidth:1.5};class ko extends tr{constructor(t,e={}){const{x1:n,y1:r,x2:o,y2:i,bend:a=0,headAngle:s=60,headLength:l=8,inset:c=0,insetStart:u=c,insetEnd:f=c}=e;super(t,[{name:"x1",value:n,scale:"x"},{name:"y1",value:r,scale:"y"},{name:"x2",value:o,scale:"x",optional:!0},{name:"y2",value:i,scale:"y",optional:!0}],e,bo),this.bend=!0===a?22.5:Math.max(-90,Math.min(90,a)),this.headAngle=+s,this.headLength=+l,this.insetStart=+u,this.insetEnd=+f}render(t,{x:n,y:r},o,i){const{x1:a,y1:s,x2:l=a,y2:c=s,SW:u}=o,{dx:f,dy:d,strokeWidth:h,bend:p,headAngle:m,headLength:y,insetStart:g,insetEnd:v}=this,x=u?t=>u[t]:()=>h,w=p*ct,b=m*ct/2,k=y/1.5;return e.create("svg:g").call(Lt,this,i).call(Ot,n,r,vt+f,vt+d).call((e=>e.selectAll().data(t).enter().append("path").call(At,this).attr("d",(t=>{let e=a[t],n=s[t],r=l[t],o=c[t];const i=Math.hypot(r-e,o-n);if(i<=g+v)return null;let u=Math.atan2(o-n,r-e);const f=Math.min(k*x(t),i/3),d=Math.hypot(i/Math.tan(w),i)/2;if(g||v)if(d<1e5){const t=Math.sign(w),[i,a]=function([t,e],[n,r],o,i){const a=n-t,s=r-e,l=Math.hypot(a,s),c=i*Math.sqrt(o*o-l*l/4)/l;return[(t+n)/2-s*c,(e+r)/2+a*c]}([e,n],[r,o],d,t);if(g&&([e,n]=$o([i,a,d],[e,n,g],-t*Math.sign(g))),v){const[e,n]=$o([i,a,d],[r,o,v],t*Math.sign(v));u+=Math.atan2(n-a,e-i)-Math.atan2(o-a,r-i),r=e,o=n}}else{const t=r-e,i=o-n,a=Math.hypot(t,i);g&&(e+=t/a*g,n+=i/a*g),v&&(r-=t/a*v,o-=i/a*v)}const h=u+w,p=h+b,m=h-b,y=r-f*Math.cos(p),$=o-f*Math.sin(p),M=r-f*Math.cos(m),L=o-f*Math.sin(m);return`M${e},${n}${d<1e5?`A${d},${d} 0,0,${w>0?1:0} `:"L"}${r},${o}M${y},${$}L${r},${o}L${M},${L}`})).call(kt,this,o))).node()}}function $o([t,e,n],[r,o,i],a){const s=r-t,l=o-e,c=Math.hypot(s,l),u=(s*s+l*l-i*i+n*n)/(2*c),f=a*Math.sqrt(n*n-u*u);return[t+(s*u+l*f)/c,e+(l*u-s*f)/c]}class Mo extends tr{constructor(t,e,n={},r){super(t,e,n,r);const{inset:o=0,insetTop:i=o,insetRight:a=o,insetBottom:s=o,insetLeft:l=o,rx:c,ry:u}=n;this.insetTop=p(i),this.insetRight=p(a),this.insetBottom=p(s),this.insetLeft=p(l),this.rx=Ct(c,"auto"),this.ry=Ct(u,"auto")}render(t,n,r,o){const{dx:i,dy:a,rx:s,ry:l}=this;return e.create("svg:g").call(Lt,this,o).call(this._transform,n,i,a).call((e=>e.selectAll().data(t).enter().append("rect").call(At,this).attr("x",this._x(n,r,o)).attr("width",this._width(n,r,o)).attr("y",this._y(n,r,o)).attr("height",this._height(n,r,o)).call(Bt,"rx",s).call(Bt,"ry",l).call(kt,this,r))).node()}_x(t,{x:e},{marginLeft:n}){const{insetLeft:r}=this;return e?t=>e[t]+r:n+r}_y(t,{y:e},{marginTop:n}){const{insetTop:r}=this;return e?t=>e[t]+r:n+r}_width({x:t},{x:e},{marginRight:n,marginLeft:r,width:o}){const{insetLeft:i,insetRight:a}=this,s=e?t.bandwidth():o-n-r;return Math.max(0,s-i-a)}_height({y:t},{y:e},{marginTop:n,marginBottom:r,height:o}){const{insetTop:i,insetBottom:a}=this,s=e?t.bandwidth():o-n-r;return Math.max(0,s-i-a)}}const Lo={ariaLabel:"bar"};class Ao extends Mo{constructor(t,e={}){const{x1:n,x2:r,y:o}=e;super(t,[{name:"x1",value:n,scale:"x"},{name:"x2",value:r,scale:"x"},{name:"y",value:o,scale:"y",type:"band",optional:!0}],e,Lo)}_transform(t,{x:e},n,r){t.call(Ot,e,null,n,r)}_x({x:t},{x1:e,x2:n},{marginLeft:r}){const{insetLeft:o}=this;return Xe(t)?r+o:t=>Math.min(e[t],n[t])+o}_width({x:t},{x1:e,x2:n},{marginRight:r,marginLeft:o,width:i}){const{insetLeft:a,insetRight:s}=this;return Xe(t)?i-r-o-a-s:t=>Math.max(0,Math.abs(n[t]-e[t])-a-s)}}class Ro extends Mo{constructor(t,e={}){const{x:n,y1:r,y2:o}=e;super(t,[{name:"y1",value:r,scale:"y"},{name:"y2",value:o,scale:"y"},{name:"x",value:n,scale:"x",type:"band",optional:!0}],e,Lo)}_transform(t,{y:e},n,r){t.call(Ot,null,e,n,r)}_y({y:t},{y1:e,y2:n},{marginTop:r}){const{insetTop:o}=this;return Xe(t)?r+o:t=>Math.min(e[t],n[t])+o}_height({y:t},{y1:e,y2:n},{marginTop:r,marginBottom:o,height:i}){const{insetTop:a,insetBottom:s}=this;return Xe(t)?i-r-o-a-s:t=>Math.max(0,Math.abs(n[t]-e[t])-a-s)}}function Bo(t,e={y:u,x2:f}){return new Ao(t,Pr(vr(Tr(e))))}function Oo(t,e={x:u,y2:f}){return new Ro(t,qr(xr(Dr(e))))}function Co(t,e={}){return zo(Object.fromEntries(["x","x1","x2"].filter((t=>null!=e[t])).map((e=>[e,t]))),e)}function So(t,e={}){return zo(Object.fromEntries(["y","y1","y2"].filter((t=>null!=e[t])).map((e=>[e,t]))),e)}function zo(t={},n={}){const r=C(n),o=Object.entries(t).map((([t,e])=>{const r=T(t,n);if(null==r)throw new Error(`missing channel: ${t}`);const[o,i]=D(r);return{key:t,input:r,output:o,setOutput:i,map:No(e)}}));return{...on(n,((t,n)=>{const i=l(t,r),a=o.map((({input:e})=>l(t,e))),s=o.map((({setOutput:e})=>e(new Array(t.length))));for(const t of n)for(const n of i?e.group(t,(t=>i[t])).values():[t])o.forEach((({map:t},e)=>t.map(n,a[e],s[e])));return{data:t,facets:n}})),...Object.fromEntries(o.map((({key:t,output:e})=>[t,e])))}}function No(t){if(t&&"function"==typeof t.map)return t;if("function"==typeof t)return To(t);switch(`${t}`.toLowerCase()){case"cumsum":return Do;case"rank":return To(e.rank);case"quantile":return To(Eo)}throw new Error(`invalid map: ${t}`)}function Eo(t){const n=e.count(t)-1;return e.rank(t).map((t=>t/n))}function To(t){return{map(e,n,r){const o=t(N(n,e));if(o.length!==e.length)throw new Error("map function returned a mismatched length");for(let t=0,n=e.length;t"symbol"===t));if(y){const t=m.find((({name:t})=>"fill"===t)),e=m.find((({name:t})=>"stroke"===t));y.hint={fill:t?t.value===y.value?"color":"currentColor":this.fill,stroke:e?e.value===y.value?"color":"currentColor":this.stroke}}}render(t,{x:n,y:r},o,i){const{x:a,y:s,r:l,rotate:c,symbol:u}=o,{dx:f,dy:d}=this,[h,p]=Tt(this,i),m=this.symbol===e.symbolCircle;return e.create("svg:g").call(Lt,this,i).call(Ot,n,r,vt+f,vt+d).call((n=>n.selectAll().data(t).enter().append(m?"circle":"path").call(At,this).call(m?t=>{t.attr("cx",a?t=>a[t]:h).attr("cy",s?t=>s[t]:p).attr("r",l?t=>l[t]:this.r)}:t=>{const n=a&&s?t=>`translate(${a[t]},${s[t]})`:a?t=>`translate(${a[t]},${p})`:s?t=>`translate(${h},${s[t]})`:()=>`translate(${h},${p})`;t.attr("transform",c?t=>`${n(t)} rotate(${c[t]})`:this.rotate?t=>`${n(t)} rotate(${this.rotate})`:n).attr("d",(t=>{const n=e.path(),r=l?l[t]:this.r;return(u?u[t]:this.symbol).draw(n,r*r*Math.PI),n}))}).call(kt,this,o))).node()}}function Po(t,{x:e,y:n,...r}={}){return void 0===r.frameAnchor&&([e,n]=O(e,n)),new Yo(t,{...r,x:e,y:n})}const qo={ariaLabel:"rule",fill:null,stroke:"currentColor"};class _o extends tr{constructor(t,e={}){const{x:n,y1:r,y2:o,inset:i=0,insetTop:a=i,insetBottom:s=i}=e;super(t,[{name:"x",value:n,scale:"x",optional:!0},{name:"y1",value:r,scale:"y",optional:!0},{name:"y2",value:o,scale:"y",optional:!0}],e,qo),this.insetTop=p(a),this.insetBottom=p(s)}render(t,{x:n,y:r},o,i){const{x:a,y1:s,y2:l}=o,{width:c,height:u,marginTop:f,marginRight:d,marginLeft:h,marginBottom:p}=i,{insetTop:m,insetBottom:y}=this;return e.create("svg:g").call(Lt,this,i).call(Ot,a&&n,null,vt,0).call((e=>e.selectAll().data(t).enter().append("line").call(At,this).attr("x1",a?t=>a[t]:(h+c-d)/2).attr("x2",a?t=>a[t]:(h+c-d)/2).attr("y1",s&&!Xe(r)?t=>s[t]+m:f+m).attr("y2",l&&!Xe(r)?r.bandwidth?t=>l[t]+r.bandwidth()-y:t=>l[t]-y:u-p-y).call(kt,this,o))).node()}}class Fo extends tr{constructor(t,e={}){const{x1:n,x2:r,y:o,inset:i=0,insetRight:a=i,insetLeft:s=i}=e;super(t,[{name:"y",value:o,scale:"y",optional:!0},{name:"x1",value:n,scale:"x",optional:!0},{name:"x2",value:r,scale:"x",optional:!0}],e,qo),this.insetRight=p(a),this.insetLeft=p(s)}render(t,{x:n,y:r},o,i){const{y:a,x1:s,x2:l}=o,{width:c,height:u,marginTop:f,marginRight:d,marginLeft:h,marginBottom:p}=i,{insetLeft:m,insetRight:y,dx:g,dy:v}=this;return e.create("svg:g").call(Lt,this,i).call(Ot,null,a&&r,g,vt+v).call((e=>e.selectAll().data(t).enter().append("line").call(At,this).attr("x1",s&&!Xe(n)?t=>s[t]+m:h+m).attr("x2",l&&!Xe(n)?n.bandwidth?t=>l[t]+n.bandwidth()-y:t=>l[t]-y:c-d-y).attr("y1",a?t=>a[t]:(f+u-p)/2).attr("y2",a?t=>a[t]:(f+u-p)/2).call(kt,this,o))).node()}}function jo(t,e){let{x:n=f,y:r,y1:o,y2:i,...a}=xr(e);return[o,i]=Go(r,o,i),new _o(t,{...a,x:n,y1:o,y2:i})}function Io(t,e){let{y:n=f,x:r,x1:o,x2:i,...a}=vr(e);return[o,i]=Go(r,o,i),new Fo(t,{...a,y:n,x1:o,x2:i})}function Go(t,e,n){if(void 0===t){if(void 0===e){if(void 0!==n)return[0,n]}else if(void 0===n)return[0,e]}else{if(void 0===e)return void 0===n?[0,t]:[t,n];if(void 0===n)return[t,e]}return[e,n]}const Xo={ariaLabel:"tick",fill:null,stroke:"currentColor"};class Uo extends tr{constructor(t,e,n){super(t,e,n,Xo)}render(t,n,r,o){const{dx:i,dy:a}=this;return e.create("svg:g").call(Lt,this,o).call(this._transform,n,i,a).call((e=>e.selectAll().data(t).enter().append("line").call(At,this).attr("x1",this._x1(n,r,o)).attr("x2",this._x2(n,r,o)).attr("y1",this._y1(n,r,o)).attr("y2",this._y2(n,r,o)).call(kt,this,r))).node()}}class Vo extends Uo{constructor(t,e={}){const{x:n,y:r,inset:o=0,insetTop:i=o,insetBottom:a=o}=e;super(t,[{name:"x",value:n,scale:"x"},{name:"y",value:r,scale:"y",type:"band",optional:!0}],e),this.insetTop=p(i),this.insetBottom=p(a)}_transform(t,{x:e},n,r){t.call(Ot,e,null,vt+n,r)}_x1(t,{x:e}){return t=>e[t]}_x2(t,{x:e}){return t=>e[t]}_y1(t,{y:e},{marginTop:n}){const{insetTop:r}=this;return e?t=>e[t]+r:n+r}_y2({y:t},{y:e},{height:n,marginBottom:r}){const{insetBottom:o}=this;return e?n=>e[n]+t.bandwidth()-o:n-r-o}}class Ho extends Uo{constructor(t,e={}){const{x:n,y:r,inset:o=0,insetRight:i=o,insetLeft:a=o}=e;super(t,[{name:"y",value:r,scale:"y"},{name:"x",value:n,scale:"x",type:"band",optional:!0}],e),this.insetRight=p(i),this.insetLeft=p(a)}_transform(t,{y:e},n,r){t.call(Ot,null,e,n,vt+r)}_x1(t,{x:e},{marginLeft:n}){const{insetLeft:r}=this;return e?t=>e[t]+r:n+r}_x2({x:t},{x:e},{width:n,marginRight:r}){const{insetRight:o}=this;return e?n=>e[n]+t.bandwidth()-o:n-r-o}_y1(t,{y:e}){return t=>e[t]}_y2(t,{y:e}){return t=>e[t]}}function Zo(t,{x:e=f,...n}={}){return new Vo(t,{...n,x:e})}function Qo(t,{y:e=f,...n}={}){return new Ho(t,{...n,y:e})}function Jo(t){const e=Ko(t),n=ti(t);return t.map((t=>tn?t:NaN))}function Ko(t,n){const r=2.5*ei(t,n)-1.5*ni(t,n);return e.min(t,(t=>t>=r?t:NaN))}function ti(t,n){const r=2.5*ni(t,n)-1.5*ei(t,n);return e.max(t,(t=>t<=r?t:NaN))}function ei(t,n){return e.quantile(t,.25,n)}function ni(t,n){return e.quantile(t,.75,n)}const ri={ariaLabel:"cell"};class oi extends Mo{constructor(t,{x:e,y:n,...r}={}){super(t,[{name:"x",value:e,scale:"x",type:"band",optional:!0},{name:"y",value:n,scale:"y",type:"band",optional:!0}],r,ri)}_transform(){}}const ii={ariaLabel:"frame",fill:"none",stroke:"currentColor"};class ai extends tr{constructor(t={}){const{inset:e=0,insetTop:n=e,insetRight:r=e,insetBottom:o=e,insetLeft:i=e}=t;super(void 0,void 0,t,ii),this.insetTop=p(n),this.insetRight=p(r),this.insetBottom=p(o),this.insetLeft=p(i)}render(t,n,r,o){const{marginTop:i,marginRight:a,marginBottom:s,marginLeft:l,width:c,height:u}=o,{insetTop:f,insetRight:d,insetBottom:h,insetLeft:p,dx:m,dy:y}=this;return e.create("svg:rect").call(Lt,this,o).call(At,this).call(Ot,null,null,vt+m,vt+y).attr("x",l+p).attr("y",i+f).attr("width",c-l-a-p-d).attr("height",u-i-s-f-h).node()}}const si={ariaLabel:"image",fill:null,stroke:null};class li extends tr{constructor(t,e={}){let{x:n,y:r,width:o,height:i,src:a,preserveAspectRatio:s,crossOrigin:l,frameAnchor:c}=e;void 0===o&&void 0!==i?o=i:void 0===i&&void 0!==o&&(i=o);const[u,f]="string"==typeof(d=a)&&(function(t){return/^\.*\//.test(t)}(d)||function(t){return/^(blob|data|file|http|https):/i.test(t)}(d))?[void 0,d]:[d,void 0];var d;const[p,m]=b(o,16),[y,g]=b(i,16);super(t,[{name:"x",value:n,scale:"x",optional:!0},{name:"y",value:r,scale:"y",optional:!0},{name:"width",value:p,filter:pt,optional:!0},{name:"height",value:y,filter:pt,optional:!0},{name:"src",value:u,optional:!0}],e,si),this.src=f,this.width=m,this.height=g,this.preserveAspectRatio=Ct(s,"xMidYMid"),this.crossOrigin=h(l),this.frameAnchor=et(c)}render(t,{x:n,y:r},o,i){const{x:a,y:s,width:l,height:c,src:u}=o,{dx:f,dy:d}=this,[h,p]=Tt(this,i);return e.create("svg:g").call(Lt,this,i).call(Ot,n,r,vt+f,vt+d).call((e=>e.selectAll().data(t).enter().append("image").call(At,this).attr("x",l&&a?t=>a[t]-l[t]/2:l?t=>h-l[t]/2:a?t=>a[t]-this.width/2:h-this.width/2).attr("y",c&&s?t=>s[t]-c[t]/2:c?t=>p-c[t]/2:s?t=>s[t]-this.height/2:p-this.height/2).attr("width",l?t=>l[t]:this.width).attr("height",c?t=>c[t]:this.height).call(Bt,"href",u?t=>u[t]:this.src).call(Bt,"preserveAspectRatio",this.preserveAspectRatio).call(Bt,"crossorigin",this.crossOrigin).call(kt,this,o))).node()}}const ci={ariaLabel:"line",fill:"none",stroke:"currentColor",strokeWidth:1.5,strokeLinecap:"round",strokeLinejoin:"round",strokeMiterlimit:1};class ui extends tr{constructor(t,e={}){const{x:n,y:r,z:o,curve:i,tension:a}=e;super(t,[{name:"x",value:n,scale:"x"},{name:"y",value:r,scale:"y"},{name:"z",value:C(e),optional:!0}],e,ci),this.z=o,this.curve=ur(i,a),ao(this,e)}filter(t){return t}render(t,{x:n,y:r},o,i){const{x:a,y:s}=o,{dx:l,dy:c}=this;return e.create("svg:g").call(Lt,this,i).call(Ot,n,r,vt+l,vt+c).call((n=>n.selectAll().data(Mt(t,[a,s],this,o)).enter().append("path").call(At,this).call($t,this,o).call(mo,this,o).attr("d",e.line().curve(this.curve).defined((t=>t>=0)).x((t=>a[t])).y((t=>s[t]))))).node()}}const fi={ariaLabel:"rect"};class di extends tr{constructor(t,e={}){const{x1:n,y1:r,x2:o,y2:i,inset:a=0,insetTop:s=a,insetRight:l=a,insetBottom:c=a,insetLeft:u=a,rx:f,ry:d}=e;super(t,[{name:"x1",value:n,scale:"x",optional:!0},{name:"y1",value:r,scale:"y",optional:!0},{name:"x2",value:o,scale:"x",optional:!0},{name:"y2",value:i,scale:"y",optional:!0}],e,fi),this.insetTop=p(s),this.insetRight=p(l),this.insetBottom=p(c),this.insetLeft=p(u),this.rx=Ct(f,"auto"),this.ry=Ct(d,"auto")}render(t,{x:n,y:r},o,i){const{x1:a,y1:s,x2:l,y2:c}=o,{marginTop:u,marginRight:f,marginBottom:d,marginLeft:h,width:p,height:m}=i,{insetTop:y,insetRight:g,insetBottom:v,insetLeft:x,dx:w,dy:b,rx:k,ry:$}=this;return e.create("svg:g").call(Lt,this,i).call(Ot,a&&l?n:null,s&&c?r:null,w,b).call((e=>e.selectAll().data(t).enter().append("rect").call(At,this).attr("x",a&&l&&!Xe(n)?t=>Math.min(a[t],l[t])+x:h+x).attr("y",s&&c&&!Xe(r)?t=>Math.min(s[t],c[t])+y:u+y).attr("width",a&&l&&!Xe(n)?t=>Math.max(0,Math.abs(l[t]-a[t])-x-g):p-f-h-g-x).attr("height",s&&c&&!Xe(r)?t=>Math.max(0,Math.abs(s[t]-c[t])-y-v):m-u-d-y-v).call(Bt,"rx",k).call(Bt,"ry",$).call(kt,this,o))).node()}}const hi={ariaLabel:"text",strokeLinejoin:"round",strokeWidth:3,paintOrder:"stroke"};class pi extends tr{constructor(t,e={}){const{x:n,y:r,text:o=(null!=t&&_(t)?f:u),frameAnchor:i,textAnchor:a=(/right$/i.test(i)?"end":/left$/i.test(i)?"start":"middle"),lineAnchor:s=(/^top/i.test(i)?"top":/^bottom/i.test(i)?"bottom":"middle"),lineHeight:c=1,lineWidth:d=1/0,monospace:p,fontFamily:m=(p?"ui-monospace, monospace":void 0),fontSize:y,fontStyle:g,fontVariant:v,fontWeight:x,rotate:w}=e,[k,M]=b(w,0),[L,A]=function(t){return null==t||"number"==typeof t?[void 0,t]:"string"!=typeof t?[t,void 0]:(t=t.trim().toLowerCase(),vi.has(t)||/^[+-]?\d*\.?\d+(e[+-]?\d+)?(\w*|%)$/.test(t)?[void 0,t]:[t,void 0])}(y);var R;super(t,[{name:"x",value:n,scale:"x",optional:!0},{name:"y",value:r,scale:"y",optional:!0},{name:"fontSize",value:L,optional:!0},{name:"rotate",value:(R=k,null==R?null:{transform:t=>l(t,R,Float64Array),label:Y(R)}),optional:!0},{name:"text",value:o,filter:dt}],e,hi),this.rotate=M,this.textAnchor=Ct(a,"middle"),this.lineAnchor=$(s,"lineAnchor",["top","middle","bottom"]),this.lineHeight=+c,this.lineWidth=+d,this.monospace=!!p,this.fontFamily=h(m),this.fontSize=A,this.fontStyle=h(g),this.fontVariant=h(v),this.fontWeight=h(x),this.frameAnchor=et(i)}render(t,{x:n,y:r},o,i){const{x:a,y:s,rotate:l,text:c,fontSize:u}=o,{dx:f,dy:d,rotate:h}=this,[p,m]=Tt(this,i);return e.create("svg:g").call(Lt,this,i).call(gi,this,c,i).call(Ot,n,r,vt+f,vt+d).call((e=>e.selectAll().data(t).enter().append("text").call(At,this).call(mi,this,c).attr("transform",l?a&&s?t=>`translate(${a[t]},${s[t]}) rotate(${l[t]})`:a?t=>`translate(${a[t]},${m}) rotate(${l[t]})`:s?t=>`translate(${p},${s[t]}) rotate(${l[t]})`:t=>`translate(${p},${m}) rotate(${l[t]})`:h?a&&s?t=>`translate(${a[t]},${s[t]}) rotate(${h})`:a?t=>`translate(${a[t]},${m}) rotate(${h})`:s?t=>`translate(${p},${s[t]}) rotate(${h})`:`translate(${p},${m}) rotate(${h})`:a&&s?t=>`translate(${a[t]},${s[t]})`:a?t=>`translate(${a[t]},${m})`:s?t=>`translate(${p},${s[t]})`:`translate(${p},${m})`).call(Bt,"font-size",u&&(t=>u[t])).call(kt,this,o))).node()}}function mi(t,{monospace:n,lineAnchor:r,lineHeight:o,lineWidth:i},a){if(!a)return;const s=isFinite(i)?n?t=>xi(t,i,ki):t=>xi(t,100*i,bi):t=>t.split(/\r\n?|\n/g);t.each((function(t){const n=s(lt(a[t])),i=n.length,l="top"===r?.71:"bottom"===r?1-i:(164-100*i)/200;if(i>1)for(let t=0;tn-e)){const r=[];let o,i=0;for(const[a,s,l]of function*(t){let e=0,n=0;const r=t.length;for(;no&&n(t,o,s)>e&&(r.push(t.slice(o,i)),o=a),l?(r.push(t.slice(o,s)),o=void 0):i=s;return r}const wi={a:56,b:63,c:57,d:63,e:58,f:37,g:62,h:60,i:26,j:26,k:55,l:26,m:88,n:60,o:60,p:62,q:62,r:39,s:54,t:38,u:60,v:55,w:79,x:54,y:55,z:55,A:69,B:67,C:73,D:74,E:61,F:58,G:76,H:75,I:28,J:55,K:67,L:58,M:89,N:75,O:78,P:65,Q:78,R:67,S:65,T:65,U:75,V:69,W:98,X:69,Y:67,Z:67,0:64,1:48,2:62,3:64,4:66,5:63,6:65,7:58,8:65,9:65," ":29,"!":32,'"':49,"'":31,"(":39,")":39,",":31,"-":48,".":31,"/":32,":":31,";":31,"?":52,"‘":31,"’":31,"“":47,"”":47};function bi(t,e,n){let r=0;for(let o=e;o=55296&&e<=56319){const e=t.charCodeAt(o+1);e>=56320&&e<=57343&&++o}}return r}function ki(t,e,n){return n-e}function $i({path:t=f,delimiter:n,frameAnchor:r,treeLayout:o=e.tree,treeSort:i,treeSeparation:a,treeAnchor:s,...c}={}){s=Li(s),i=Bi(i),void 0===r&&(r=s.frameAnchor);const u=Ci(n),h=Ii(c,zi),[p,m]=D(),[y,g]=D();return{x:p,y:y,frameAnchor:r,...on(c,((n,r)=>{const c=u(l(n,t)),f=m([]),p=g([]);let y=-1;const v=[],x=[],w=e.stratify().path((t=>c[t])),b=o();b.nodeSize&&b.nodeSize([1,1]),b.separation&&void 0!==a&&b.separation(a??d);for(const t of h)t[ji]=t[_i]([]);for(const t of r){const e=[],r=w(t.filter((t=>null!=c[t]))).each((t=>t.data=n[t.data]));null!=i&&r.sort(i),b(r);for(const t of r.descendants()){e.push(++y),v[y]=t.data,s.position(t,y,f,p);for(const e of h)e[ji][y]=e[Fi](t)}x.push(e)}return{data:v,facets:x}})),...Object.fromEntries(h)}}function Mi({path:t=f,delimiter:n,curve:r="bump-x",stroke:o="#555",strokeWidth:i=1.5,strokeOpacity:a=.5,treeLayout:s=e.tree,treeSort:c,treeSeparation:u,treeAnchor:h,...p}={}){h=Li(h),c=Bi(c),p={curve:r,stroke:o,strokeWidth:i,strokeOpacity:a,...p};const m=Ci(n),y=Ii(p,Ni),[g,v]=D(),[x,w]=D(),[b,k]=D(),[$,M]=D();return{x1:g,x2:x,y1:b,y2:$,...on(p,((n,r)=>{const o=m(l(n,t)),i=v([]),a=w([]),f=k([]),p=M([]);let g=-1;const x=[],b=[],$=e.stratify().path((t=>o[t])),L=s();L.nodeSize&&L.nodeSize([1,1]),L.separation&&void 0!==u&&L.separation(u??d);for(const t of y)t[ji]=t[_i]([]);for(const t of r){const e=[],r=$(t.filter((t=>null!=o[t]))).each((t=>t.data=n[t.data]));null!=c&&r.sort(c),L(r);for(const{source:t,target:n}of r.links()){e.push(++g),x[g]=n.data,h.position(t,g,i,f),h.position(n,g,a,p);for(const e of y)e[ji][g]=e[Fi](n,t)}b.push(e)}return{data:x,facets:b}})),...Object.fromEntries(y)}}function Li(t="left"){switch(`${t}`.trim().toLowerCase()){case"left":return Ai;case"right":return Ri}throw new Error(`invalid tree anchor: ${t}`)}const Ai={frameAnchor:"left",dx:6,position({x:t,y:e},n,r,o){r[n]=e,o[n]=-t}},Ri={frameAnchor:"right",dx:-6,position({x:t,y:e},n,r,o){r[n]=-e,o[n]=-t}};function Bi(t){return null==t||"function"==typeof t?t:`${t}`.trim().toLowerCase().startsWith("node:")?Oi(zi(t)):Oi(function(t){return e=>e.data?.[t]}(t))}function Oi(t){return(e,n)=>ft(t(e),t(n))}function Ci(t="/"){return"/"==`${t}`?t=>t:e=>{return e.map((n=t,r="/",n=new RegExp(function(t){return`${t}`.replace(/[\\^$*+?.()|[\]{}]/g,"\\$&")}(n),"g"),t=>null==t?null:`${t}`.replace(n,r)));var n,r}}function Si(t){return L(t)&&"function"==typeof t.node}function zi(t){if(Si(t))return t.node;if((t=`${t}`.trim().toLowerCase()).startsWith("node:")){switch(t){case"node:name":return Ti;case"node:path":return Ei;case"node:internal":return Yi;case"node:depth":return Di;case"node:height":return Wi}throw new Error(`invalid node value: ${t}`)}}function Ni(t){if(Si(t))return t.node;if(L(e=t)&&"function"==typeof e.link)return t.link;var e;if((t=`${t}`.trim().toLowerCase()).startsWith("node:")||t.startsWith("parent:")){switch(t){case"parent:name":return Pi(Ti);case"parent:path":return Pi(Ei);case"parent:depth":return Pi(Di);case"parent:height":return Pi(Wi);case"node:name":return Ti;case"node:path":return Ei;case"node:internal":return Yi;case"node:depth":return Di;case"node:height":return Wi}throw new Error(`invalid link value: ${t}`)}}function Ei(t){return t.id}function Ti(t){return function(t){let e=t.length;for(;--e>0&&!qi(t,e););return t.slice(e+1)}(t.id)}function Di(t){return t.depth}function Wi(t){return t.height}function Yi(t){return!!t.children}function Pi(t){return(e,n)=>null==n?void 0:t(n)}function qi(t,e){if("/"===t[e]){let n=0;for(;e>0&&"\\"===t[--e];)++n;if(0==(1&n))return!0}return!1}const _i=2,Fi=3,ji=4;function Ii(t,e){const n=[];for(const r in t){const o=t[r],i=e(o);void 0!==i&&n.push([r,...D(o),i])}return n}function Gi(t,{fill:e,stroke:n,strokeWidth:r,strokeOpacity:o,strokeLinejoin:i,strokeLinecap:a,strokeMiterlimit:s,strokeDasharray:l,strokeDashoffset:c,marker:u,markerStart:f=u,markerEnd:d=u,dot:h=H(f)&&H(d),text:p="node:name",textStroke:m="white",title:y="node:path",dx:g,dy:v,...x}={}){return void 0===g&&(g=Li(x.treeAnchor).dx),er(xo(t,Mi({markerStart:f,markerEnd:d,stroke:void 0!==n?n:void 0===e?"node:internal":e,strokeWidth:r,strokeOpacity:o,strokeLinejoin:i,strokeLinecap:a,strokeMiterlimit:s,strokeDasharray:l,strokeDashoffset:c,...x})),h?Po(t,$i({fill:void 0===e?"node:internal":e,title:y,...x})):null,null!=p?yi(t,$i({text:p,fill:void 0===e?"currentColor":e,stroke:m,dx:g,dy:v,title:y,...x})):null)}const Xi={ariaLabel:"vector",fill:null,stroke:"currentColor",strokeWidth:1.5,strokeLinecap:"round"};class Ui extends tr{constructor(t,e={}){const{x:n,y:r,length:o,rotate:i,anchor:a="middle",frameAnchor:s}=e,[l,c]=b(o,12),[u,f]=b(i,0);super(t,[{name:"x",value:n,scale:"x",optional:!0},{name:"y",value:r,scale:"y",optional:!0},{name:"length",value:l,scale:"length",optional:!0},{name:"rotate",value:u,optional:!0}],e,Xi),this.length=c,this.rotate=f,this.anchor=$(a,"anchor",["start","middle","end"]),this.frameAnchor=et(s)}render(t,{x:n,y:r},o,i){const{x:a,y:s,length:l,rotate:c}=o,{dx:u,dy:f,length:d,rotate:h,anchor:p}=this,[m,y]=Tt(this,i),g=l?t=>l[t]:()=>d,v=c?t=>c[t]:()=>h,x=a?t=>a[t]:()=>m,w=s?t=>s[t]:()=>y,b="start"===p?0:"end"===p?1:.5;return e.create("svg:g").attr("fill","none").call(Lt,this,i).call(Ot,n,r,vt+u,vt+f).call((e=>e.selectAll().data(t).enter().append("path").call(At,this).attr("d",(t=>{const e=g(t),n=v(t)*ct,r=Math.sin(n)*e,o=-Math.cos(n)*e,i=(r+o)/5,a=(r-o)/5;return`M${x(t)-r*b},${w(t)-o*b}l${r},${o}m${-a},${-i}l${a},${i}l${-i},${a}`})).call(kt,this,o))).node()}}function Vi(t){if(void 0===t)return Ji;if("function"==typeof t)return Hi(((e,n)=>t(N(n,e))));if(/^p\d{2}$/i.test(t))return Zi(x(t));switch(`${t}`.toLowerCase()){case"deviation":return ta;case"first":return Ji;case"last":return Ki;case"max":return ea;case"mean":return na;case"median":return ra;case"min":return oa;case"sum":return ia;case"extent":return Qi}throw new Error(`invalid basis: ${t}`)}function Hi(t){return{map(e,n,r){const o=+t(e,n);for(const t of e)r[t]=null===n[t]?NaN:n[t]/o}}}function Zi(t){return Hi(((e,n)=>t(e,(t=>n[t]))))}const Qi={map(t,n,r){const[o,i]=e.extent(t,(t=>n[t])),a=i-o;for(const e of t)r[e]=null===n[e]?NaN:(n[e]-o)/a}},Ji=Hi(((t,e)=>{for(let n=0;n{for(let n=t.length-1;n>=0;--n){const r=e[t[n]];if(ut(r))return r}})),ta={map(t,n,r){const o=e.mean(t,(t=>n[t])),i=e.deviation(t,(t=>n[t]));for(const e of t)r[e]=null===n[e]?NaN:i?(n[e]-o)/i:0}},ea=Zi(e.max),na=Zi(e.mean),ra=Zi(e.median),oa=Zi(e.min),ia=Zi(e.sum);function aa(t={}){"number"==typeof t&&(t={k:t});let{k:n,reduce:r,shift:o,anchor:i}=t;if(void 0===i&&void 0!==o&&(i=function(t){switch(`${t}`.toLowerCase()){case"centered":return"middle";case"leading":return"start";case"trailing":return"end"}throw new Error(`invalid shift: ${t}`)}(o),gt(`Warning: the shift option is deprecated; please use anchor "${i}" instead.`)),!((n=Math.floor(n))>0))throw new Error(`invalid k: ${n}`);return function(t="mean"){if("string"==typeof t){if(/^p\d{2}$/i.test(t))return sa(x(t));switch(t.toLowerCase()){case"deviation":return sa(e.deviation);case"max":return sa(e.max);case"mean":return ca;case"median":return sa(e.median);case"min":return sa(e.min);case"mode":return sa(e.mode);case"sum":return la;case"variance":return sa(e.variance);case"difference":return ua;case"ratio":return fa;case"first":return da;case"last":return ha}}if("function"!=typeof t)throw new Error(`invalid reduce: ${t}`);return sa(t)}(r)(n,function(t="middle",e){switch(`${t}`.toLowerCase()){case"middle":return e-1>>1;case"start":return 0;case"end":return e-1}throw new Error(`invalid anchor: ${t}`)}(i,n))}function sa(t){return(e,n)=>({map(r,o,i){const a=Float64Array.from(r,(t=>null===o[t]?NaN:o[t]));let s=0;for(let t=0;tn[t]))}function*wa(t,n){yield e.greatest(t,(t=>n[t]))}function ba(t,n,r){if(null!=t){if(null==r[t])throw new Error(`missing channel: ${t}`);t=r[t]}const o=C(r);return on(r,((r,i)=>{const a=l(r,o),s=l(r,t),c=[];for(const t of i){const r=[];for(const o of a?e.group(t,(t=>a[t])).values():[t])for(const t of n(o,s))r.push(t);c.push(r)}return{data:r,facets:c}}))}t.Area=oo,t.Arrow=ko,t.BarX=Ao,t.BarY=Ro,t.Cell=oi,t.Dot=Yo,t.Frame=ai,t.Image=li,t.Line=ui,t.Link=vo,t.Mark=tr,t.Rect=di,t.RuleX=_o,t.RuleY=Fo,t.Text=pi,t.TickX=Vo,t.TickY=Ho,t.Vector=Ui,t.area=function(t,e){return void 0===e?io(t,{x:y,y:g}):new oo(t,e)},t.areaX=function(t,e){const{y:n=u,...r}=Mr(e);return new oo(t,Pr(Tr({...r,y1:n,y2:void 0})))},t.areaY=io,t.arrow=function(t,{x:e,x1:n,x2:r,y:o,y1:i,y2:a,...s}={}){return[n,r]=wo(e,n,r),[i,a]=wo(o,i,a),new ko(t,{...s,x1:n,x2:r,y1:i,y2:a})},t.barX=Bo,t.barY=Oo,t.bin=function(t={fill:"count"},e={}){[t,e]=Ar(t,e);const{x:n,y:r}=function(t){let{x:e,y:n}=t;return e=Rr(e,t),n=Rr(n,t),[e.value,n.value]=O(e.value,n.value),{x:e,y:n}}(e);return Lr(n,r,null,null,t,fr(dr(e)))},t.binX=wr,t.binY=br,t.boxX=function(t,{x:e={transform:t=>t},y:n=null,fill:r="#ccc",fillOpacity:o,stroke:i="currentColor",strokeOpacity:a,strokeWidth:s=2,...l}={}){const c=null!=n?pn:dn;return er(Io(t,c({x1:Ko,x2:ti},{x:e,y:n,stroke:i,strokeOpacity:a,...l})),Bo(t,c({x1:"p25",x2:"p75"},{x:e,y:n,fill:r,fillOpacity:o,...l})),Zo(t,c({x:"p50"},{x:e,y:n,stroke:i,strokeOpacity:a,strokeWidth:s,...l})),Po(t,zo({x:Jo},{x:e,y:n,z:n,stroke:i,strokeOpacity:a,...l})))},t.boxY=function(t,{y:e={transform:t=>t},x:n=null,fill:r="#ccc",fillOpacity:o,stroke:i="currentColor",strokeOpacity:a,strokeWidth:s=2,...l}={}){const c=null!=n?hn:dn;return er(jo(t,c({y1:Ko,y2:ti},{x:n,y:e,stroke:i,strokeOpacity:a,...l})),Oo(t,c({y1:"p25",y2:"p75"},{x:n,y:e,fill:r,fillOpacity:o,...l})),Qo(t,c({y:"p50"},{x:n,y:e,stroke:i,strokeOpacity:a,strokeWidth:s,...l})),Po(t,zo({y:Jo},{x:n,y:e,z:n,stroke:i,strokeOpacity:a,...l})))},t.cell=function(t,{x:e,y:n,...r}={}){return[e,n]=O(e,n),new oi(t,{...r,x:e,y:n})},t.cellX=function(t,{x:e=u,fill:n,stroke:r,...o}={}){return void 0===n&&void 0===w(r)[0]&&(n=f),new oi(t,{...o,x:e,fill:n,stroke:r})},t.cellY=function(t,{y:e=u,fill:n,stroke:r,...o}={}){return void 0===n&&void 0===w(r)[0]&&(n=f),new oi(t,{...o,y:e,fill:n,stroke:r})},t.cluster=function(t,n){return Gi(t,{...n,treeLayout:e.cluster})},t.column=D,t.dot=Po,t.dotX=function(t,{x:e=f,...n}={}){return new Yo(t,{...n,x:e})},t.dotY=function(t,{y:e=f,...n}={}){return new Yo(t,{...n,y:e})},t.filter=function(t,e){return on(e,sn(t))},t.formatIsoDate=st,t.formatMonth=function(t="en-US",e="short"){const n=it(t,e);return t=>null==t||isNaN(t=new Date(Date.UTC(2e3,+t)))?void 0:n.format(t)},t.formatWeekday=function(t="en-US",e="short"){const n=at(t,e);return t=>null==t||isNaN(t=new Date(Date.UTC(2001,0,+t)))?void 0:n.format(t)},t.frame=function(t){return new ai(t)},t.group=function(t={fill:"count"},e={}){let{x:n,y:r}=e;if([n,r]=O(n,r),null==n)throw new Error("missing channel: x");if(null==r)throw new Error("missing channel: y");return mn(n,r,t,e)},t.groupX=hn,t.groupY=pn,t.groupZ=dn,t.image=function(t,{x:e,y:n,...r}={}){return void 0===r.frameAnchor&&([e,n]=O(e,n)),new li(t,{...r,x:e,y:n})},t.legend=function(t={}){for(const[e,n]of Hn){const r=t[e];if(A(r)){let o;if("symbol"===e){const{fill:e,stroke:n=(void 0===e&&A(t.color)?"color":void 0)}=t;o={fill:e,stroke:n}}return n(Ye(e,r,o),Zn(r,t),(e=>A(t[e])?Ye(e,t[e]):null))}}throw new Error("unknown legend type; no scale found")},t.line=function(t,{x:e,y:n,...r}={}){return[e,n]=O(e,n),new ui(t,{...r,x:e,y:n})},t.lineX=function(t,{x:e=f,y:n=u,...r}={}){return new ui(t,Mr({...r,x:e,y:n}))},t.lineY=function(t,{x:e=u,y:n=f,...r}={}){return new ui(t,$r({...r,x:e,y:n}))},t.link=xo,t.map=zo,t.mapX=Co,t.mapY=So,t.marks=er,t.normalize=Vi,t.normalizeX=function(t,e){return 1===arguments.length&&({basis:t,...e}=t),Co(Vi(t),e)},t.normalizeY=function(t,e){return 1===arguments.length&&({basis:t,...e}=t),So(Vi(t),e)},t.plot=Kn,t.rect=function(t,e){return new di(t,yr(gr(e)))},t.rectX=function(t,e={y:u,interval:1,x2:f}){return new di(t,Pr(gr(Tr(e))))},t.rectY=function(t,e={x:u,interval:1,y2:f}){return new di(t,qr(yr(Dr(e))))},t.reverse=function(t){return on(t,ln)},t.ruleX=jo,t.ruleY=Io,t.scale=function(t={}){let e;for(const n in t)if(Zt.has(n)&&A(t[n])){if(void 0!==e)throw new Error("ambiguous scale definition; multiple scales found");e=Qe(Ye(n,t[n]))}if(void 0===e)throw new Error("invalid scale definition; no scale found");return e},t.select=function(t,e={}){if("string"==typeof t)switch(t.toLowerCase()){case"first":return ma(e);case"last":return ya(e)}if("function"==typeof t)return ba(null,t,e);let n,r;for(n in t){if(void 0!==r)throw new Error("ambiguous selector; multiple inputs");r=pa(t[n])}if(void 0===r)throw new Error(`invalid selector: ${t}`);return ba(n,r,e)},t.selectFirst=ma,t.selectLast=ya,t.selectMaxX=function(t){return ba("x",wa,t)},t.selectMaxY=function(t){return ba("y",wa,t)},t.selectMinX=function(t){return ba("x",xa,t)},t.selectMinY=function(t){return ba("y",xa,t)},t.shuffle=function({seed:t,...n}={}){return on(n,fn(null==t?Math.random:e.randomLcg(t)))},t.sort=function(t,e){return on(e,cn(t))},t.stackX=Wr,t.stackX1=function(t={},e={}){1===arguments.length&&([t,e]=_r(t));const{y1:n,y:r=n,x:o}=e,[i,a,s]=Fr(r,o,"x",t,e);return{...i,y1:n,y:a,x:s}},t.stackX2=function(t={},e={}){1===arguments.length&&([t,e]=_r(t));const{y1:n,y:r=n,x:o}=e,[i,a,,s]=Fr(r,o,"x",t,e);return{...i,y1:n,y:a,x:s}},t.stackY=Yr,t.stackY1=function(t={},e={}){1===arguments.length&&([t,e]=_r(t));const{x1:n,x:r=n,y:o}=e,[i,a,s]=Fr(r,o,"y",t,e);return{...i,x1:n,x:a,y:s}},t.stackY2=function(t={},e={}){1===arguments.length&&([t,e]=_r(t));const{x1:n,x:r=n,y:o}=e,[i,a,,s]=Fr(r,o,"y",t,e);return{...i,x1:n,x:a,y:s}},t.text=yi,t.textX=function(t,{x:e=f,...n}={}){return new pi(t,{...n,x:e})},t.textY=function(t,{y:e=f,...n}={}){return new pi(t,{...n,y:e})},t.tickX=Zo,t.tickY=Qo,t.transform=on,t.tree=Gi,t.treeLink=Mi,t.treeNode=$i,t.valueof=l,t.vector=function(t,{x:e,y:n,...r}={}){return void 0===r.frameAnchor&&([e,n]=O(e,n)),new Ui(t,{...r,x:e,y:n})},t.vectorX=function(t,{x:e=f,...n}={}){return new Ui(t,{...n,x:e})},t.vectorY=function(t,{y:e=f,...n}={}){return new Ui(t,{...n,y:e})},t.version="0.4.3",t.window=aa,t.windowX=function(t={},e){return 1===arguments.length&&(e=t),Co(aa(t),e)},t.windowY=function(t={},e){return 1===arguments.length&&(e=t),So(aa(t),e)},Object.defineProperty(t,"__esModule",{value:!0})})); diff --git a/content/libraries/d3-shape/v3.1.0/d3-shape.js b/content/libraries/d3-shape/v3.1.0/d3-shape.js new file mode 100644 index 0000000..b7019cc --- /dev/null +++ b/content/libraries/d3-shape/v3.1.0/d3-shape.js @@ -0,0 +1,2 @@ +// https://d3js.org/d3-shape/ v3.1.0 Copyright 2010-2021 Mike Bostock +!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports,require("d3-path")):"function"==typeof define&&define.amd?define(["exports","d3-path"],n):n((t="undefined"!=typeof globalThis?globalThis:t||self).d3=t.d3||{},t.d3)}(this,(function(t,n){"use strict";function i(t){return function(){return t}}const e=Math.abs,s=Math.atan2,o=Math.cos,h=Math.max,_=Math.min,r=Math.sin,a=Math.sqrt,l=1e-12,c=Math.PI,u=c/2,f=2*c;function y(t){return t>1?0:t<-1?c:Math.acos(t)}function x(t){return t>=1?u:t<=-1?-u:Math.asin(t)}function p(t){return t.innerRadius}function v(t){return t.outerRadius}function d(t){return t.startAngle}function T(t){return t.endAngle}function g(t){return t&&t.padAngle}function b(t,n,i,e,s,o,h,_){var r=i-t,a=e-n,c=h-s,u=_-o,f=u*r-c*a;if(!(f*fO*O+R*R&&(S=A,E=P),{cx:S,cy:E,x01:-u,y01:-f,x11:S*(s/w-1),y11:E*(s/w-1)}}var w=Array.prototype.slice;function k(t){return"object"==typeof t&&"length"in t?t:Array.from(t)}function N(t){this._context=t}function S(t){return new N(t)}function E(t){return t[0]}function A(t){return t[1]}function P(t,e){var s=i(!0),o=null,h=S,_=null;function r(i){var r,a,l,c=(i=k(i)).length,u=!1;for(null==o&&(_=h(l=n.path())),r=0;r<=c;++r)!(r=c;--u)a.point(v[u],d[u]);a.lineEnd(),a.areaEnd()}p&&(v[l]=+t(f,l,i),d[l]=+e(f,l,i),a.point(o?+o(f,l,i):v[l],s?+s(f,l,i):d[l]))}if(y)return a=null,y+""||null}function c(){return P().defined(h).curve(r).context(_)}return t="function"==typeof t?t:void 0===t?E:i(+t),e="function"==typeof e?e:i(void 0===e?0:+e),s="function"==typeof s?s:void 0===s?A:i(+s),l.x=function(n){return arguments.length?(t="function"==typeof n?n:i(+n),o=null,l):t},l.x0=function(n){return arguments.length?(t="function"==typeof n?n:i(+n),l):t},l.x1=function(t){return arguments.length?(o=null==t?null:"function"==typeof t?t:i(+t),l):o},l.y=function(t){return arguments.length?(e="function"==typeof t?t:i(+t),s=null,l):e},l.y0=function(t){return arguments.length?(e="function"==typeof t?t:i(+t),l):e},l.y1=function(t){return arguments.length?(s=null==t?null:"function"==typeof t?t:i(+t),l):s},l.lineX0=l.lineY0=function(){return c().x(t).y(e)},l.lineY1=function(){return c().x(t).y(s)},l.lineX1=function(){return c().x(o).y(e)},l.defined=function(t){return arguments.length?(h="function"==typeof t?t:i(!!t),l):h},l.curve=function(t){return arguments.length?(r=t,null!=_&&(a=r(_)),l):r},l.context=function(t){return arguments.length?(null==t?_=a=null:a=r(_=t),l):_},l}function C(t,n){return nt?1:n>=t?0:NaN}function O(t){return t}N.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:this._context.lineTo(t,n)}}};var R=X(S);function z(t){this._curve=t}function X(t){function n(n){return new z(t(n))}return n._curve=t,n}function Y(t){var n=t.curve;return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t.curve=function(t){return arguments.length?n(X(t)):n()._curve},t}function q(){return Y(P().curve(R))}function B(){var t=M().curve(R),n=t.curve,i=t.lineX0,e=t.lineX1,s=t.lineY0,o=t.lineY1;return t.angle=t.x,delete t.x,t.startAngle=t.x0,delete t.x0,t.endAngle=t.x1,delete t.x1,t.radius=t.y,delete t.y,t.innerRadius=t.y0,delete t.y0,t.outerRadius=t.y1,delete t.y1,t.lineStartAngle=function(){return Y(i())},delete t.lineX0,t.lineEndAngle=function(){return Y(e())},delete t.lineX1,t.lineInnerRadius=function(){return Y(s())},delete t.lineY0,t.lineOuterRadius=function(){return Y(o())},delete t.lineY1,t.curve=function(t){return arguments.length?n(X(t)):n()._curve},t}function j(t,n){return[(n=+n)*Math.cos(t-=Math.PI/2),n*Math.sin(t)]}z.prototype={areaStart:function(){this._curve.areaStart()},areaEnd:function(){this._curve.areaEnd()},lineStart:function(){this._curve.lineStart()},lineEnd:function(){this._curve.lineEnd()},point:function(t,n){this._curve.point(n*Math.sin(t),n*-Math.cos(t))}};class D{constructor(t,n){this._context=t,this._x=n}areaStart(){this._line=0}areaEnd(){this._line=NaN}lineStart(){this._point=0}lineEnd(){(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line}point(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:this._x?this._context.bezierCurveTo(this._x0=(this._x0+t)/2,this._y0,this._x0,n,t,n):this._context.bezierCurveTo(this._x0,this._y0=(this._y0+n)/2,t,this._y0,t,n)}this._x0=t,this._y0=n}}class I{constructor(t){this._context=t}lineStart(){this._point=0}lineEnd(){}point(t,n){if(t=+t,n=+n,0==this._point++)this._x0=t,this._y0=n;else{const i=j(this._x0,this._y0),e=j(this._x0,this._y0=(this._y0+n)/2),s=j(t,this._y0),o=j(t,n);this._context.moveTo(...i),this._context.bezierCurveTo(...e,...s,...o)}}}function L(t){return new D(t,!0)}function V(t){return new D(t,!1)}function W(t){return new I(t)}function F(t){return t.source}function H(t){return t.target}function G(t){let e=F,s=H,o=E,h=A,_=null,r=null;function a(){let i;const a=w.call(arguments),l=e.apply(this,a),c=s.apply(this,a);if(null==_&&(r=t(i=n.path())),r.lineStart(),a[0]=l,r.point(+o.apply(this,a),+h.apply(this,a)),a[0]=c,r.point(+o.apply(this,a),+h.apply(this,a)),r.lineEnd(),i)return r=null,i+""||null}return a.source=function(t){return arguments.length?(e=t,a):e},a.target=function(t){return arguments.length?(s=t,a):s},a.x=function(t){return arguments.length?(o="function"==typeof t?t:i(+t),a):o},a.y=function(t){return arguments.length?(h="function"==typeof t?t:i(+t),a):h},a.context=function(n){return arguments.length?(null==n?_=r=null:r=t(_=n),a):_},a}const J=a(3);var K={draw(t,n){const i=.59436*a(n+_(n/28,.75)),e=i/2,s=e*J;t.moveTo(0,i),t.lineTo(0,-i),t.moveTo(-s,-e),t.lineTo(s,e),t.moveTo(-s,e),t.lineTo(s,-e)}},Q={draw(t,n){const i=a(n/c);t.moveTo(i,0),t.arc(0,0,i,0,f)}},U={draw(t,n){const i=a(n/5)/2;t.moveTo(-3*i,-i),t.lineTo(-i,-i),t.lineTo(-i,-3*i),t.lineTo(i,-3*i),t.lineTo(i,-i),t.lineTo(3*i,-i),t.lineTo(3*i,i),t.lineTo(i,i),t.lineTo(i,3*i),t.lineTo(-i,3*i),t.lineTo(-i,i),t.lineTo(-3*i,i),t.closePath()}};const Z=a(1/3),$=2*Z;var tt={draw(t,n){const i=a(n/$),e=i*Z;t.moveTo(0,-i),t.lineTo(e,0),t.lineTo(0,i),t.lineTo(-e,0),t.closePath()}},nt={draw(t,n){const i=.62625*a(n);t.moveTo(0,-i),t.lineTo(i,0),t.lineTo(0,i),t.lineTo(-i,0),t.closePath()}},it={draw(t,n){const i=.87559*a(n-_(n/7,2));t.moveTo(-i,0),t.lineTo(i,0),t.moveTo(0,i),t.lineTo(0,-i)}},et={draw(t,n){const i=a(n),e=-i/2;t.rect(e,e,i,i)}},st={draw(t,n){const i=.4431*a(n);t.moveTo(i,i),t.lineTo(i,-i),t.lineTo(-i,-i),t.lineTo(-i,i),t.closePath()}};const ot=r(c/10)/r(7*c/10),ht=r(f/10)*ot,_t=-o(f/10)*ot;var rt={draw(t,n){const i=a(.8908130915292852*n),e=ht*i,s=_t*i;t.moveTo(0,-i),t.lineTo(e,s);for(let n=1;n<5;++n){const h=f*n/5,_=o(h),a=r(h);t.lineTo(a*i,-_*i),t.lineTo(_*e-a*s,a*e+_*s)}t.closePath()}};const at=a(3);var lt={draw(t,n){const i=-a(n/(3*at));t.moveTo(0,2*i),t.lineTo(-at*i,-i),t.lineTo(at*i,-i),t.closePath()}};const ct=a(3);var ut={draw(t,n){const i=.6824*a(n),e=i/2,s=i*ct/2;t.moveTo(0,-i),t.lineTo(s,e),t.lineTo(-s,e),t.closePath()}};const ft=-.5,yt=a(3)/2,xt=1/a(12),pt=3*(xt/2+1);var vt={draw(t,n){const i=a(n/pt),e=i/2,s=i*xt,o=e,h=i*xt+i,_=-o,r=h;t.moveTo(e,s),t.lineTo(o,h),t.lineTo(_,r),t.lineTo(ft*e-yt*s,yt*e+ft*s),t.lineTo(ft*o-yt*h,yt*o+ft*h),t.lineTo(ft*_-yt*r,yt*_+ft*r),t.lineTo(ft*e+yt*s,ft*s-yt*e),t.lineTo(ft*o+yt*h,ft*h-yt*o),t.lineTo(ft*_+yt*r,ft*r-yt*_),t.closePath()}},dt={draw(t,n){const i=.6189*a(n-_(n/6,1.7));t.moveTo(-i,-i),t.lineTo(i,i),t.moveTo(-i,i),t.lineTo(i,-i)}};const Tt=[Q,U,tt,et,rt,lt,vt],gt=[Q,it,dt,ut,K,st,nt];function bt(){}function mt(t,n,i){t._context.bezierCurveTo((2*t._x0+t._x1)/3,(2*t._y0+t._y1)/3,(t._x0+2*t._x1)/3,(t._y0+2*t._y1)/3,(t._x0+4*t._x1+n)/6,(t._y0+4*t._y1+i)/6)}function wt(t){this._context=t}function kt(t){this._context=t}function Nt(t){this._context=t}function St(t,n){this._basis=new wt(t),this._beta=n}wt.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){switch(this._point){case 3:mt(this,this._x1,this._y1);case 2:this._context.lineTo(this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3,this._context.lineTo((5*this._x0+this._x1)/6,(5*this._y0+this._y1)/6);default:mt(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}},kt.prototype={areaStart:bt,areaEnd:bt,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._y0=this._y1=this._y2=this._y3=this._y4=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x2,this._y2),this._context.closePath();break;case 2:this._context.moveTo((this._x2+2*this._x3)/3,(this._y2+2*this._y3)/3),this._context.lineTo((this._x3+2*this._x2)/3,(this._y3+2*this._y2)/3),this._context.closePath();break;case 3:this.point(this._x2,this._y2),this.point(this._x3,this._y3),this.point(this._x4,this._y4)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x2=t,this._y2=n;break;case 1:this._point=2,this._x3=t,this._y3=n;break;case 2:this._point=3,this._x4=t,this._y4=n,this._context.moveTo((this._x0+4*this._x1+t)/6,(this._y0+4*this._y1+n)/6);break;default:mt(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}},Nt.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3;var i=(this._x0+4*this._x1+t)/6,e=(this._y0+4*this._y1+n)/6;this._line?this._context.lineTo(i,e):this._context.moveTo(i,e);break;case 3:this._point=4;default:mt(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}},St.prototype={lineStart:function(){this._x=[],this._y=[],this._basis.lineStart()},lineEnd:function(){var t=this._x,n=this._y,i=t.length-1;if(i>0)for(var e,s=t[0],o=n[0],h=t[i]-s,_=n[i]-o,r=-1;++r<=i;)e=r/i,this._basis.point(this._beta*t[r]+(1-this._beta)*(s+e*h),this._beta*n[r]+(1-this._beta)*(o+e*_));this._x=this._y=null,this._basis.lineEnd()},point:function(t,n){this._x.push(+t),this._y.push(+n)}};var Et=function t(n){function i(t){return 1===n?new wt(t):new St(t,n)}return i.beta=function(n){return t(+n)},i}(.85);function At(t,n,i){t._context.bezierCurveTo(t._x1+t._k*(t._x2-t._x0),t._y1+t._k*(t._y2-t._y0),t._x2+t._k*(t._x1-n),t._y2+t._k*(t._y1-i),t._x2,t._y2)}function Pt(t,n){this._context=t,this._k=(1-n)/6}Pt.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:At(this,this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2,this._x1=t,this._y1=n;break;case 2:this._point=3;default:At(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Mt=function t(n){function i(t){return new Pt(t,n)}return i.tension=function(n){return t(+n)},i}(0);function Ct(t,n){this._context=t,this._k=(1-n)/6}Ct.prototype={areaStart:bt,areaEnd:bt,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:At(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var Ot=function t(n){function i(t){return new Ct(t,n)}return i.tension=function(n){return t(+n)},i}(0);function Rt(t,n){this._context=t,this._k=(1-n)/6}Rt.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:At(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var zt=function t(n){function i(t){return new Rt(t,n)}return i.tension=function(n){return t(+n)},i}(0);function Xt(t,n,i){var e=t._x1,s=t._y1,o=t._x2,h=t._y2;if(t._l01_a>l){var _=2*t._l01_2a+3*t._l01_a*t._l12_a+t._l12_2a,r=3*t._l01_a*(t._l01_a+t._l12_a);e=(e*_-t._x0*t._l12_2a+t._x2*t._l01_2a)/r,s=(s*_-t._y0*t._l12_2a+t._y2*t._l01_2a)/r}if(t._l23_a>l){var a=2*t._l23_2a+3*t._l23_a*t._l12_a+t._l12_2a,c=3*t._l23_a*(t._l23_a+t._l12_a);o=(o*a+t._x1*t._l23_2a-n*t._l12_2a)/c,h=(h*a+t._y1*t._l23_2a-i*t._l12_2a)/c}t._context.bezierCurveTo(e,s,o,h,t._x2,t._y2)}function Yt(t,n){this._context=t,this._alpha=n}Yt.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:this.point(this._x2,this._y2)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var i=this._x2-t,e=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(i*i+e*e,this._alpha))}switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3;default:Xt(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var qt=function t(n){function i(t){return n?new Yt(t,n):new Pt(t,0)}return i.alpha=function(n){return t(+n)},i}(.5);function Bt(t,n){this._context=t,this._alpha=n}Bt.prototype={areaStart:bt,areaEnd:bt,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){if(t=+t,n=+n,this._point){var i=this._x2-t,e=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(i*i+e*e,this._alpha))}switch(this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:Xt(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var jt=function t(n){function i(t){return n?new Bt(t,n):new Ct(t,0)}return i.alpha=function(n){return t(+n)},i}(.5);function Dt(t,n){this._context=t,this._alpha=n}Dt.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var i=this._x2-t,e=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(i*i+e*e,this._alpha))}switch(this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:Xt(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var It=function t(n){function i(t){return n?new Dt(t,n):new Rt(t,0)}return i.alpha=function(n){return t(+n)},i}(.5);function Lt(t){this._context=t}function Vt(t){return t<0?-1:1}function Wt(t,n,i){var e=t._x1-t._x0,s=n-t._x1,o=(t._y1-t._y0)/(e||s<0&&-0),h=(i-t._y1)/(s||e<0&&-0),_=(o*s+h*e)/(e+s);return(Vt(o)+Vt(h))*Math.min(Math.abs(o),Math.abs(h),.5*Math.abs(_))||0}function Ft(t,n){var i=t._x1-t._x0;return i?(3*(t._y1-t._y0)/i-n)/2:n}function Ht(t,n,i){var e=t._x0,s=t._y0,o=t._x1,h=t._y1,_=(o-e)/3;t._context.bezierCurveTo(e+_,s+_*n,o-_,h-_*i,o,h)}function Gt(t){this._context=t}function Jt(t){this._context=new Kt(t)}function Kt(t){this._context=t}function Qt(t){this._context=t}function Ut(t){var n,i,e=t.length-1,s=new Array(e),o=new Array(e),h=new Array(e);for(s[0]=0,o[0]=2,h[0]=t[0]+2*t[1],n=1;n=0;--n)s[n]=(h[n]-s[n+1])/o[n];for(o[e-1]=(t[e]+s[e-1])/2,n=0;n1)for(var i,e,s,o=1,h=t[n[0]],_=h.length;o=0;)i[n]=n;return i}function nn(t,n){return t[n]}function en(t){const n=[];return n.key=t,n}function sn(t){var n=t.map(on);return tn(t).sort((function(t,i){return n[t]-n[i]}))}function on(t){for(var n,i=-1,e=0,s=t.length,o=-1/0;++io&&(o=n,e=i);return e}function hn(t){var n=t.map(_n);return tn(t).sort((function(t,i){return n[t]-n[i]}))}function _n(t){for(var n,i=0,e=-1,s=t.length;++e=0&&(this._t=1-this._t,this._line=1-this._line)},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:if(this._t<=0)this._context.lineTo(this._x,n),this._context.lineTo(t,n);else{var i=this._x*(1-this._t)+t*this._t;this._context.lineTo(i,this._y),this._context.lineTo(i,n)}}this._x=t,this._y=n}},t.arc=function(){var t=p,h=v,w=i(0),k=null,N=d,S=T,E=g,A=null;function P(){var i,p,v=+t.apply(this,arguments),d=+h.apply(this,arguments),T=N.apply(this,arguments)-u,g=S.apply(this,arguments)-u,P=e(g-T),M=g>T;if(A||(A=i=n.path()),dl)if(P>f-l)A.moveTo(d*o(T),d*r(T)),A.arc(0,0,d,T,g,!M),v>l&&(A.moveTo(v*o(g),v*r(g)),A.arc(0,0,v,g,T,M));else{var C,O,R=T,z=g,X=T,Y=g,q=P,B=P,j=E.apply(this,arguments)/2,D=j>l&&(k?+k.apply(this,arguments):a(v*v+d*d)),I=_(e(d-v)/2,+w.apply(this,arguments)),L=I,V=I;if(D>l){var W=x(D/v*r(j)),F=x(D/d*r(j));(q-=2*W)>l?(X+=W*=M?1:-1,Y-=W):(q=0,X=Y=(T+g)/2),(B-=2*F)>l?(R+=F*=M?1:-1,z-=F):(B=0,R=z=(T+g)/2)}var H=d*o(R),G=d*r(R),J=v*o(Y),K=v*r(Y);if(I>l){var Q,U=d*o(z),Z=d*r(z),$=v*o(X),tt=v*r(X);if(Pl?V>l?(C=m($,tt,H,G,d,V,M),O=m(U,Z,J,K,d,V,M),A.moveTo(C.cx+C.x01,C.cy+C.y01),Vl&&q>l?L>l?(C=m(J,K,U,Z,v,-L,M),O=m(H,G,$,tt,v,-L,M),A.lineTo(C.cx+C.x01,C.cy+C.y01),L0&&(y+=c);for(null!=n?x.sort((function(t,i){return n(p[t],p[i])})):null!=e&&x.sort((function(t,n){return e(i[t],i[n])})),_=0,a=y?(d-u*g)/y:0;_0?c*a:0)+g,p[r]={data:i[r],index:_,value:c,startAngle:v,endAngle:l,padAngle:T};return p}return _.value=function(n){return arguments.length?(t="function"==typeof n?n:i(+n),_):t},_.sortValues=function(t){return arguments.length?(n=t,e=null,_):n},_.sort=function(t){return arguments.length?(e=t,n=null,_):e},_.startAngle=function(t){return arguments.length?(s="function"==typeof t?t:i(+t),_):s},_.endAngle=function(t){return arguments.length?(o="function"==typeof t?t:i(+t),_):o},_.padAngle=function(t){return arguments.length?(h="function"==typeof t?t:i(+t),_):h},_},t.pointRadial=j,t.radialArea=B,t.radialLine=q,t.stack=function(){var t=i([]),n=tn,e=$t,s=nn;function o(i){var o,h,_=Array.from(t.apply(this,arguments),en),r=_.length,a=-1;for(const t of i)for(o=0,++a;o0)for(var i,e,s,o,h,_,r=0,a=t[n[0]].length;r0?(e[0]=o,e[1]=o+=s):s<0?(e[1]=h,e[0]=h+=s):(e[0]=0,e[1]=s)},t.stackOffsetExpand=function(t,n){if((e=t.length)>0){for(var i,e,s,o=0,h=t[0].length;o0){for(var i,e=0,s=t[n[0]],o=s.length;e0&&(e=(i=t[n[0]]).length)>0){for(var i,e,s,o=0,h=1;h