Eunoia

API Reference

Julia · julia · 1.0.1

Eunoia.BoundingBox

BoundingBox
BoundingBox(x::Real, y::Real, width::Real, height::Real)

An axis-aligned rectangle used as a label or glyph keep-out box.

BoundingBox(x::Real, y::Real, width::Real, height::Real)

Eunoia.Circle

Circle <: AbstractShape

A fitted circle for one input set.

Eunoia.Container

Container

The fitted universe box drawn around a diagram fit with a complement. The container's area minus the union of the shapes matches the requested complement area.

Eunoia.Ellipse

Ellipse <: AbstractShape

A fitted ellipse for one input set.

Eunoia.EulerFit

EulerFit{S} <: AbstractEulerFit{S}
EulerFit{S}

Result of fitting an area-proportional Euler diagram with shapes of type S.

Fields:

  • shapes: fitted shapes, one per input set, in input order.

  • original_values: the requested exclusive area per region (keyed by combination string, e.g. "A&B").

  • fitted_values: the fitted exclusive area per region.

  • residuals: original_values − fitted_values per region.

  • region_error: per-region error (always in exclusive form).

  • diag_error: eulerAPE-style worst-case region error.

  • stress: venneuler-style stress metric.

  • loss: final value of the optimizer's objective.

  • iterations: optimizer iteration count.

  • container: the fitted universe box when fit with a complement, else nothing.

The plot_data field holds the native renderable geometry (region polygons and label anchors); it backs plotting and is not part of the stable public API.

Eunoia.GlyphBoxPlacements

GlyphBoxPlacements
GlyphBoxPlacements

Result of place_glyph_boxes. scale is the diagram-wide factor to apply to the reference text size. Each vector in boxes is a prefix aligned with the corresponding input sizes; unplaced reports the omitted suffix.

Eunoia.GlyphPlacements

GlyphPlacements
GlyphPlacements

Result of place_glyphs. radius is shared by every glyph, positions contains glyph centers by region, and unplaced reports any shortfall when a fixed radius could not accommodate every requested glyph.

Eunoia.LabelPlacement

LabelPlacement
LabelPlacement

A resolved label position returned by place_labels or place_set_labels. anchor is the center of the label box. kind is one of :interior, :exterior_raycast, :exterior_force_directed, :exterior_elbow, :exterior_matched, or :exterior_set (:unknown for a future native variant). For exterior placements that need a leader line, tether is the inside-region point the leader starts from, leader_end is where it meets the label box, and leader_waypoints are the intermediate polyline vertices. Set-label placements carry no leader geometry.

Eunoia.Point

Point

A 2D point.

Eunoia.Rectangle

Rectangle <: AbstractShape

A fitted axis-aligned rectangle for one input set.

Eunoia.RotatedRectangle

RotatedRectangle <: AbstractShape

A fitted rotated rectangle for one input set. rotation is the angle (in radians) of the rectangle about its center.

Eunoia.Square

Square <: AbstractShape

A fitted axis-aligned square for one input set.

Eunoia.VennFit

VennFit{S} <: AbstractEulerFit{S}
VennFit{S}

Result of laying out a (non-proportional) Venn diagram. Shares EulerFit's structure, but the layout is topological: every set intersection is drawn regardless of area, so the proportional-error metrics are not meaningful (left at zero) and original_values is empty. fitted_values holds the geometric area of each region.

Eunoia.euler

euler(
    values::AbstractDict;
    shape::AbstractString = "circle",
    input_type::AbstractString = "exclusive",
    complement::Union{Nothing, Real} = nothing,
    seed::Union{Nothing, Integer} = nothing,
    max_sets::Union{Nothing, Integer} = nothing,
    loss::Union{Nothing, AbstractString} = nothing,
    loss_eps::Union{Nothing, Real} = nothing,
    n_restarts::Union{Nothing, Integer} = nothing,
    optimizer::Union{Nothing, AbstractString} = nothing,
    mds_solver::Union{Nothing, AbstractString} = nothing,
    initial_sampler::Union{Nothing, AbstractString} = nothing,
    cmaes_fallback_threshold::Union{Nothing, Real} = nothing,
    max_iterations::Union{Nothing, Integer} = nothing,
    tolerance::Union{Nothing, Real} = nothing,
    xtol::Union{Nothing, Real} = nothing,
    ftol::Union{Nothing, Real} = nothing,
    gtol::Union{Nothing, Real} = nothing,
    jobs::Union{Nothing, Integer} = nothing,
    n_vertices::Union{Nothing, Integer} = nothing,
    label_precision::Union{Nothing, Real} = nothing,
    sliver_threshold::Union{Nothing, Real} = nothing
)
euler(values; shape="circle", input_type="exclusive",
      complement=nothing, seed=nothing, loss=nothing, …)

Fit an area-proportional Euler diagram. values is one of:

  • a mapping from combination strings to areas, where a key is a single set ("A") or an &-joined intersection ("A&B"):

    euler(Dict("A" => 5, "B" => 3, "A&B" => 1.5))
  • a mapping from set names to membership collections (vector/set/tuple); each element is counted into the canonical region of the sets it belongs to, yielding exclusive per-region counts (so input_type must stay "exclusive"):

    euler(Dict("A" => ["x", "y"], "B" => ["y", "z"]))

Keyword arguments:

  • shape: "circle" (default), "ellipse", "square", "rectangle", or "rotated_rectangle".

  • input_type: "exclusive" (default; per-region areas) or "inclusive" (set sizes that include overlaps; the core converts internally and the reported fitted_values/residuals are reconstructed in the inclusive scale).

  • complement: target "universe" area outside every set (opts into container fitting); nothing to disable.

  • seed: RNG seed for reproducible restarts; nothing for default.

  • max_sets: raise the set-count ceiling above the core default (32); clamped core-side to the hard cap (63). nothing keeps the default. Note that a fully-overlapping n-set diagram has 2^n - 1 regions, so large dense inputs remain intractable regardless.

Fitting knobs (all optional; nothing keeps the core default). Invalid string tokens are rejected by the native core and surface as an error:

  • loss: objective function. One of "sum_squared" (default), "sum_absolute", "sum_absolute_region_error", "sum_squared_region_error", "max_absolute", "max_squared", "root_mean_squared", "stress", "diag_error", "log_sum_absolute", or a C¹-smooth surrogate "smooth_sum_absolute", "smooth_sum_absolute_region_error", "smooth_max_absolute", "smooth_max_squared", "smooth_diag_error", "smooth_log_sum_absolute".

  • loss_eps: smoothing parameter for the six smooth_* losses (default 1e-3); ignored by the non-smooth losses.

  • n_restarts: number of randomly seeded restarts (default 10).

  • optimizer: final-layout solver. One of "levenberg_marquardt", "lbfgs", "nelder_mead", "mads", "trf", "cmaes", "cmaes_lm", or "cmaes_trf" (default).

  • mds_solver: initial-layout (MDS) solver, "levenberg_marquardt" (default) or "lbfgs".

  • initial_sampler: restart-position sampler, "uniform" (default) or "latin_hypercube".

  • cmaes_fallback_threshold: loss above which the cmaes_* optimizers fire their global escape stage (default 1e-3).

  • max_iterations: per-optimizer iteration cap (default 200).

  • tolerance: unified convergence tolerance (default 1e-3).

  • xtol, ftol, gtol: fine-grained Levenberg-Marquardt tolerances overriding the defaults derived from tolerance.

  • jobs: thread count for the restart loop; a pure wall-time knob, the chosen layout is identical regardless of value.

Plot-tuning knobs (all optional; nothing keeps the core default). These shape the plot_data geometry used for rendering, not the fit:

  • n_vertices: vertices per polygonized shape/region outline (default 200). Lower values give coarser outlines; higher values, smoother ones.

  • label_precision: pole-of-inaccessibility search precision for label anchors, in coordinate units (default 0.01).

  • sliver_threshold: minimum region-piece area, as a fraction of the largest piece, below which a piece is rejected as a polygonization artifact (default 1e-3); 0.0 disables the filter.

Returns an EulerFit carrying the fitted shapes, the original_values/fitted_values/residuals per region, the per-region region_error, the scalar fit metrics, and—if a complement was given—a container.

Eunoia.eunoiaplot

eunoiaplot(fit; colors, fills, edges, labels, quantities, legend, complement,
           fontsize=14, label_placement=true, set_label_placement=false,
           glyphs=nothing, members=nothing, figure=(;), axis=(;))
eunoiaplot(gridpos, fit; axis=(;), kwargs...)

Render a fitted EulerFit/VennFit as a publication-ready Makie figure (equal aspect, no axis decorations), returning a Makie.FigureAxisPlot.

The second form draws into a layout cell of an existing figure — e.g. eunoiaplot(f[1, 2], fit) — mirroring Makie's plot(fig[i, j], data). It creates a diagram-configured axis (equal aspect, hidden decorations) in that cell and returns a Makie.AxisPlot. Use it to assemble multi-panel figures without configuring each axis by hand. It takes the same styling keywords (pass an axis title and the like through axis = (; title = "…")) but does not add a legend; add a Legend yourself if you want one.

This requires a Makie backend to be loaded — the implementation lives in a package extension that activates on using CairoMakie (or GLMakie/WGLMakie). The bare Makie plot(fit)/plot!(ax, fit) recipe forms also work once a backend is loaded.

Styling keywords mirror the eunoia-py plot() API:

  • colors: per-set colors — a vector (shape order) or a Dict(name => color); omitted uses a built-in categorical palette. Region fills blend the member colors perceptually (OKLab).

  • fills: Dict(combo => style) per-region fill overrides.

  • edges: set-outline style — a uniform style, a per-set Dict, or a vector.

  • labels: false/true/nothing, a per-set Dict, or a uniform style.

  • quantities: false/true, "original"/"fitted", "counts"/"percent", or a Dict.

  • legend: false/true or a Dict of Legend keywords.

  • complement: container-box style Dict (drawn only when the fit has one).

  • fontsize: base label font size in points (quantities render smaller).

Collision-aware labels:

  • label_placement: true (default) places labels collision-aware via place_labels: each region's label is measured (Makie text metrics), positioned inside its region when it fits, else pushed outside with a leader line. Set names and quantities are combined into one box per region, so a set name and its region quantity never overlap. The default uses the "raycast" exterior solver with straight leaders; pass a NamedTuple/Dict of place_labels strategy knobs (placement, leader, tether, margin, iterations, precision, leader_gap, min_gap) to change it, e.g. label_placement = (; placement = "force_directed") or label_placement = (; leader = "elbow", tether = "boundary"). Pass label_placement=false to instead draw labels at their raw anchors.

  • leader_style: collection of lines! keywords styling the leader lines.

  • set_label_placement: false (default) keeps set names inside their regions; true places them just outside their own shape, and a NamedTuple/Dict additionally forwards margin, angular_steps, obstacles, and precision to place_set_labels.

  • glyphs: an explicit region-to-integer-count mapping. Circular glyphs are packed with place_glyphs; use glyph_options for placement knobs and glyph_style for Makie scatter! attributes.

  • members: an explicit region-to-ordered-names mapping. Names are measured, packed with place_glyph_boxes, and scaled uniformly; use member_options and member_style to customize them. glyphs and members are mutually exclusive.

Collision-aware placement needs the axis (to convert pixel text metrics to layout units), so it is available through eunoiaplot/eunoiaplot! only; the bare plot(fit) recipe form ignores label_placement.

eunoiaplot(::AbstractEulerFit, args...; kwargs...)
eunoiaplot(
    fit::AbstractEulerFit;
    figure = (;),
    axis = (;),
    legend = false,
    kwargs...
)
eunoiaplot(
    gp::Union{Makie.GridPosition, Makie.GridSubposition},
    fit::AbstractEulerFit;
    axis = (;),
    kwargs...
)

Eunoia.eunoiaplot!

eunoiaplot!(ax, fit; label_placement=true, set_label_placement=false,
            glyphs=nothing, members=nothing, leader_style=(;), kwargs...)

Draw a fitted diagram into an existing Makie axis ax. It accepts the same styling and placement keywords as eunoiaplot, but does not alter the axis aspect or decorations.

eunoiaplot!(::Any, ::AbstractEulerFit, args...; kwargs...)
eunoiaplot!(
    ax,
    fit::AbstractEulerFit;
    label_placement = true,
    set_label_placement = false,
    glyphs = nothing,
    glyph_options = (;),
    glyph_style = (;),
    members = nothing,
    member_options = (;),
    member_style = (;),
    leader_style = (;),
    kwargs...
)
eunoiaplot!(ax, fit; label_placement=true, set_label_placement=false,
            glyphs=nothing, members=nothing, leader_style=(;), kwargs...)

Draw a fit into an existing axis. By default (label_placement=true) labels are placed collision-aware via raycast (see Eunoia.eunoiaplot for the value forms); the resolved label boxes and any exterior leader polylines are drawn into ax. Pass label_placement=false to instead leave labels at their raw anchors. Set set_label_placement=true to move set names outside their shapes. Explicit glyphs and members mappings enable the two mutually exclusive glyph modes. leader_style is a collection of lines! keywords for leader lines.

Eunoia.label_boxes

label_boxes(placements::AbstractDict, sizes::AbstractDict; padding::Real = 0)
label_boxes(placements, sizes; padding=0) -> Vector{BoundingBox}

Convert resolved label placements and their measured (width, height) sizes into padded, axis-aligned keep-out boxes. The result can be passed as obstacles to place_set_labels, place_glyphs, or place_glyph_boxes.

Eunoia.place_glyph_boxes

place_glyph_boxes(
    fit::AbstractEulerFit,
    sizes::AbstractDict;
    arrangement::Union{Nothing, AbstractString} = nothing,
    scale::Union{Nothing, Real} = nothing,
    min_scale::Union{Nothing, Real} = nothing,
    gap::Union{Nothing, Real} = nothing,
    seed::Union{Nothing, Integer} = nothing,
    precision::Union{Nothing, Real} = nothing,
    max_attempts::Union{Nothing, Integer} = nothing,
    obstacles::Union{Nothing, AbstractVector} = nothing
)
place_glyph_boxes(fit, sizes; arrangement=nothing, scale=nothing,
                  min_scale=nothing, gap=nothing, seed=nothing,
                  precision=nothing, max_attempts=nothing,
                  obstacles=nothing) -> GlyphBoxPlacements

Pack ordered, caller-measured member-label boxes inside fitted regions. sizes maps each canonical region combination to a vector of (width, height) pairs. The returned boxes are a prefix aligned with each input vector; render the corresponding text at the reference font size multiplied by scale.

Eunoia.place_glyphs

place_glyphs(
    fit::AbstractEulerFit,
    counts::AbstractDict;
    arrangement::Union{Nothing, AbstractString} = nothing,
    radius::Union{Nothing, Real} = nothing,
    gap::Union{Nothing, Real} = nothing,
    seed::Union{Nothing, Integer} = nothing,
    precision::Union{Nothing, Real} = nothing,
    max_attempts::Union{Nothing, Integer} = nothing,
    obstacles::Union{Nothing, AbstractVector} = nothing
)
place_glyphs(fit, counts; arrangement=nothing, radius=nothing, gap=nothing,
             seed=nothing, precision=nothing, max_attempts=nothing,
             obstacles=nothing) -> GlyphPlacements

Pack equally sized circular glyphs inside fitted regions. counts maps canonical region combinations to nonnegative integer counts. Omit radius to choose the largest shared radius that accommodates every requested glyph.

Eunoia.place_labels

place_labels(
    fit::AbstractEulerFit,
    sizes::AbstractDict;
    placement::Union{Nothing, AbstractString} = nothing,
    leader::Union{Nothing, AbstractString} = nothing,
    margin::Union{Nothing, Real} = nothing,
    iterations::Union{Nothing, Integer} = nothing,
    precision::Union{Nothing, Real} = nothing,
    tether::Union{Nothing, AbstractString} = nothing,
    leader_gap::Union{Nothing, Real} = nothing,
    min_gap::Union{Nothing, Real} = nothing
)
place_labels(fit, sizes; placement=nothing, leader=nothing, margin=nothing,
             iterations=nothing, precision=nothing, tether=nothing,
             leader_gap=nothing, min_gap=nothing)

Resolve collision-aware label positions for the regions of a fitted EulerFit/VennFit, given the rendered label box sizes.

The core can't place labels without their on-screen sizes (font metrics it never sees at fit time), so this is a separate call from euler: measure each label, then ask for placements. sizes is a mapping from region/combination strings ("A", "A&B", …) to a (width, height) tuple in the same coordinate units as the fitted shapes. Only regions present in both sizes and the fit's geometry get a placement; degenerate inputs are silently skipped.

Each placement tries to sit inside its region; one that can't fit is pushed outside with a leader line. Returns a Dict{String,LabelPlacement} (see LabelPlacement).

Strategy knobs (all optional; nothing keeps the core default). Invalid string tokens are rejected by the native core and surface as an error:

  • leader: leader edge type, "straight" (default) or "elbow" (d3-pie style orthogonal leaders with column-based placement).

  • placement: exterior solver for straight leaders, "raycast" (default), "force_directed" (spring/repulsion relaxation for crowded diagrams), or "matched" (noncrossing boundary labels); ignored for "elbow".

  • margin: gap between the diagram and exterior labels (both edge types); the per-region proportional default applies when omitted.

  • iterations: iteration cap for "force_directed" (default 200); ignored otherwise.

  • precision: pole-of-inaccessibility search precision (default 0.01).

  • tether: where an exterior leader attaches to its region, "poi" (default, the pole of inaccessibility) or "boundary" (the region's outer ring).

  • leader_gap: visible gap between the leader tip and the label box (default 0.0).

  • min_gap: minimum vertical spacing between stacked "elbow" labels; ignored otherwise.

fit = euler(Dict("A" => 5, "B" => 3, "A&B" => 1.5))
placements = place_labels(fit, Dict("A" => (0.6, 0.3), "B" => (0.6, 0.3));
                          placement="force_directed")

Eunoia.place_set_labels

place_set_labels(
    fit::AbstractEulerFit,
    sizes::AbstractDict;
    margin::Union{Nothing, Real} = nothing,
    angular_steps::Union{Nothing, Integer} = nothing,
    obstacles::Union{Nothing, AbstractVector} = nothing,
    precision::Union{Nothing, Real} = nothing
)
place_set_labels(fit, sizes; margin=nothing, angular_steps=nothing,
                 obstacles=nothing, precision=nothing)

Place one measured label per set just outside that set's shape. Labels hug the shape boundary and need no leader line. sizes maps set names to (width, height) pairs in diagram coordinates. Returns a Dict{String,LabelPlacement} keyed by set name.

Eunoia.venn

venn(
    sets;
    shape::AbstractString = "circle",
    complement::Union{Nothing, Real} = nothing
)
venn(sets; shape="circle", complement=nothing)

Build a canonical Venn diagram. sets selects the set names, as one of:

  • an Integer n — n sets with default names "A", "B", …;

  • a vector of set names, e.g. ["cat", "dog", "fish"];

  • a mapping whose keys are set/combination labels (the distinct base set names are extracted; values are ignored, since a Venn layout is non-proportional).

The number of names selects the arrangement; shape is "circle" (n ≤ 3), "ellipse" (n ≤ 5), "square", "rectangle" (n ≤ 3), or "rotated_rectangle" (n ≤ 4).

Pass complement to reserve that area outside every set; the fit then carries a container box (the "universe" frame) drawn behind the diagram, just as for euler.

venn(["A", "B", "C"]; shape="ellipse")
venn(3)
venn(4; shape="rotated_rectangle", complement=2)

Returns a VennFit: the same structure as EulerFit, but the layout is topological, so fitted_values holds each region's geometric area and original_values is empty.

Eunoia.version

version()
version() -> String

Return the version of the underlying eunoia-capi native library.