Annotation Recipe

Selected film ratings over release years with title annotations
Point positions reused by a field-driven text layer.

Minimal flow

Runnable: install ggaction and provide the named data array as plain row objects.

import { chart } from "ggaction";

const program = chart()
  .createCanvas()
  .createData({ values: films })
  .createScatterPlot({ x: "Released_Year", y: "IMDB_Rating" })
  .createTextMark({ dx: 7, dy: -6, align: "left", baseline: "bottom" })
  .encodeText({ field: "Series_Title" })
  .layoutLabels({
    padding: 3,
    maxDisplacement: 48,
    leader: { stroke: "#94a3b8", opacity: 0.8 }
  });

films is an array of plain row objects containing the two position fields and the label field. The text layer reuses the preceding point layer’s data and resolved Cartesian anchors.

You must decide

The library infers

layoutLabels() reduces label-to-label overlap within the requested plot or Canvas bounds. It is bounded best effort: dense impossible layouts store a warning summary instead of expanding margins or changing typography. Filter rows when every label still cannot fit.

Continue

Text marks · Data filtering