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. Read the documentation at eunoia.bz.
- Five shape families: fit with circles, ellipses, squares, axis-aligned rectangles, or rotated rectangles; the engine is shape-agnostic until fit time.
- Robust fitting: initial initialization followed by a global/local optimization pipeline that mirrors and improves on eulerr.
- Venn diagrams too: canonical arrangements for up to three sets with circles, squares, or rectangles, four with rotated rectangles, and five with ellipses, 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.
cargo add eunoiaThen run the following example to fit an Euler diagram of three overlapping sets.
use eunoia::geometry::shapes::Ellipse;
use eunoia::{DiagramSpecBuilder, Fitter, InputType};
fn main() {
let spec = DiagramSpecBuilder::new()
.set("Adventure", 20.0)
.set("Comedy", 14.0)
.set("Drama", 18.0)
.intersection(&["Adventure", "Comedy"], 6.0)
.intersection(&["Adventure", "Drama"], 5.0)
.intersection(&["Comedy", "Drama"], 4.0)
.intersection(&["Adventure", "Comedy", "Drama"], 2.0)
.input_type(InputType::Exclusive)
.build()
.unwrap();
// Swap `Ellipse` for `Circle`, `Square`, `Rectangle`, or `RotatedRectangle`.
let layout = Fitter::<Ellipse>::new(&spec).seed(1).fit().unwrap();
println!(
"{} shapes, loss = {:.2e}",
layout.shapes().len(),
layout.loss()
);
}
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.
Eunoia powers a web app for interactive diagram fitting and exploration, located at https://eunoia.bz/app.
The pure-Rust core powers bindings in several languages, all backed by the same fitting engine:
| Language | Package | Install |
|---|---|---|
| R | eulerr (repo) |
install.packages("eulerr") |
| Python | eunoia (repo) |
pip install eunoia |
| Julia | Eunoia.jl (repo) |
]add Eunoia |
| JavaScript | @jolars/eunoia (this repo) |
npm install @jolars/eunoia |
A TypeScript package is published as
@jolars/eunoia. Here's a
minimal example of fitting an Euler diagram in Node or a bundler environment:
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" | "rotatedRectangle"
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+.
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:
<script type="module">
import { euler, init } from "https://esm.sh/@jolars/eunoia/web";
await init(); // instantiate the embedded WebAssembly module (once)
const layout = euler({ sets: { A: 5, B: 2, "A&B": 1 } });
console.log(layout.circles);
</script>eunoia = import("https://esm.sh/@jolars/eunoia/web");
await eunoia.init();
layout = eunoia.euler({ sets: { A: 5, B: 2, "A&B": 1 } });@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/.
If you use Eunoia in your research, please cite the paper:
Larsson, J., & Lee, N. M. (2026). Eunoia: Area-Proportional Euler and Venn Diagrams in Rust, Julia, Python, R, and JavaScript (arXiv:2611.02198). arXiv. https://doi.org/10.48550/arXiv.2611.02198
@misc{larsson2026f,
title = {Eunoia: {{Area}}-Proportional {{Euler}} and {{Venn}} Diagrams in {{Rust}}, {{Julia}}, {{Python}}, {{R}}, and {{JavaScript}}},
shorttitle = {Eunoia},
author = {Larsson, Johan and Lee, Nicole M.},
year = {2026},
month = nov,
number = {arXiv:2611.02198},
eprint = {2611.02198},
primaryclass = {stat.CO},
publisher = {arXiv},
doi = {10.48550/arXiv.2611.02198},
archiveprefix = {arXiv}
}BibLaTeX
@online{larsson2026f,
title = {Eunoia: {{Area}}-Proportional {{Euler}} and {{Venn}} Diagrams in {{Rust}}, {{Julia}}, {{Python}}, {{R}}, and {{JavaScript}}},
shorttitle = {Eunoia},
author = {Larsson, Johan and Lee, Nicole M.},
date = {2026-11-01},
eprint = {2611.02198},
eprinttype = {arXiv},
eprintclass = {stat.CO},
doi = {10.48550/arXiv.2611.02198},
pubstate = {prepublished}
}For reproducibility, also cite the software release you used. Select that
release in the Zenodo archive and
export its citation. The concept DOI 10.5281/zenodo.20665805 identifies Eunoia
across all releases.
CITATION.cff contains the software metadata and preferred paper citation. The Eunoia citation page renders the paper in APA, BibTeX, BibLaTeX, and other formats.
Eunoia is distributed under the terms of either the MIT license or the Apache License 2.0, at your option.