Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ It’s not just line charts, of course. Here’s another useful chart type, the
Plot.plot({
height: 240,
marks: [
Plot.binX(data, {x: "Volume"}),
Plot.binRectY(data, {x: "Volume"}),
Plot.ruleY([0]) // add a rule at y = 0
]
})
Expand Down
8 changes: 4 additions & 4 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@ export {plot} from "./plot.js";
export {Mark} from "./mark.js";
export {Area, area, areaX, areaY} from "./marks/area.js";
export {BarX, BarY, barX, barY} from "./marks/bar.js";
export {bin, binX, binY} from "./marks/bin.js";
export {binDot, binRect, binRectX, binRectY} from "./marks/bin.js";
export {Cell, cell, cellX, cellY} from "./marks/cell.js";
export {Dot, dot, dotX, dotY} from "./marks/dot.js";
export {Frame, frame} from "./marks/frame.js";
export {group, groupX, groupY} from "./marks/group.js";
export {groupCell, groupDot, groupBarX, groupBarY} from "./marks/group.js";
export {Line, line, lineX, lineY} from "./marks/line.js";
export {Link, link} from "./marks/link.js";
export {Rect, rect, rectX, rectY} from "./marks/rect.js";
export {RuleX, RuleY, ruleX, ruleY} from "./marks/rule.js";
export {stackAreaX, stackAreaY, stackBarX, stackBarY} from "./marks/stack.js";
export {Text, text, textX, textY} from "./marks/text.js";
export {TickX, TickY, tickX, tickY} from "./marks/tick.js";
export {bin1, bin2} from "./transforms/bin.js";
export {group1, group2} from "./transforms/group.js";
export {bin, binX, binY, binR} from "./transforms/bin.js";
export {group, groupX, groupY} from "./transforms/group.js";
export {movingAverage} from "./transforms/movingAverage.js";
export {stackX, stackY} from "./transforms/stack.js";
7 changes: 0 additions & 7 deletions src/mark.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,13 +130,6 @@ export function maybeNumber(value, defaultValue) {
: [value, undefined];
}

// The value may be defined as a string or function, rather than an object with
// a value property. TODO Allow value to be specified as array, too? This would
// require promoting the array to an accessor for compatibility with d3.bin.
export function maybeValue(x) {
return typeof x === "string" || typeof x === "function" ? {value: x} : x;
}

// If the channel value is specified as a string, indicating a named field, this
// wraps the specified function f with another function with the corresponding
// label property, such that the associated axis inherits the label by default.
Expand Down
103 changes: 10 additions & 93 deletions src/marks/bin.js
Original file line number Diff line number Diff line change
@@ -1,102 +1,19 @@
import {arrayify, identity, maybeLabel} from "../mark.js";
import {bin1, bin2} from "../transforms/bin.js";
import {bin, binX, binY, binR} from "../transforms/bin.js";
import {rect, rectX, rectY} from "./rect.js";
import {dot} from "./dot.js";

export function bin(data, {x, y, domain, thresholds, normalize, transform, ...options} = {}) {
data = arrayify(data);
if (transform !== undefined) data = arrayify(transform(data));
return rect(
data,
{
insetTop: 1,
insetLeft: 1,
...options,
transform: bin2({x, y, domain, thresholds}),
fill: normalize ? normalizer(normalize, data.length) : length,
x1: maybeLabel(x0, x),
x2: x1,
y1: maybeLabel(y0, y),
y2: y1
}
);
export function binRect(data, options) {
return rect(data, bin({insetTop: 1, insetLeft: 1, ...options, out: "fill"}));
}

export function binX(data, {
x = identity,
domain,
thresholds,
normalize,
cumulative,
transform,
...options
} = {}) {
data = arrayify(data);
if (transform !== undefined) data = arrayify(transform(data));
return rectY(
data,
{
insetLeft: 1,
...options,
transform: bin1({value: x, domain, thresholds, cumulative}),
y: normalize ? normalizer(normalize, data.length) : length,
x1: maybeLabel(x0, x),
x2: x1
}
);
export function binDot(data, options) {
return dot(data, binR(options));
}

export function binY(data, {
y = identity,
domain,
thresholds,
normalize,
cumulative,
transform,
...options
} = {}) {
data = arrayify(data);
if (transform !== undefined) data = arrayify(transform(data));
return rectX(
data,
{
insetTop: 1,
...options,
transform: bin1({value: y, domain, thresholds, cumulative}),
x: normalize ? normalizer(normalize, data.length) : length,
y1: maybeLabel(x0, y),
y2: x1
}
);
export function binRectY(data, options) {
return rectY(data, binX({insetLeft: 1, ...options}));
}

function x0(d) {
return d.x0;
}

function x1(d) {
return d.x1;
}

function y0(d) {
return d.y0;
}

function y1(d) {
return d.y1;
}

function length(d) {
return d.length;
}

length.label = "Frequency";

// An alternative channel definition to length (above) that computes the
// proportion of each bin in [0, k]. If k is true, it is treated as 100 for
// percentages; otherwise, it is typically 1.
function normalizer(k, n) {
k = k === true ? 100 : +k;
const value = bin => bin.length * k / n;
value.label = `Frequency${k === 100 ? " (%)" : ""}`;
return value;
export function binRectX(data, options) {
return rectX(data, binY({insetTop: 1, ...options}));
}
93 changes: 10 additions & 83 deletions src/marks/group.js
Original file line number Diff line number Diff line change
@@ -1,93 +1,20 @@
import {arrayify, identity, first, second, maybeLabel, maybeZero} from "../mark.js";
import {group1, group2} from "../transforms/group.js";
import {groupX, groupY, group} from "../transforms/group.js";
import {barX, barY} from "./bar.js";
import {cell} from "./cell.js";
import {dot} from "./dot.js";

export function group(data, {
x = first,
y = second,
transform,
...options
} = {}) {
if (transform !== undefined) data = transform(arrayify(data));
return cell(
data,
{
...options,
transform: group2(x, y),
x: maybeLabel(first, x),
y: maybeLabel(second, y),
fill: length3
}
);
export function groupCell(data, options) {
return cell(data, group({...options, out: "fill"}));
}

export function groupX(data, {
x = identity,
y,
y1,
y2,
transform,
...options
} = {}) {
data = arrayify(data);
if (transform !== undefined) data = arrayify(transform(data));
([y1, y2] = maybeZero(y, y1, y2, maybeLength(data, options)));
return barY(
data,
{
...options,
transform: group1(x),
x: maybeLabel(first, x),
y1,
y2
}
);
export function groupDot(data, options) {
return dot(data, group({...options, out: "r"}));
}

export function groupY(data, {
y = identity,
x,
x1,
x2,
transform,
...options
} = {}) {
data = arrayify(data);
if (transform !== undefined) data = arrayify(transform(data));
([x1, x2] = maybeZero(x, x1, x2, maybeLength(data, options)));
return barX(
data,
{
...options,
transform: group1(y),
x1,
x2,
y: maybeLabel(first, y)
}
);
export function groupBarX(data, options) {
return barX(data, groupY(options));
}

function length2([, group]) {
return group.length;
}

function length3([,, group]) {
return group.length;
}

length2.label = length3.label = "Frequency";

function maybeLength(data, {normalize}) {
return normalize ? normalizer(normalize, data.length) : length2;
}

// An alternative channel definition to length2 (above) that computes the
// proportion of each bin in [0, k]. If k is true, it is treated as 100 for
// percentages; otherwise, it is typically 1.
function normalizer(k, n) {
k = k === true ? 100 : +k;
const value = ([, group]) => group.length * k / n;
value.label = `Frequency${k === 100 ? " (%)" : ""}`;
return value;
export function groupBarY(data, options) {
return barY(data, groupX(options));
}
8 changes: 4 additions & 4 deletions src/marks/stack.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@ import {areaX, areaY} from "./area.js";
import {barX, barY} from "./bar.js";

export function stackAreaX(data, options) {
return areaX(...stackX(data, options));
return areaX(data, stackX(options));
}

export function stackAreaY(data, options) {
return areaY(...stackY(data, options));
return areaY(data, stackY(options));
}

export function stackBarX(data, options) {
return barX(...stackX(data, options));
return barX(data, stackX(options));
}

export function stackBarY(data, options) {
return barY(...stackY(data, options));
return barY(data, stackY(options));
}
Loading