Provenny¶
Lay out area-proportional euler/venn diagrams for any number of sets.
- class provenny.Bounds(min_x: float, min_y: float, max_x: float, max_y: float)¶
Bases:
NamedTupleAn axis-aligned bounding box; a
(min_x, min_y, max_x, max_y)tuple with names.A real
tuple, so it unpacks, indexes, and compares equal to the plain 4-tuple – the added names and helpers are pure convenience.ax.set_xlim(box.min_x, box.max_x).- property center: tuple[float, float]¶
The box center
(x, y).
- property height: float¶
The extent along y,
max_y - min_y.
- max_x: float¶
Alias for field number 2
- max_y: float¶
Alias for field number 3
- min_x: float¶
Alias for field number 0
- min_y: float¶
Alias for field number 1
- property width: float¶
The extent along x,
max_x - min_x.
- class provenny.Diagram(names: tuple[_Name, ...], shapes: ndarray[tuple[int, ...], dtype[float64]])¶
Bases:
Generic[_Name]A solved layout: the set
namesand the(n, 5)shapesplaced for them.Returned by
proportional_venn().diagram[name](orellipse()) gives a set’s shape as anEllipse, and the diagram acts as a mapping over the names – iteration,len, andin– in order of first appearance, generic over the (hashable) label type.- property bounds: Bounds¶
The axis-aligned box
(min_x, min_y, max_x, max_y)enclosing every set’s ellipse.
- ellipse(name: _Name) Ellipse¶
Return the shape placed for a set name, as an
Ellipse.The spelled-out form of
diagram[name]; raisesKeyErrorfor an unknown name, as indexing does.
- names: tuple[_Name, ...]¶
- shapes: ndarray[tuple[int, ...], dtype[float64]]¶
- zone(names: Collection[Hashable], *, tol: float = 1e-09) Zone | None¶
Return the zone inside exactly
names(its boundary, area, and label point).namesare the sets the zone is inside; every other set is outside it, so{"A", "B"}is theA & Bzone and{"A"}the “A only” zone.Nonemeans that zone is empty in this layout. Its label point iszone(...).center.tolis the boundary-test tolerance (as forzone()). RaisesKeyErrorfor an unknown name andValueErrorfor an emptynames(the exterior is not a zone).
- class provenny.Ellipse(array: ndarray[tuple[int, ...], dtype[float64]])¶
Bases:
objectA placed shape wrapping its
(5,)layout row[*center, major, minor, angle].Indexing a
Diagramreturns one of these.- property angle: float¶
The major axis’s orientation from the x-axis, in radians, in
[0, pi).
- anomaly(x: float, y: float) float¶
Return the eccentric anomaly of a boundary point
(x, y), in[0, tau).
- property area: float¶
The enclosed area,
pi * major * minor.
- array: ndarray[tuple[int, ...], dtype[float64]]¶
- property center: tuple[float, float]¶
The
(x, y)center.
- contains(x: float, y: float, tol: float = 0.0) bool¶
Whether
(x, y)lies within the closed ellipse.
- frame(x: float, y: float) tuple[float, float]¶
(x, y)in the ellipse’s axis frame, scaled by the semi-axes (1 on boundary).
- property major: float¶
The larger semi-axis.
- matplotlib_path() tuple[ndarray[tuple[int, ...], dtype[float64]], ndarray[tuple[int, ...], dtype[uint8]]]¶
Return the outline as
(vertices, codes)formatplotlib.path.Path.
- property minor: float¶
The smaller semi-axis.
- point_at(anomaly: float) tuple[float, float]¶
Return the
(x, y)boundary point at eccentricanomaly.
- sample(num: int = 100) ndarray[tuple[int, ...], dtype[float64]]¶
Sample about
num(x, y)points evenly around the outline.
- svg_path() str¶
Return the outline as an svg
<path>d-string.
- class provenny.Zone(loops: list[list[Arc]], _ellipses: ndarray[tuple[int, ...], dtype[float64]], _inside: ndarray[tuple[int, ...], dtype[bool]])¶
Bases:
objectA laid-out zone: its boundary
loopsand the interior point to label it.loopsare the closed arc loops (outer lobes, nested holes).areais exact andcenteris the chebyshev (max-clearance) interior point, always inside even a crescent.- property area: float¶
The exact enclosed area (holes subtracted), via green’s theorem on the arcs.
- property bounds: Bounds¶
The axis-aligned bounding box
(min_x, min_y, max_x, max_y)of the boundary.
- property center: tuple[float, float]¶
The chebyshev (max-clearance) label point, computed on first access.
- loops: list[list[Arc]]¶
- matplotlib_path() tuple[ndarray[tuple[int, ...], dtype[float64]], ndarray[tuple[int, ...], dtype[uint8]]]¶
Return the boundary as
(vertices, codes)formatplotlib.path.Path.
- sample(num: int = 100) list[ndarray[tuple[int, ...], dtype[float64]]]¶
Sample about
numpoints around each boundary loop.
- svg_path() str¶
Return the boundary as an svg
<path>d-string.
- provenny.proportional_venn(areas: Mapping[Collection[_Name], float], *, mode: Literal['circle', 'ellipse', 'optimal'] = 'circle', restarts: int | None = None, tol: float = 1e-09, rng: Generator | None = None) Diagram[_Name]¶
Lay out a venn/euler diagram from named subset areas.
- Parameters:
areas – A mapping from a subset of set names to that subset’s area (e.g.
{"A": 1.0, "B": 1.0, "AB": 0.4}); omitted subsets are empty. A string key is a subset of single-character names, so"AB"is the pair{"A", "B"}.mode –
"circle"places circles."ellipse"places ellipses (annealed from pairwise-mds circle positions), which fit targets that circles cannot, while keeping every pairwise overlap a single connected lens – the mode to reach for when you want ellipses."optimal"drops the connectedness penalty for the lowest area error it can reach, letting a pair overlap in two disconnected lobes. All modes return circles when circles are already optimal.restarts – The number of random mds restarts.
"ellipse"/"optimal"anneal each distinct basin the restarts uncover and keep the best fit;"circle"keeps the best circle.Nonepicks the default:2 * (n - 1)for the ellipse modes (about the basin count, with margin), a small constant for"circle".tol – The numeric tolerance for area computations.
rng – Generator for the restart seeds;
Noneuses a freshnumpy.random.default_rng(). Pass a seeded one for reproducibility.
- Returns:
A
Diagrampairing each set name with the canonical ellipse placed for it;index or iterate it to read the shapes.
- Raises:
ValueError – If
modeis unknown,restartsis below 1, the mapping names no set, or a subset is malformed – repeated across keys, naming a set twice, or with a non-finite or negative area.
- provenny.proportional_venn_array(areas: ndarray[tuple[int, ...], dtype[float64]], *, mode: Literal['circle', 'ellipse', 'optimal'] = 'circle', restarts: int | None = None, tol: float = 1e-09, rng: Generator | None = None) ndarray[tuple[int, ...], dtype[float64]]¶
Lay out a venn/euler diagram from a raw subset-area array.
- Parameters:
areas – A 1-D array of the area of every non-empty subset of the
nsets, length2**n - 1, indexed by subset bitmask minus one (bitimarks seti). For two sets this is[|A|, |B|, |A & B|].mode –
"circle"places circles."ellipse"places ellipses (annealed from pairwise-mds circle positions), which fit targets that circles cannot, while keeping every pairwise overlap a single connected lens – the mode to reach for when you want ellipses."optimal"drops the connectedness penalty for the lowest area error it can reach, letting a pair overlap in two disconnected lobes. All modes return circles when circles are already optimal.restarts – The number of random mds restarts.
"ellipse"/"optimal"anneal each distinct basin the restarts uncover and keep the best fit;"circle"keeps the best circle.Nonepicks the default:2 * (n - 1)for the ellipse modes (about the basin count, with margin), a small constant for"circle".tol – The numeric tolerance for area computations.
rng – Generator for the restart seeds;
Noneuses a freshnumpy.random.default_rng(). Pass a seeded one for reproducibility.
- Returns:
The shapes, one canonical ellipse row per set (an
(n, 5)array of)(cx, cy, major, minor, angle)withmajor >= minorandanglein[0, pi). Every mode returns this same(n, 5)layout, so a caller neverbranches on the mode.
- Raises:
ValueError – If
modeis unknown,restartsis below 1, or the areas are malformed – the wrong length, non-finite, negative, or leaving a set with no area.
- provenny.zone(ellipses: ndarray[tuple[int, ...], dtype[float64]], inside: ndarray[tuple[int, ...], dtype[bool]], *, tol: float = 1e-09) Zone | None¶
Build the zone inside the flagged sets and outside the rest, or
Noneif empty.- Parameters:
ellipses – An
(n, 5)layout of canonical(cx, cy, major, minor, angle)rows (major >= minor,anglein[0, pi)), asproportional_venn_array()returns.inside – A boolean mask over the sets;
inside[i]true keeps the zone inside seti.tol – Numeric tolerance for the boundary tests.
- Return type:
The zone, or
Nonewhen it is empty in this layout.- Raises:
ValueError – If the rows are not canonical ellipses, or no set is flagged – the exterior is not a zone.