Skip to content

Commit

Permalink
document box (observablehq#1394)
Browse files Browse the repository at this point in the history
* document box

* remove unused accessor

* adopt identity transform

* edits

---------

Co-authored-by: Mike Bostock <[email protected]>
  • Loading branch information
2 people authored and chaichontat committed Jan 14, 2024
1 parent f4a1340 commit 19f37cb
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 12 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1185,7 +1185,7 @@ 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 [tick](#tick) representing 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:
Expand Down
40 changes: 40 additions & 0 deletions src/marks/box.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,50 @@ import type {DotOptions} from "./dot.js";
import type {RuleXOptions, RuleYOptions} from "./rule.js";
import type {TickXOptions, TickYOptions} from "./tick.js";

/** Options for the boxX mark. */
export type BoxXOptions = DotOptions & BarXOptions & TickXOptions & RuleXOptions;

/** Options for the boxY mark. */
export type BoxYOptions = DotOptions & BarYOptions & TickYOptions & RuleYOptions;

/**
* Returns a box mark that draws horizontal boxplots where **x** is quantitative
* or temporal and **y**, if present, is ordinal. The box mark is a compound
* mark consisting of four marks:
*
* - a rule representing the extreme values (not including outliers),
* - a bar representing the interquartile range (trimmed to the data),
* - a tick representing the median value, and
* - a 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 2
*/
export function boxX(data?: Data, options?: BoxXOptions): CompoundMark;

/**
* Returns a box mark that draws vertical boxplots where **y** is quantitative
* or temporal and **x**, if present, is ordinal. The box mark is a compound
* mark consisting of four marks:
*
* - a rule representing the extreme values (not including outliers),
* - a bar representing the interquartile range (trimmed to the data),
* - a tick representing the median value, and
* - a 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 2
*/
export function boxY(data?: Data, options?: BoxYOptions): CompoundMark;
23 changes: 12 additions & 11 deletions src/marks/box.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {min, max, quantile} from "d3";
import {max, min, quantile} from "d3";
import {marks} from "../mark.js";
import {identity} from "../options.js";
import {groupX, groupY, groupZ} from "../transforms/group.js";
import {map} from "../transforms/map.js";
import {barX, barY} from "./bar.js";
Expand All @@ -11,7 +12,7 @@ export function boxX(data, options = {}) {
// Returns a composite mark for producing a horizontal box plot, applying the
// necessary statistical transforms. The boxes are grouped by y, if present.
const {
x = {transform: (x) => x},
x = identity,
y = null,
fill = "#ccc",
fillOpacity,
Expand All @@ -34,7 +35,7 @@ export function boxY(data, options = {}) {
// Returns a composite mark for producing a vertical box plot, applying the
// necessary statistical transforms. The boxes are grouped by x, if present.
const {
y = {transform: (y) => y},
y = identity,
x = null,
fill = "#ccc",
fillOpacity,
Expand All @@ -60,20 +61,20 @@ function oqr(values) {
return values.map((v) => (v < r1 || v > r2 ? v : NaN));
}

function loqr1(values, value) {
const lo = quartile1(values, value) * 2.5 - quartile3(values, value) * 1.5;
function loqr1(values) {
const lo = quartile1(values) * 2.5 - quartile3(values) * 1.5;
return min(values, (d) => (d >= lo ? d : NaN));
}

function hiqr2(values, value) {
const hi = quartile3(values, value) * 2.5 - quartile1(values, value) * 1.5;
function hiqr2(values) {
const hi = quartile3(values) * 2.5 - quartile1(values) * 1.5;
return max(values, (d) => (d <= hi ? d : NaN));
}

function quartile1(values, value) {
return quantile(values, 0.25, value);
function quartile1(values) {
return quantile(values, 0.25);
}

function quartile3(values, value) {
return quantile(values, 0.75, value);
function quartile3(values) {
return quantile(values, 0.75);
}

0 comments on commit 19f37cb

Please sign in to comment.