Bar mark
TIP
The bar mark is a variant of the rect mark for use when one dimension is ordinal and the other is quantitative. See also the cell mark.
The bar mark comes in two orientations: barY extends vertically↑ as in a vertical bar chart or column chart, while barX extends horizontally→. For example, the bar chart below shows the frequency of letters in the English language.
ForkPlot.barY(alphabet, {x: "letter", y: "frequency"}).plot()
Ordinal domains are sorted naturally (alphabetically) by default. Either set the scale domain explicitly to change the order, or use the mark sort option to derive the scale domain from a channel. For example, to sort x by descending y:
ForkPlot.barY(alphabet, {x: "letter", y: "frequency", sort: {x: "-y"}}).plot()
There is typically one ordinal value associated with each bar, such as a name (or above, letter), and two quantitative values defining a lower and upper bound; the lower bound is often not specified (as above) because it defaults to zero. For barY, x is ordinal and y1 & y2 are quantitative, whereas for barX, y is ordinal and x1 & x2 are quantitative.
Above, since y was specified instead of y1 and y2, the bar spans from zero to the given y value: if you only specify a single quantitative value, barY applies an implicit stackY transform and likewise barX implicitly applies stackX. The stacked horizontal bar chart below draws one bar (of unit width in x) per penguin, colored and sorted by the penguin’s body mass, and grouped by species along y.
ForkPlot.plot({
marginLeft: 60,
x: {label: "Frequency"},
y: {label: null},
color: {legend: true},
marks: [
Plot.barX(penguins, {y: "species", x: 1, inset: 0.5, fill: "body_mass_g", sort: "body_mass_g"}),
Plot.ruleX([0])
]
})
TIP
The group transform with the count reducer could be used to produce one bar per species.
You can opt-out of the implicit stack transform by specifying the bar’s extent with two quantitative values: x1 and x2 for barX, or y1 and y2 for barY. For example, here is a historical timeline of civilizations, where each has a beginning and an end.
ForkPlot.plot({
marginLeft: 130,
axis: null,
x: {
axis: "top",
grid: true,
tickFormat: (x) => x < 0 ? `${-x} BC` : `${x} AD`
},
marks: [
Plot.barX(civilizations, {
x1: "start",
x2: "end",
y: "civilization",
sort: {y: "x1"}
}),
Plot.text(civilizations, {
x: "start",
y: "civilization",
text: "civilization",
textAnchor: "end",
dx: -3
})
]
})
TIP
This uses a text mark to label the bars directly instead of a y axis. It also uses a custom tick format for the x axis to show the calendar era.
For a diverging bar chart, simply specify a negative value. The chart below shows change in population from 2010 to 2019. States whose population increased are green, while states whose population decreased are pink. (Puerto Rico’s population declined sharply after hurricanes Maria and Irma.)
ForkPlot.plot({
label: null,
x: {
axis: "top",
label: "← decrease · Change in population, 2010–2019 (%) · increase →",
labelAnchor: "center",
tickFormat: "+",
percent: true
},
color: {
scheme: "PiYg",
type: "ordinal"
},
marks: [
Plot.barX(statepop, {y: "State", x: (d) => (d[2019] - d[2010]) / d[2010], fill: (d) => Math.sign(d[2019] - d[2010]), sort: {y: "x"}}),
Plot.gridX({stroke: "white", strokeOpacity: 0.5}),
Plot.axisY({x: 0}),
Plot.ruleX([0])
]
})
TIP
The percent scale option is useful for showing percentages; it applies a scale transform that multiplies associated channel values by 100.
When ordinal data is regular, such as the yearly observations of the time-series bar chart of world population below, use the interval option to enforce uniformity and show gaps for missing data. It can be set to a named interval such as hour or day, a number for numeric intervals, a d3-time interval, or a custom implementation.
ForkPlot
.barY(timeseries, {x: "year", y: "population"})
.plot({x: {tickFormat: "", interval: checked ? 1 : undefined}})
TIP
You can also make a time-series bar chart with a rect mark, possibly with the bin transform to bin observations at regular intervals.
A bar’s ordinal dimension is optional; if missing, the bar spans the chart along this dimension. Such bars typically also have a color encoding. For example, here are warming stripes showing the increase in average temperature globally over the last 172 years.
ForkPlot.plot({
x: {round: true, tickFormat: "d"},
color: {scheme: "BuRd"},
marks: [
Plot.barX(hadcrut, {
x: "year",
fill: "anomaly",
interval: 1, // annual observations
inset: 0 // no gaps
})
]
})
With the stack transform, a one-dimensional bar can show the proportions of each value relative to the whole, as a compact alternative to a pie or donut chart.
ForkPlot.plot({
x: {percent: true},
marks: [
Plot.barX(alphabet, Plot.stackX({x: "frequency", fillOpacity: 0.3, inset: 0.5})),
Plot.textX(alphabet, Plot.stackX({x: "frequency", text: "letter", inset: 0.5})),
Plot.ruleX([0, 1])
]
})
TIP
Although barX applies an implicit stackX transform, textX does not; this example uses an explicit stackX transform in both cases for clarity.
For a grouped bar chart, use faceting. The chart below uses fy to partition the bar chart of penguins by island.
ForkPlot.plot({
marginLeft: 60,
marginRight: 60,
label: null,
x: {label: "Frequency"},
y: {padding: 0},
marks: [
Plot.barX(penguins, {fy: "island", y: "sex", x: 1, inset: 0.5}),
Plot.ruleX([0])
]
})
Bar options
For required channels, see barX and barY. The bar mark supports the standard mark options, including insets and rounded corners. The stroke defaults to none. The fill defaults to currentColor if the stroke is none, and to none otherwise.
barX(data, options)
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
The following optional channels are supported:
- y - the vertical position; bound to the y scale, which must be band
If neither the x1 nor x2 option is specified, the x option may be specified as shorthand to apply an implicit stackX transform; 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 identity. If options is undefined, then it defaults to x2 as identity and y as the zero-based index [0, 1, 2, …]; this allows an array of numbers to be passed to barX to make a quick sequential bar chart. If the y channel is not specified, the bar will span the full vertical extent 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. Named UTC intervals such as day are also supported; see scale options.
barY(data, options)
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
The following optional channels are supported:
- x - the horizontal position; bound to the x scale, which must be band
If neither the y1 nor y2 option is specified, the y option may be specified as shorthand to apply an implicit stackY transform; 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 identity. If options is undefined, then it defaults to y2 as identity and x as the zero-based index [0, 1, 2, …]; this allows an array of numbers to be passed to barY to make a quick sequential bar chart. If the x channel is not specified, the bar will span the full horizontal extent 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. Named UTC intervals such as day are also supported; see scale options.