Skip to content

Place ​

The Place family holds the ways a label can find its spot on the mark it labels. A place is a value of the position option of .label(), beside the position strings ("outset-top", "center", ...). A position string puts the label at one spot by the mark's box. A place reads the mark's outline and tries spots in order.

ts
import { Place, Unit, chart, group, line, scatter } from "gofish-graphics";
import data from "vega-datasets";

const yearlyStocks = async () => {
  const rows = (await data["stocks.csv"]()) as any[];
  const acc = new Map<
    string,
    { symbol: string; date: string; sum: number; n: number }
  >();
  for (const d of rows) {
    const year = new Date(d.date).getFullYear();
    const key = `${d.symbol}${year}`;
    const e = acc.get(key) ?? {
      symbol: d.symbol,
      date: `${year}-07-01`,
      sum: 0,
      n: 0,
    };
    e.sum += +d.price;
    e.n += 1;
    acc.set(key, e);
  }
  return [...acc.values()].map((e) => ({
    symbol: e.symbol,
    date: e.date,
    price: Math.round((e.sum / e.n) * 100) / 100,
  }));
};

(async () => {
  const loaded = { stocks: await yearlyStocks() };
  const context = { loaded };
  const container = document.getElementById("app");
  chart(context.loaded.stocks, { schema: { date: Unit.time() }, w: 560, h: 320 })
    .flow(
      group({ by: "symbol" }),
      scatter({ by: "date", x: "date", y: "price" })
    )
    .mark(
      line({ stroke: "symbol", strokeWidth: 2 }).label("symbol", {
        position: Place.along({ at: 0.6, orient: "sloped" }),
        halo: {},
        fontWeight: 600,
      })
    )
    .render(container, { axes: true, legend: false });
})();

Signature ​

ts
Place.around; // or Place.around({ directions?, side?, offset? })
Place.along; // or Place.along({ at?, side?, orient?, offset? })
Place.start; // or Place.start({ offset? })
Place.end; // or Place.end({ offset? })
Place.interior;

No place has a required option, so each member is a place as it is, and calling it sets options: Place.end and Place.end() are the same place. A place is a plain object, { kind, ...params }, of type Place.Place, for example { kind: "along", at: 0.6, orient: "sloped" }. The same object is the place's wire form.

The family is also a module of its own:

ts
import { Place } from "gofish-graphics";
import { along } from "gofish-graphics/place"; // the same value as Place.along

Members ​

MemberReadsWhere the label goesDefault for
Place.around()the outline's extreme pointsJust outside the mark, in each of eight screen directions.a dot (circle)
Place.along()an open path or a region's outlineOn or beside the outline, sliding along it from at.
Place.start()an open path's first pointJust before the path's start, level.
Place.end()an open path's last pointJust past the path's end, level.a line, an arrow
Place.interior()a filled regionInside the region, where the label's box can grow largest.a band, a polygon

With no position, a label takes the default for its mark's kind of geometry, and "outset" for any other mark.

How the labels of one call are placed ​

The labels of one .label() call are placed together, in data order. Each takes its first spot that stays inside the plot and covers no labeled mark, no label already placed, and no node in the label's avoiding option. A label with no free spot is hidden, and the render prints how many labels each call hid. A label of Place.start() or Place.end() has one spot, past its path's end, which may be outside the plot. Labels there that would cover each other slide apart vertically, and a label that still covers a mark, a label or a node in avoiding is hidden.

A position string ignores avoiding, and is never hidden.

In a polar or other curved coordinate space, a place is an error, and a label's default is "outset" (#1201).

Place.around() ​

OptionTypeDefaultDescription
directions"top-right" | "top-left" | "bottom-right" | "bottom-left" | "right" | "left" | "top" | "bottom"[]["top-right", "top-left", "bottom-right", "bottom-left", "right", "left", "top", "bottom"]The directions to try, in order.
side"outset" | "inset" | "outset" | "inset"[]"outset"Outside the outline ("outset") or inside it ("inset"), or a list tried in order at each direction: ["outset", "inset"] with directions ["top"] puts a bar's value above it, or inside its top when there is no room above.
offsetnumberPixels between the outline and the label. Default: the label's offset, or 3.

Place.along() ​

OptionTypeDefaultDescription
atnumber | "start" | "middle" | "end" | "x-min" | "x-max" | "y-min" | "y-max""middle"Where along the outline: a fraction of its length, 0 to 1 (the label is centered there); "start" or "end" (the label's start or end is flush with the path's); "middle"; or an edge of a box, "x-min", "x-max", "y-min" or "y-max", named by axis in the mark's own frame (the label stays within that edge, or is hidden).
side"on" | "above" | "below" | "left" | "right" | "inset" | "outset" | "on" | "above" | "below" | "left" | "right" | "inset" | "outset"[]"on"Which side of the outline: "on" straddles it. On an open path, "above" and "below" are the screen's (a stretch steeper than about 75 degrees has neither, so it gives no spot), and "left" and "right" are the path's own, of its direction of travel. On a closed outline, "inset" and "outset" are inside and outside. A list is tried in order at each spot.
orient"horizontal" | "sloped""horizontal""horizontal" keeps the label level. "sloped" turns it to the chord of the outline across the label's width, kept upright, and skips a spot where the outline bends away from the chord by more than about a third of the text's height, so it suits smooth lines.
offsetnumberPixels between the outline and the label. Default: the label's offset, or 3.

Place.start() ​

OptionTypeDefaultDescription
offsetnumberPixels between the outline and the label. Default: the label's offset, or 4.

Place.end() ​

OptionTypeDefaultDescription
offsetnumberPixels between the outline and the label. Default: the label's offset, or 4.

Place.interior() ​

OptionTypeDefaultDescription

See also ​