Skip to content

pack ​

Places its children so that their enclosing circles touch and do not overlap. This is circle packing. With a by, pack makes one child per group. Without a by, it makes one child per row. Two pack operators in a row give a nested packing.

js
gf.chart(seafood)
  .flow(gf.pack({ by: "lake" }), gf.pack())
  .mark(gf.circle({ r: 12, fill: "species" }))
  .render(root, { w: 420, h: 420 });

Signature ​

ts
pack({ by?, method? })
pack({ method? }, marks)

Combinator form ​

Given a list of marks, pack packs those marks instead of rows of data. It returns a mark, so a pack can hold another pack.

js
gf.pack({}, [
  gf.circle({ r: 60 }),
  gf.ellipse({ w: 90, h: 44 }),
  gf.pack({}, [
    gf.circle({ r: 26 }),
    gf.circle({ r: 18 }),
    gf.circle({ r: 14 }),
  ]),
]).render(root, { w: 420, h: 420 });

Parameters ​

Circle packing: place the flow's groups (or rows) so their enclosing circles touch without overlapping. Children keep their pixel size; the pack does not fit itself to the available space yet (#967).

OptionTypeDefaultDescription
bystring | FieldAccessorField to partition rows by (like spread/scatter); also accepts a field(...) accessor carrying domain ops (sort/reverse/bin/dropNulls). Without by, one child per row.
methodobject{"kind":"circles"}The packing strategy, made by a function call: circles() packs each child's enclosing circle with d3's front-chain algorithm.

Strategies ​

method holds the packing strategy. You make a strategy with a function call.

  • circles() packs each child's enclosing circle with d3's front-chain algorithm (packSiblings). It is the default, so pack() and pack({ method: circles() }) are the same. It takes no options yet.

Each child is packed by its enclosing circle, which depends on its shape.

  • A circle is its own enclosing circle.
  • An ellipse uses the circle of its larger radius.
  • A polygon uses the smallest circle through its vertices.
  • A rect or text uses the circle through the corners of its box.
  • A nested pack uses the smallest circle around its own children.

Limits ​

  • Children keep the pixel size they are laid out at. The pack does not scale itself to fit the space it is given, and it cannot yet size a child from data. So give each child a size in pixels, e.g., circle({ r: 12 }), not circle({ r: "count" }). See #967.
  • There is no padding between circles yet.