Skip to content

Bar Chart ​

The relative frequency of letters in English, drawn by a barY composite shape that appends the bars and both axes, with d3-scale. After the D3 bar chart.

js
const alphabet = [
  {letter: "A", frequency: 0.08167},
  {letter: "B", frequency: 0.01492},
  {letter: "C", frequency: 0.02782},
  {letter: "D", frequency: 0.04253},
  {letter: "E", frequency: 0.12702},
  {letter: "F", frequency: 0.02288},
  {letter: "G", frequency: 0.02015},
  {letter: "H", frequency: 0.06094},
  {letter: "I", frequency: 0.06966},
  {letter: "J", frequency: 0.00153},
  {letter: "K", frequency: 0.00772},
  {letter: "L", frequency: 0.04025},
  {letter: "M", frequency: 0.02406},
  {letter: "N", frequency: 0.06749},
  {letter: "O", frequency: 0.07507},
  {letter: "P", frequency: 0.01929},
  {letter: "Q", frequency: 0.00095},
  {letter: "R", frequency: 0.05987},
  {letter: "S", frequency: 0.06327},
  {letter: "T", frequency: 0.09056},
  {letter: "U", frequency: 0.02758},
  {letter: "V", frequency: 0.00978},
  {letter: "W", frequency: 0.0236},
  {letter: "X", frequency: 0.0015},
  {letter: "Y", frequency: 0.01974},
  {letter: "Z", frequency: 0.00074},
];

const width = 640;
const height = 400;
const font = {fill: "black", fontSize: 10, fontFamily: "sans-serif"};

function barY(flow, {x, y, fill = "steelblue", marginTop = 20, marginRight = 0, marginBottom = 30, marginLeft = 40}) {
  const scaleX = d3.scaleBand(x, [marginLeft, width - marginRight]).padding(0.1);
  const scaleY = d3.scaleLinear([0, d3.max(y)], [height - marginBottom, marginTop]).nice();
  const I = d3.range(x.length);

  flow.data(I).append(cm.rect, {
    x: (i) => scaleX(x[i]),
    y: (i) => scaleY(y[i]),
    width: scaleX.bandwidth(),
    height: (i) => scaleY(0) - scaleY(y[i]),
    fill,
  });
  flow
    .datum(0)
    .append(cm.group, {x: 0, y: height - marginBottom})
    .call(axisX, scaleX);
  flow.datum(0).append(cm.group, {x: marginLeft, y: 0}).call(axisY, scaleY);
}

function axisX(flow, scale) {
  const [x, x1] = scale.range();
  const tickX = (d) => scale(d) + scale.bandwidth() / 2;
  flow.append(cm.link, {x, y: 0, x1, y1: 0, stroke: "black"});
  flow.data(scale.domain()).append(cm.link, {x: tickX, y: 0, x1: tickX, y1: 4, stroke: "black"});
  flow.data(scale.domain()).append(cm.text, {
    ...font,
    text: (d) => d,
    x: tickX,
    y: 8,
    textAlign: "center",
    textBaseline: "top",
  });
}

function axisY(flow, scale) {
  const format = scale.tickFormat(10, "%");
  flow.data(scale.ticks()).append(cm.link, {x: 0, y: scale, x1: -4, y1: scale, stroke: "black"});
  flow.data(scale.ticks()).append(cm.text, {
    ...font,
    text: format,
    x: -6,
    y: scale,
    textAlign: "end",
    textBaseline: "middle",
  });
}

const renderer = cm.canvas({width, height});
const root = cm.flow().renderer(renderer);

root.data(alphabet).append(barY, {
  x: (d) => d.letter,
  y: (d) => d.frequency,
});

root.render();

document.body.append(renderer.node());