Skip to content

aegean.viz

viz

One-line visualization helpers (the [viz] extra: matplotlib, imported lazily).

Convenience plots over the corpus model and the analysis layer — each function draws one publication-ready-enough figure and returns the matplotlib Axes (pass ax= to compose subplots; call .figure.savefig(...) to write a file). These are conveniences, not a plotting framework: for anything bespoke, take the numbers from aegean.analysis and plot them yourself.

Most functions take backend="matplotlib" (the default) or backend="plotly". With "plotly" they return a Plotly Figure instead of a matplotlib Axes (call .write_html(...) to save an interactive page); Plotly is imported lazily and, if absent, raises a clear pointer to pip install 'pyaegean[viz-interactive]'.

import aegean stays dependency-free — matplotlib (and Plotly) are imported only inside the plotting calls, and a missing matplotlib raises a clear pointer to pip install 'pyaegean[viz]'. From the shell: aegean plot ….

TimelineBin dataclass

TimelineBin(start: int, count: int)

One time bucket: start is the bin's first year (negative = BCE); count is the number of documents whose parsed date midpoint falls in [start, start + bin_width).

Timeline dataclass

Timeline(bins: tuple[TimelineBin, ...], parsed: int, unparsed: int, total: int, bin_width: int)

The result of bucketing a corpus's documents over parsed dates.

bins are the non-empty buckets in chronological order; unparsed counts the documents whose meta.period :func:parse_period could not read (never dropped — always reported). unparsed_fraction is that count over total.

correspondence_layout

correspondence_layout(points: Sequence[tuple[float, float]], *, percentile: float = 0.9, pad_factor: float = 1.1, floor: float = 1e-09) -> list[tuple[float, float]]

Scale CA coordinates into the box [-1, 1]² for legible plotting.

A correspondence-analysis axis is usually dominated by one or two outlier points that, scaled by the global maximum, crush the rest of the cloud into a thin band. This scales each axis independently to its percentile-th absolute coordinate (×pad_factor) and pins points beyond that at the box edge (±1). The picture then shows relative position along each axis, not literal CA distances — state that in any caption.

plot_sign_frequencies

plot_sign_frequencies(corpus: Any, *, top: int = 20, kind: str = 'signs', ax: Any = None) -> Any

Horizontal frequency bars — the aegean stats table as a figure.

kind="signs" (default) counts individual signs; kind="words" whole words. Most frequent at the top.

plot_dispersion

plot_dispersion(corpus: Any, *, kind: str = 'words', min_frequency: int = 2, annotate: int = 10, ax: Any = None) -> Any

Frequency (log x) against Gries' normalized DP (y).

The diagnostic read: bottom-right = frequent corpus-wide vocabulary; top-right = frequent but concentrated items (formulaic or site/genre-bound — on Aegean material usually the interesting quadrant). The annotate most frequent items are labeled.

plot_keyness

plot_keyness(target: Any, reference: Any, *, kind: str = 'words', top: int = 15, min_target: int = 2, ax: Any = None) -> Any

Diverging bars of the top-G² key items: log-ratio effect size, right = overused in the target, left = underused. Bar labels carry G².

plot_collocation_network

plot_collocation_network(corpus: Any, word: str | None = None, *, max_nodes: int = 24, min_count: int = 2, ax: Any = None) -> Any

A document-co-occurrence network of multi-sign words (circular layout).

Edges join words attested together in min_count+ documents; width and opacity scale with the count. word restricts to that word's ego network. Exploratory on undeciphered material: an edge is shared context, not an asserted phrase or meaning.

plot_scansion

plot_scansion(line: Any, *, meter: str = 'hexameter', ax: Any = None) -> Any

A scansion grid for one verse line: syllables in metrical position, long (—) and short (⏑) marks, foot boundaries, and the caesura (‖).

line is Greek text (scanned via greek.scan_line) or an existing LineScansion. Raises ScansionError if the text does not fit the meter (synizesis is declined, never inferred).

plot_balance

plot_balance(corpus: Any, *, ax: Any = None) -> Any

Accounting reconciliation at a glance: each checked total (KU-RO / TO-SO) as computed sum (x) vs stated total (y). Points on the diagonal balance; red points do not — the discrepancies worth a closer look. The reconciliation inherits the heuristics of balance_check (section boundaries are inferred), so treat outliers as leads, not verdicts.

plot_correspondence_analysis

plot_correspondence_analysis(ca: CAResult, *, label_top: int = 12, ax: Any = None) -> Any

Correspondence-analysis biplot: rows (blue) and columns (amber) in one plane, with per-axis percentile scaling so a single outlier can't flatten the cloud (see :func:correspondence_layout). The heaviest label_top columns and all rows are labelled. Shows relative position along each axis, not literal CA distances.

plot_findspots

plot_findspots(corpus: Any, *, backend: str = 'matplotlib', ax: Any = None) -> Any

A scatter of the corpus's find-sites: longitude (x) against latitude (y), marker size scaled by the number of inscriptions from each site, each point labelled with its site name and count.

Coordinates come from the bundled site gazetteer (:func:aegean.geo.site_coordinates, stdlib — no [geo] extra needed to plot). Find-site labels are resolved through the same whitespace-normalized index :mod:aegean.geo uses, so the plot's site and inscription counts agree with :func:aegean.geo.to_geodataframe (a label split across lines still maps, and raw-label variants of one gazetteer site aggregate into one point). Sites absent from the gazetteer are dropped; if no site maps, the corpus has nothing to place and a clear ValueError is raised (the CLI turns it into a one-line message).

parse_period

parse_period(text: str) -> tuple[int, int] | None

Best-effort parse of an origDate-style date string to a (start, end) year range, BCE years negative and CE positive (e.g. "480—450 BCE"(-480, -450), "Third century BC"(-300, -201), "II century C.E"(101, 200), "27 BC - 14 AD"(-27, 14), "II-III century CE"(101, 300)).

A range is split into sides and each side is read on its own era and century intent, so a cross-era span keeps both signs; a side missing an era or the "century" word inherits it from the other side ("100-90 BC", "II-III century CE"). Returns None when the string carries no readable century or era-qualified year (a bare "Hellenistic" or "" is honestly unparseable, not guessed). Half/quarter and hedge qualifiers ("Second half of", "Perhaps", "Ca.") are ignored, and the whole century is returned. This is a heuristic for aggregate binning, not a dating authority.

timeline_bins

timeline_bins(corpus: Any, *, bin_width: int = 100) -> Timeline

Bucket a corpus's documents into bin_width-year bins by their parsed date.

Each document is placed by the midpoint of its :func:parse_period range; documents with no readable date are counted in unparsed (never silently dropped). Default bin_width=100 gives one bar per century.

plot_timeline

plot_timeline(corpus: Any, *, bin_width: int = 100, backend: str = 'matplotlib', ax: Any = None) -> Any

Document counts over bin_width-year bins (default one bar per century), from the best-effort dates in meta.period (see :func:parse_period).

The fraction of documents whose date could not be read is stated on the figure and available on :func:timeline_bins — dates are never silently dropped. Raises ValueError only for a corpus with no documents at all.

plot_sign_network

plot_sign_network(corpus: Any, *, level: str = 'sign', scope: str = 'document', min_count: int = 1, max_nodes: int = 30, backend: str = 'matplotlib', ax: Any = None) -> Any

Render the corpus's co-occurrence graph (:func:aegean.analysis.graph.cooccurrence_graph) with a deterministic, seedless frequency-ranked circular layout.

level ("sign"/"word"), scope ("document"/"line") and min_count are passed straight to the graph builder; the max_nodes most frequent nodes are drawn. Node size scales with corpus frequency, edge width with the shared-unit weight. Raises ValueError when nothing co-occurs at the threshold. Exploratory: an edge is shared context on undeciphered material, never an asserted phrase or meaning.