Complement (universe/container)
An Euler or Venn diagram normally shows only the named sets and their overlaps. Often, though, the sets are drawn from a larger population, and some items belong to none of them. That leftover, everything outside every set, is the complement, or the universe. eunoia can draw it as a bounding container: a rectangle around the diagram whose empty margin stands in for the items outside all sets.
Support is opt-in. Pass complement: N and eunoia fits a container,
exposes it on the returned layout, and surfaces the leftover area as its
own region.
Opting in
The complement option on euler() is the area of the region outside
every set, in the same units as the set sizes. With it set, the fitter
solves for a bounding rectangle in addition to the shapes:
import { euler } from "@jolars/eunoia";
const layout = euler({
sets: { A: 8, B: 6, "A&B": 2 },
complement: 25,
});
layout.container; // -> { x, y, width, height } (center + full extents) layout.container is present only when a complement was requested;
otherwise it is absent.
How the container is fitted
For an area-proportional Euler diagram the container is part of the fit, not an afterthought. The fitter jointly optimizes an axis-aligned rectangle alongside the shapes so that
container area − area of the union of the (clipped) shapes ≈
N.
Two things follow. First, the complement pins the diagram’s absolute scale: without it only ratios of areas are determined, but matching a concrete leftover area fixes the overall size. Second, any shape that would otherwise drift outside the frame is pulled back in, because area that spills beyond the container does not count toward the union.
Because the container is a single enclosing universe, a spec that fits as several disjoint clusters is rejected when a complement is set—there is no one rectangle that meaningfully encloses unrelated groups.
The complement region ("")
In output: "regions" mode the universe is returned as a region like any
other, except that its combination key is the empty string. Its
polygon is the container with the union of the shapes punched out as
holes, so it tiles exactly the shaded margin you see above.
const layout = euler({ sets, complement: 10, output: "regions" });
// The universe region, keyed by "".
const universe = layout.regions.find((r) => r.combination === "");
// Everything except the universe.
const named = layout.regions.filter((r) => r.combination !== ""); Rendering the container as a frame
The container is a center (x, y) plus a full width and height, so a
rectangle spans from (x − width / 2, y − height / 2) to (x + width / 2, y + height / 2). The bundled SVG renderer
(@jolars/eunoia/svg) draws it for you as a dashed frame, and can print
the complement count in the corner:
import { toSvg } from "@jolars/eunoia/svg";
const svg = toSvg(layout, {
complement: 10, // shown in the corner when showCounts is on
showCounts: true,
containerStroke: "#9ca3af", // dashed frame color
complementColor: "#6b7280", // complement-count text color
}); Venn diagrams
venn() accepts a complement too, but it behaves differently. A Venn
diagram is topological, not area-proportional: its canonical layout
is fixed, so the complement value is not fitted. Instead the container is
a purely visual frame, a fixed padding around the diagram’s bounding box,
and layout.container is therefore not proportional to the requested
complement; it just gives you somewhere to write the count.
import { venn } from "@jolars/eunoia";
const layout = venn({ n: 3, complement: 12 });
layout.container; // a visual frame, not an area-matched rectangle In Rust
In the core library the complement is opted into on the spec builder with .complement(area); negative values are rejected. When set, the fitted Layout carries the container rectangle. See the rustdoc for DiagramSpecBuilder and Layout.
use eunoia::DiagramSpecBuilder;
let spec = DiagramSpecBuilder::new()
.set("A", 8.0)
.set("B", 6.0)
.intersection(&["A", "B"], 2.0)
.complement(10.0)
.build()?; See also
- Shapes: the primitives the container is fitted around.
- Fitter pipeline: how a spec becomes fitted geometry, container included.
- Label placement: placing labels in and around the diagram.