Skip to content

Commit 516cbe3

Browse files
Filmbostock
andauthored
aspectRatio option (#837)
Co-authored-by: Mike Bostock <[email protected]>
1 parent d9c992b commit 516cbe3

17 files changed

+8477
-24
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,12 @@ These options determine the overall layout of the plot; all are specified as num
9292
* **margin** - shorthand for the four margins
9393
* **width** - the outer width of the plot (including margins)
9494
* **height** - the outer height of the plot (including margins)
95+
* **aspectRatio** - the desired aspect ratio of data (affecting default **height**)
9596

9697
The default **width** is 640. On Observable, the width can be set to the [standard width](https://github.com/observablehq/stdlib/blob/main/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 maximum margins of the plot’s constituent [marks](#mark-options). While most marks default to zero margins (because they are drawn inside the chart area), Plot’s [axis mark](#axis) has non-zero default margins.
9798

99+
The **aspectRatio** option, if not null, computes a default **height** such that a variation of one unit in the *x* dimension is represented by the corresponding number of pixels as a variation in the *y* dimension of one unit. Note: when using facets, set the *fx* and *fy* scales’ **round** option to false if you need an exact aspect ratio.
100+
98101
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:
99102

100103
```js

src/dimensions.js

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import {extent} from "d3";
12
import {projectionAspectRatio} from "./projection.js";
23
import {isOrdinalScale} from "./scales.js";
34
import {offset} from "./style.js";
@@ -87,9 +88,9 @@ export function Dimensions(scales, marks, options = {}) {
8788
}
8889

8990
function autoHeight(
90-
{y, fy, fx},
91+
{x, y, fy, fx},
9192
marks,
92-
{projection},
93+
{projection, aspectRatio},
9394
{width, marginTopDefault, marginRightDefault, marginBottomDefault, marginLeftDefault}
9495
) {
9596
const nfy = fy ? fy.scale.domain().length : 1;
@@ -104,5 +105,45 @@ function autoHeight(
104105
}
105106

106107
const ny = y ? (isOrdinalScale(y) ? y.scale.domain().length : Math.max(7, 17 / nfy)) : 1;
108+
109+
// If a desired aspect ratio is given, compute a default height to match.
110+
if (aspectRatio != null) {
111+
aspectRatio = +aspectRatio;
112+
if (!(isFinite(aspectRatio) && aspectRatio > 0)) throw new Error(`invalid aspectRatio: ${aspectRatio}`);
113+
const ratio = aspectRatioLength("y", y) / (aspectRatioLength("x", x) * aspectRatio);
114+
const fxb = fx ? fx.scale.bandwidth() : 1;
115+
const fyb = fy ? fy.scale.bandwidth() : 1;
116+
const w = fxb * (width - marginLeftDefault - marginRightDefault) - x.insetLeft - x.insetRight;
117+
return (ratio * w + y.insetTop + y.insetBottom) / fyb + marginTopDefault + marginBottomDefault;
118+
}
119+
107120
return !!(y || fy) * Math.max(1, Math.min(60, ny * nfy)) * 20 + !!fx * 30 + 60;
108121
}
122+
123+
function aspectRatioLength(k, scale) {
124+
if (!scale) throw new Error(`aspectRatio requires ${k} scale`);
125+
const {type, domain} = scale;
126+
let transform;
127+
switch (type) {
128+
case "linear":
129+
case "utc":
130+
case "time":
131+
transform = Number;
132+
break;
133+
case "pow": {
134+
const exponent = scale.scale.exponent();
135+
transform = (x) => Math.pow(x, exponent);
136+
break;
137+
}
138+
case "log":
139+
transform = Math.log;
140+
break;
141+
case "point":
142+
case "band":
143+
return domain.length;
144+
default:
145+
throw new Error(`unsupported ${k} scale for aspectRatio: ${type}`);
146+
}
147+
const [min, max] = extent(domain);
148+
return Math.abs(transform(max) - transform(min));
149+
}

test/data/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,11 @@ https://data.giss.nasa.gov/gistemp/
9595
Met Office Hadley Centre
9696
https://www.metoffice.gov.uk/hadobs/hadcrut4/data/current/series_format.html
9797

98+
## libor.csv
99+
CBO
100+
https://www.cbo.gov/topics/budget/accuracy-projections
101+
https://observablehq.com/@tophtucker/examples-of-bitemporal-charts
102+
98103
## metros.csv
99104
The New York Times
100105
https://www.nytimes.com/2019/12/02/upshot/wealth-poverty-divide-american-cities.html

0 commit comments

Comments
 (0)