Eunoia
Eunoia is a Rust library for area-proportional Euler and Venn diagrams. Give it a set of sizes and intersections and it fits a layout of shapes whose areas match your data as closely as possible. It is a ground-up rewrite of the R package eulerr: faster, more flexible, and built to power bindings across many languages.
Highlights
- Four shape families: fit with circles, ellipses, squares, or rectangles; the engine is shape-agnostic until fit time.
- Robust fitting: MDS initialization followed by a global/local optimization pipeline (LM, CMA-ES, trust-region) that mirrors and improves on eulerr.
- Venn diagrams too: canonical n-set Venn arrangements (circles for n≤3, ellipses for n=4-5) independent of the fitter.
- Renderable output: region polygon extraction, clipping, and automatic label placement, ready to draw as SVG.
- Many targets: pure Rust core that ships to JavaScript via WebAssembly and to other languages through a small C ABI.
Quick start (Rust)
use Ellipse;
use ;
layout.shapes() returns the fitted geometry; the plotting module turns a
Layout into region polygons and label anchors for rendering. See the
rustdoc for the full API.
The Eunoia ecosystem
The pure-Rust core powers bindings in several languages, all backed by the same fitting engine:
| Language | Package | Install |
|---|---|---|
| Rust | eunoia |
cargo add eunoia |
| R | eulerr (repo) |
install.packages("eulerr") |
| Python | eunoia (repo) |
pip install eunoia |
| Julia | Eunoia.jl |
(see the package README) |
| JavaScript | @jolars/eunoia |
npm install @jolars/eunoia |
| Web app | eunoia.bz | build diagrams in the browser |
JavaScript / TypeScript
WebAssembly bindings are published as
@jolars/eunoia:
import { euler, venn } from "@jolars/eunoia";
// Fit an Euler diagram from set sizes
const layout = euler({
sets: { A: 5, B: 2, "A&B": 1 },
shape: "circle", // "circle" | "ellipse" | "square" | "rectangle"
output: "shapes", // "shapes" | "polygons" | "regions"
inputType: "exclusive", // "exclusive" | "inclusive"
seed: 42,
});
if (layout.mode === "shapes" && layout.shape === "circle") {
for (const c of layout.circles) {
console.log(c.label, c.x, c.y, c.radius);
}
}
// Or build a canonical n-set Venn diagram
const v = venn({ n: 3, output: "regions" });
A renderer-agnostic SVG serializer is available at @jolars/eunoia/svg. The
default entry is built with wasm-pack --target bundler, so it works with any
modern bundler (Vite, Webpack, Rollup, esbuild) and Node 20+.
Browser / Observable (no bundler)
The default entry imports the .wasm module directly, which only a bundler can
resolve. For a plain HTML page, an Observable
notebook, or any environment without a build step, use the @jolars/eunoia/web
entry instead: a single self-contained ESM file with the WebAssembly module
inlined. Call init() once before fitting:
In Observable:
eunoia = import
await eunoia.
layout = eunoia.
@jolars/eunoia/svg is pure JavaScript (no WebAssembly), so it already works
directly from a CDN with no init().
Full runnable examples (a Quarto document and a standalone HTML page) are in
examples/.
Documentation
- Narrative docs: eunoia.bz/docs/
- Rust API reference: docs.rs/eunoia
License
Eunoia is distributed under the terms of either the MIT license or the Apache License 2.0, at your option.