Julia · 1.0.1

<a id="a-gallery-of-euler-and-venn-diagrams"></a>

<a id="A-gallery-of-Euler-and-Venn-diagrams"></a>

# A gallery of Euler and Venn diagrams

This page is a gallery of Euler and Venn diagrams and a showcase of the customization options available through [`eunoiaplot`](<reference/64c23a11690b420c37333e95ed51ddc80a26b8edd06ecb5463752a6e8f752650>). It is the Julia counterpart to the [eulerr gallery](<https://jolars.github.io/eulerr/articles/gallery.html>) and the [eunoia-py gallery](<https://jolars.github.io/eunoia-py/gallery.html>). 

Rendering lives in a [Makie](<https://docs.makie.org>) extension that loads once a backend is imported. Here we use [CairoMakie](<https://docs.makie.org/stable/explanations/backends/cairomakie>), a software backend that needs no display. 

```julia
using Eunoia, CairoMakie
CairoMakie.activate!(type = "png") # raster output for the gallery
```

The styling keywords (`colors`, `fills`, `edges`, `labels`, `quantities`, `legend`, `complement`) mirror the Python API, but their *values* are [Makie](<https://docs.makie.org>) attributes. A matplotlib style dict like `{"linestyle": "--"}` becomes `Dict(:linestyle => :dash)`, a fill's `"facecolor"` becomes `:color`, and so on. A *uniform* style is a `Dict` with `Symbol` keys; a per-set or per-region map is a `Dict` keyed by name whose values are style collections (a `Dict` or a `(; key = value)` named tuple). 

<a id="euler-diagrams"></a>

<a id="Euler-Diagrams"></a>

## Euler Diagrams

<a id="uniform-intersections"></a>

<a id="Uniform-Intersections"></a>

### Uniform Intersections

Here we use squares instead of the default circles. 

```julia
fit = euler(
    Dict(
        "A" => 10,
        "B" => 10,
        "C" => 10,
        "A&B" => 4,
        "A&C" => 4,
        "B&C" => 4,
        "A&B&C" => 2,
    );
    shape = "square",
)
eunoiaplot(fit)
```

![](<../../assets/bc2faf4b04adeb6d5a9bf1c0345269f433e0446ea5677bb412cfa15c4dc03912.png>)

<a id="disjoint-sets"></a>

<a id="Disjoint-Sets"></a>

### Disjoint Sets

Rename the sets simply by choosing the dictionary keys. A flat `edges` style is applied to every outline. 

```julia
fit = euler(Dict("Tom" => 1, "Greg" => 1, "Alberta" => 1))
eunoiaplot(fit; edges = Dict(:linestyle => :dash))
```

![](<../../assets/63258d704cfc7f3462446a784fb76f3baa76b2445987911cc8c0377f080b86c6.png>)

To style each outline independently, pass `edges` as a `Dict` keyed by set name (each value a collection of `lines!` keywords) or as a vector of such collections, one per set in shape order — mirroring how `colors` accepts a per-set `Dict`. 

```julia
fit = euler(Dict("Tom" => 1, "Greg" => 1, "Alberta" => 1))
eunoiaplot(
    fit;
    edges = Dict(
        "Tom" => (; linestyle = :dash, linewidth = 2),
        "Greg" => (; linestyle = :dot),
    ),
)
```

![](<../../assets/51da367f851cfd32462a1affc20c8530b01fcc50b66a911af60d9e37db77effe.png>)

<a id="a-set-contained-in-the-intersection-of-two-sets"></a>

<a id="A-Set-Contained-in-the-Intersection-of-Two-Sets"></a>

### A Set Contained in the Intersection of Two Sets

```julia
fit = euler(
    Dict(
        "A" => 15,
        "B" => 15,
        "C" => 0,
        "A&B" => 3,
        "A&C" => 0,
        "B&C" => 0,
        "A&B&C" => 3,
    ),
)

eunoiaplot(
    fit;
    colors = ["black", "cyan", "orange"],
    edges = Dict(:color => :white, :linewidth => 2),
)
```

![](<../../assets/8dc8aeececcf800c8ea302e051eb4febb005fc8e74743bad865ddd8794388ccd.png>)

<a id="two-sets-intersecting-inside-a-third"></a>

<a id="Two-Sets-Intersecting-Inside-a-Third"></a>

### Two Sets Intersecting Inside a Third

Here we override individual region fills with per-region `fills` styles. 

```julia
fit = euler(
    Dict(
        "A" => 15,
        "B" => 0,
        "C" => 0,
        "A&B" => 3,
        "A&C" => 3,
        "B&C" => 0,
        "A&B&C" => 2,
    ),
)

eunoiaplot(
    fit;
    fills = Dict(
        "A&B&C" => (; color = :orange),
        "A&B" => (; color = :lightblue),
        "A&C" => (; color = :lightsalmon),
    ),
)
```

![](<../../assets/f91cf1b7f21fed74c8b43ed20783dde2082adcab750fcc2c8fe0177100248190.png>)

<a id="difficult-set-for-circles"></a>

<a id="Difficult-Set-(For-Circles!)"></a>

### Difficult Set (For Circles!)

This relationship cannot be drawn exactly with circles but works well with ellipses. 

```julia
fit = euler(
    Dict("A" => 7, "B" => 6, "C" => 0, "A&B" => 0, "A&C" => 1, "B&C" => 1, "A&B&C" => 2);
    shape = "ellipse",
)
eunoiaplot(fit; quantities = true)
```

![](<../../assets/58dd5b17dfc2987068b1214c49df1d04a2145df27b2d16466cffc5c8fd80e609.png>)

<a id="russian-doll"></a>

<a id="Russian-Doll"></a>

### Russian Doll

Sets intersecting inside other sets. 

```julia
fit = euler(
    Dict(
        "A" => 15,
        "B" => 0,
        "C" => 0,
        "A&B" => 10,
        "A&C" => 0,
        "B&C" => 0,
        "A&B&C" => 5,
    ),
)

eunoiaplot(fit)
```

![](<../../assets/49a874368841c9552c83fd937777c5afb9ebae7ce43d9e4056e589ba1ebfca52.png>)

<a id="wilkinson-set-relationship"></a>

<a id="Wilkinson-Set-Relationship"></a>

### Wilkinson Set Relationship

This set relationship is taken from Wilkinson et al. It works best with ellipses. We show the *fitted* values rather than the requested ones. 

```julia
fit = euler(
    Dict(
        "A" => 4,
        "B" => 6,
        "C" => 3,
        "D" => 2,
        "E" => 7,
        "F" => 3,
        "A&B" => 2,
        "A&F" => 2,
        "B&C" => 2,
        "B&D" => 1,
        "B&F" => 2,
        "C&D" => 1,
        "D&E" => 1,
        "E&F" => 1,
        "A&B&F" => 1,
        "B&C&D" => 1,
    );
    shape = "ellipse",
)

eunoiaplot(fit; quantities = "fitted", edges = Dict(:linestyle => :dot))
```

![](<../../assets/2654911a7acae0c71f7126371d502b4335cdece884faa385fd84732404bb556c.png>)

<a id="gene-set"></a>

<a id="Gene-Set"></a>

### Gene Set

```julia
fit = euler(
    Dict(
        "SE" => 13,
        "Treat" => 28,
        "Anti-CCP" => 101,
        "DAS28" => 91,
        "SE&Treat" => 1,
        "SE&DAS28" => 14,
        "Treat&Anti-CCP" => 6,
        "SE&Anti-CCP&DAS28" => 1,
    ),
)
eunoiaplot(fit; quantities = true)
```

![](<../../assets/baf4f81909d705db14bf354d781e76ee7f8651efc2c2d0e916681c8554aa7941.png>)

<a id="three-sets-intersecting-inside-a-fourth"></a>

<a id="Three-sets-intersecting-inside-a-fourth"></a>

### Three sets intersecting inside a fourth

```julia
fit = euler(
    Dict(
        "A" => 30,
        "A&B" => 3,
        "A&C" => 3,
        "A&D" => 3,
        "A&B&C" => 0.4,
        "A&B&D" => 0.4,
        "A&C&D" => 0.4,
        "A&B&C&D" => 1,
    ),
)

eunoiaplot(fit)
```

![](<../../assets/1d2a8837f9db4c1a4e39a17aba94297d5f438fdcd57b950c7a1960a386ea0b0f.png>)

<a id="eulerape-combination"></a>

<a id="eulerAPE-Combination"></a>

### eulerAPE Combination

A combination taken from the eulerAPE article, fit with ellipses. 

```julia
fit = euler(
    Dict(
        "a" => 3491,
        "b" => 3409,
        "c" => 3503,
        "a&b" => 120,
        "a&c" => 114,
        "b&c" => 132,
        "a&b&c" => 126,
    );
    shape = "ellipse",
)

eunoiaplot(fit)
```

![](<../../assets/0f9680306e66ab057cf853a0e33b2e1073db6f3211c7b8fd2c9ffa36210ce347.png>)

<a id="four-uniform-interactions"></a>

<a id="Four-Uniform-Interactions"></a>

### Four Uniform Interactions

This time we fit the diagram using rectangles. 

```julia
fit = euler(
    Dict(
        "Frodo" => 10,
        "Sam" => 10,
        "Merry" => 10,
        "Pippin" => 10,
        "Frodo&Sam" => 3,
        "Frodo&Merry" => 3,
        "Frodo&Pippin" => 0,
        "Sam&Merry" => 0,
        "Sam&Pippin" => 3,
        "Merry&Pippin" => 3,
        "Frodo&Sam&Merry" => 1,
        "Frodo&Sam&Pippin" => 1,
        "Frodo&Merry&Pippin" => 1,
        "Sam&Merry&Pippin" => 1,
        "Frodo&Sam&Merry&Pippin" => 1,
    );
    shape = "rectangle",
)

eunoiaplot(fit)
```

![](<../../assets/9272d9973a0828ede77b369842043a652b4ecd4c8cace2e1f657fe071fe9bcef.png>)

<a id="rotated-rectangles"></a>

<a id="Rotated-Rectangles"></a>

### Rotated Rectangles

Rectangles can also be fit with a free rotation angle (`shape = "rotated_rectangle"`), which gives the optimizer an extra degree of freedom and suits the diagonal four-set arrangement well. 

```julia
fit = euler(
    Dict(
        "Frodo" => 10,
        "Sam" => 10,
        "Merry" => 10,
        "Pippin" => 10,
        "Frodo&Sam" => 3,
        "Frodo&Merry" => 3,
        "Sam&Pippin" => 3,
        "Merry&Pippin" => 3,
        "Frodo&Sam&Merry" => 1,
        "Frodo&Sam&Pippin" => 1,
        "Frodo&Merry&Pippin" => 1,
        "Sam&Merry&Pippin" => 1,
        "Frodo&Sam&Merry&Pippin" => 1,
    );
    shape = "rotated_rectangle",
)

eunoiaplot(fit)
```

![](<../../assets/d5f7c2b850dc41c07685922e7ed2e83ed17d5f95d644650410c5ebac1a1593fb.png>)

<a id="two-circles-intersecting-completely"></a>

<a id="Two-Circles-Intersecting-Completely"></a>

### Two Circles Intersecting Completely

```julia
fit = euler(Dict("A" => 0, "B" => 0, "A&B" => 10))
eunoiaplot(fit)
```

![](<../../assets/888501da4db39e857085dc513b24fe0f659f2c63eedc53ba915364e9abd44c66.png>)

<a id="styling-and-the-complement"></a>

<a id="Styling-and-the-Complement"></a>

## Styling and the Complement

<a id="a-universe-complement-box"></a>

<a id="A-Universe-(Complement)-Box"></a>

### A Universe (Complement) Box

Pass `complement` to [`euler`](<reference/724ed6727eeae60915c72bfade1aba4de6ed59849fa7c8c0907cf91088d062d1>) to reserve area outside every set; it comes back as a container that [`eunoiaplot`](<reference/64c23a11690b420c37333e95ed51ddc80a26b8edd06ecb5463752a6e8f752650>) draws behind everything. The `complement` plot keyword styles that box. 

```julia
fit = euler(Dict("A" => 10, "B" => 8, "A&B" => 4); complement = 20)
eunoiaplot(fit; complement = Dict(:color => "#eeeeee"), quantities = true)
```

![](<../../assets/e1f3b16b9bb6423a19aa34195a355440ed5469132d71edb5fd670033bd95efad.png>)

<a id="colors-as-a-sequence-or-a-mapping"></a>

<a id="Colors-As-a-Sequence-or-a-Mapping"></a>

### Colors As a Sequence or a Mapping

`colors` accepts either a vector (one per set, in fit order) or a mapping from set name to color. 

```julia
fit = euler(
    Dict("A" => 10, "B" => 7, "C" => 8, "A&B" => 3, "A&C" => 4, "B&C" => 2, "A&B&C" => 1),
)

eunoiaplot(fit; colors = Dict("A" => "#e41a1c", "B" => "#377eb8", "C" => "#4daf4a"))
```

![](<../../assets/03eb5fcd1b1cd707bfdcfe8d031b3a3797459de2fc54bd39ef4b07db594c85ee.png>)

<a id="a-legend-instead-of-inline-labels"></a>

<a id="A-Legend-Instead-of-Inline-Labels"></a>

### A Legend Instead of Inline Labels

When sets are small or crowded their inline labels can overlap. Passing `legend = true` moves the set names into a color-keyed legend and turns the inline labels off by default (pass `labels = true` to keep both). A `Dict` or named tuple is forwarded to Makie's `Legend`, so you can control its title and appearance. 

```julia
fit = euler(
    Dict("A" => 10, "B" => 7, "C" => 8, "A&B" => 3, "A&C" => 4, "B&C" => 2, "A&B&C" => 1),
)
eunoiaplot(fit; legend = Dict(:title => "Sets"))
```

![](<../../assets/db38d1090c6a8f58fdf8ba1c482d9bbe350edbdb862fa3e43a5f0e21d44533f3.png>)

<a id="custom-label-text-and-style"></a>

<a id="Custom-label-text-and-style"></a>

### Custom label text and style

`labels` can be a `Dict` for per-set control. Map a set name to a replacement string, to a collection of `text!` keywords (with an optional `:text` key for custom text), or to `nothing`/`false` to hide that set's label. A style `Dict` whose keys are *not* set names — e.g. `Dict(:fontsize => 14)` — is a uniform style applied to every label instead. 

```julia
fit = euler(Dict("alpha" => 10, "beta" => 7, "alpha&beta" => 3))
eunoiaplot(
    fit;
    labels = Dict(
        "alpha" => (; text = "α", fontsize = 22),
        "beta" => (; text = "β", fontsize = 22, color = :crimson),
    ),
)
```

![](<../../assets/d90f599855487a733f51f395f62b5c3160977a45724937f5a09732fa7a4d868f.png>)

<a id="original-versus-fitted-quantities"></a>

<a id="Original-versus-Fitted-Quantities"></a>

### Original versus Fitted Quantities

To place two diagrams side by side and compare the requested values against what the layout achieved, pass a figure layout cell to [`eunoiaplot`](<reference/64c23a11690b420c37333e95ed51ddc80a26b8edd06ecb5463752a6e8f752650>) — `eunoiaplot(f[1, 1], fit)` creates a diagram-configured panel (equal aspect, hidden decorations) in that cell, so we don't build each `Axis` by hand. Per-panel options like a `title` go through `axis`. 

```julia
fit = euler(
    Dict("A" => 7, "B" => 6, "A&C" => 1, "B&C" => 1, "A&B&C" => 2, "C" => 0);
    shape = "ellipse",
)

f = Figure(size = (900, 400))

eunoiaplot(f[1, 1], fit; quantities = "original", axis = (; title = "original"))
eunoiaplot(f[1, 2], fit; quantities = "fitted", axis = (; title = "fitted"))

f
```

![](<../../assets/5601749a10edbf413d125920a86288beb8c32d17bc1dc67b3856ab3b365d8eb5.png>)

<a id="exterior-set-labels"></a>

<a id="Exterior-Set-Labels"></a>

### Exterior Set Labels

`set_label_placement = true` moves each set name outside its own shape, where it hugs the boundary without a leader. Region quantities remain collision-aware inside the diagram. A named tuple supplies the native set-label strategy knobs. 

```julia
fit = euler(Dict("Mammals" => 12, "Birds" => 9, "Mammals&Birds" => 3))
eunoiaplot(fit; quantities = true, set_label_placement = (; angular_steps = 180))
```

![](<../../assets/180716ba6b3c8c4aa253727015c1680f29c11d083811fcaf3e8b084ce3c79276.png>)

<a id="countable-glyphs"></a>

<a id="Countable-Glyphs"></a>

### Countable Glyphs

Pass explicit integer counts through `glyphs` to draw one equal-sized circular mark per unit. Eunoia chooses one radius for the entire diagram and keeps the marks clear of measured labels. Placement and Makie styling use separate option collections. 

```julia
fit = euler(Dict("A" => 12, "B" => 8, "A&B" => 4))
eunoiaplot(
    fit;
    glyphs = Dict("A" => 12, "B" => 8, "A&B" => 4),
    glyph_options = (; arrangement = "uniform", gap = 0.2),
    glyph_style = (; strokecolor = :black),
)
```

![](<../../assets/dbef287af65de248e12d1cadc32c31582dfac7e8d42011847c1466d8717222eb.png>)

<a id="packed-member-names"></a>

<a id="Packed-Member-Names"></a>

### Packed Member Names

`members` is the text analogue of `glyphs`: supply ordered names per region, and Eunoia measures and packs their boxes at one readable scale. The two modes are alternatives and cannot be enabled together. 

```julia
fit = euler(Dict("A" => 4, "B" => 3, "A&B" => 2))
eunoiaplot(
    fit;
    members = Dict(
        "A" => ["Ada", "Grace", "Barbara"],
        "B" => ["Alan", "Edsger"],
        "A&B" => ["Katherine"],
    ),
    member_style = (; color = :navy),
)
```

![](<../../assets/1cae9eb7977ca5fe6575eb40ec224400195c40d07688f41710033382bdbd5c84.png>)

<a id="counts-and-percentages"></a>

<a id="Counts-and-Percentages"></a>

### Counts and Percentages

`quantities` also chooses *how* to display each region. A string picks the display type—`"counts"` (the raw value, the default) or `"percent"` (the region's share of the total)—while a `Dict` or named tuple combines a type, a value source (`:source`), and text styling. Passing both types stacks the count above its percentage. 

```julia
fit = euler(
    Dict(
        "SE" => 13,
        "Treat" => 28,
        "Anti-CCP" => 101,
        "DAS28" => 91,
        "SE&Treat" => 1,
        "SE&DAS28" => 14,
        "Treat&Anti-CCP" => 6,
        "SE&Anti-CCP&DAS28" => 1,
    ),
)

eunoiaplot(fit; quantities = Dict(:type => ["counts", "percent"], :fontsize => 8))
```

![](<../../assets/caed0a9301a22627888d15e8461899213ed8e44cadb2e54eda2952f135ae7c5c.png>)

<a id="venn-diagrams"></a>

<a id="Venn-Diagrams"></a>

## Venn Diagrams

[`venn`](<reference/ec83f7b45a38f089fd97e9db1c19d0d5658bd2545e079bba777e3dbb45934bd6>) draws topological (non-proportional) Venn diagrams. It accepts an integer count, a vector of names, or a mapping. 

> **Note**
> 
> Circle Venn diagrams are unsupported in the pinned Eunoia core and raise an error. Use ellipses (1–5 sets) or squares/rectangles (1–3 sets); the examples below pass `shape` explicitly.

<a id="two-and-three-sets"></a>

<a id="Two-and-Three-Sets"></a>

### Two and Three Sets

```julia
f = Figure(size = (900, 400))

eunoiaplot(f[1, 1], venn(2; shape = "ellipse"))
eunoiaplot(f[1, 2], venn(["A", "B", "C"]; shape = "ellipse"))

f
```

![](<../../assets/d990f5896c9d5e34bf8058cb59dcec61f1b495bc1b40002527029f34d2156093.png>)

<a id="four-and-five-sets"></a>

<a id="Four-and-Five-Sets"></a>

### Four and Five Sets

```julia
f = Figure(size = (900, 400))

eunoiaplot(f[1, 1], venn(4; shape = "ellipse"))
eunoiaplot(f[1, 2], venn(5; shape = "ellipse"))

f
```

![](<../../assets/488089c93eaaffaeea19e3bed49f7f6b07db6581bf34d23b3f8bd132b3c46ac6.png>)

<a id="squares"></a>

<a id="Squares"></a>

### Squares

Venn diagrams of up to three sets can be drawn with square shapes instead of the default ellipse. Here the two sit side by side for the same three sets. 

```julia
f = Figure(size = (900, 400))

eunoiaplot(f[1, 1], venn(3; shape = "ellipse"); axis = (; title = "ellipse"))
eunoiaplot(f[1, 2], venn(3; shape = "square"); axis = (; title = "square"))

f
```

![](<../../assets/13e6f80dcdd55f6b3867c57d0aeb21272cd4c5791cbc80974a75b6ffc53376ec.png>)

`"rectangle"` is accepted too (up to three sets), but the symmetric Venn layout renders it identically to a square. Rectangles only differ from squares in area-proportional Euler diagrams. 

<a id="rotated-rectangles-for-four-sets"></a>

<a id="Rotated-Rectangles-for-Four-Sets"></a>

### Rotated Rectangles for Four Sets

`"rotated_rectangle"` draws a four-set Venn diagram with rotated rectangles, an arrangement that ellipses cannot lay out symmetrically. 

```julia
eunoiaplot(venn(4; shape = "rotated_rectangle"))
```

![](<../../assets/acc4dde5a7508f4f60aacc294e6197f8eb66f95f92b388a8daf0806ffaf446c7.png>)

<a id="a-complement-box"></a>

<a id="A-Complement-Box"></a>

### A Complement Box

`venn` also takes a `complement` size, just like `euler`, reserving area outside every set as a "universe" frame around the diagram. 

```julia
eunoiaplot(
    venn(3; shape = "ellipse", complement = 5);
    complement = Dict(:color => "#eeeeee"),
)
```

![](<../../assets/50d688e9625ac7f791fb82c0c8664b3a3e2bcb0119fe451e4c3e5671a21ef18d.png>)

<a id="from-membership-lists"></a>

<a id="From-Membership-Lists"></a>

### From Membership Lists

`venn` accepts the same membership-list input as `euler`; it only needs the set names. 

```julia
eunoiaplot(
    venn(Dict("A" => ["x", "y", "z"], "B" => ["y", "z", "w"], "C" => ["z", "w", "q"]);
         shape = "ellipse"),
)
```

![](<../../assets/94e82a30206ace1a2870ce2e96d0720975430e5ef0e7ff05911e3e383419aa28.png>)
