API Reference

class astromol.database.Database(data_dir: str | Path | None = None)

Central container for all astromol data. Loads JSON files, resolves cross-references, and exposes simple lookups.

get_ref(bibcode)

Look up a Ref by BibTeX citation key.

get_telescope(nick)

Look up a Telescope by nick.

get_source(nick)

Look up a Source by nick.

get_molecule(label)

Look up a Molecule by unique label.

get_molecules_by_formula(formula)

Look up all molecules with a given chemical formula.

get_molecules_by_name(name)

Look up all molecules with a given name.

Census-scoped views over an astromol.database.Database.

The view layer centralizes record selection for manuscript tables, figures, slides, and statistics. Output code should consume these views instead of reimplementing census/history filtering locally.

class astromol.census.CensusView(db: object, scope: str = 'census', census: str | None = None)

A filtered view of astromol records for a census boundary or live data.

Use for_census() for frozen/historical census outputs and current() for the live database. In census mode, accepted records are selected by history.accepted.census <= census. In current mode, accepted records are selected regardless of census label. Context queries exclude isotopologues by default; pass include_isotopologues=True for isotope-expanded views.

classmethod for_census(db, census: str | int) CensusView

Create a view frozen at a census boundary.

classmethod current(db) CensusView

Create a live view of all currently accepted records.

property is_current: bool

Whether this view represents live database contents.

property census_year: int | None

The integer census boundary, or None for current views.

accepted_record(record) bool

Return whether a molecule or detection is accepted in this view.

introduced_record(record) bool

Return whether a record had entered tracking by this view.

static is_secure(detection: Detection) bool

Return whether a detection is treated as secure.

detection_in_scope(detection: Detection, *, include_tentative: bool = False, include_disputed: bool = False) bool

Return whether a detection belongs in this view.

Secure detections require accepted history. Tentative and disputed detections are included only when requested, and then by introduced history rather than accepted history.

detections(detection_type: str | None = None, *, include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = False) list[Detection]

Return detections in this view, optionally restricted by type.

Isotopologue detections are excluded by default. Set include_isotopologues=True when the expanded isotopologue inventory is wanted.

context_detections(detection_type: str, *, include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = False) list[Detection]

Return detections for one context such as "ISM/CSM".

context_molecules(detection_type: str, *, include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = False) list[Molecule]

Return unique molecules detected in one context.

Isotopologues are excluded by default and can be included with include_isotopologues=True.

accepted_molecules(*, include_isotopologues: bool = False) list[Molecule]

Return molecule records accepted in this view by molecule history.

Isotopologues are excluded by default and can be included with include_isotopologues=True.

ism_detections(**kwargs) list[Detection]

Return ISM/CSM detections in this view.

ism_molecules(**kwargs) list[Molecule]

Return ISM/CSM molecules in this view.

ppd_detections(**kwargs) list[Detection]

Return protoplanetary-disk detections in this view.

ppd_molecules(**kwargs) list[Molecule]

Return protoplanetary-disk molecules in this view.

ice_detections(**kwargs) list[Detection]

Return ice detections in this view.

ice_molecules(**kwargs) list[Molecule]

Return ice molecules in this view.

exgal_detections(**kwargs) list[Detection]

Return extragalactic detections in this view.

exgal_molecules(**kwargs) list[Molecule]

Return extragalactic molecules in this view.

exoplanet_detections(**kwargs) list[Detection]

Return exoplanet-atmosphere detections in this view.

exoplanet_molecules(**kwargs) list[Molecule]

Return exoplanet-atmosphere molecules in this view.

source_counts(detection_type: str = 'ISM/CSM', *, include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = False, key: str = 'nick', group_diffuse_cloud: bool = False, diffuse_cloud_label: str = 'DiffuseCloud') Counter

Count source contributions for detections in this view.

key may be "nick", "name", or "latex_name". Set group_diffuse_cloud=True to consolidate all diffuse-cloud/LOS sources under one label for historical manuscript table reproduction.

facility_counts(detection_type: str = 'ISM/CSM', *, include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = False, key: str = 'nick') Counter

Count telescope/facility contributions for detections in this view.

molecule_labels(molecules: Iterable[Molecule]) set[str]

Return molecule labels from a molecule iterable.

filtered(*, molecule_filter: Callable[[Molecule], bool] | None = None, detection_filter: Callable[[Detection], bool] | None = None) FilteredCensusView

Return a custom view that filters records from this view.

Use this when a standard census/current view is the correct historical boundary, but an analysis should be restricted to a special subset such as carbon-bearing molecules, detections from one source type, or detections observed with one wavelength family.

class astromol.census.FilteredCensusView(base: CensusView, molecule_filter: Callable[[Molecule], bool] | None = None, detection_filter: Callable[[Detection], bool] | None = None)

View wrapper that applies custom filters to an existing census view.

property db

The underlying database.

property scope: str

The wrapped view scope.

property census: str | None

The wrapped census boundary, or None for current views.

property is_current: bool

Whether this view represents live database contents.

property census_year: int | None

The integer census boundary, or None for current views.

accepted_record(record) bool

Return whether a record is accepted in the wrapped view.

introduced_record(record) bool

Return whether a record had entered tracking by the wrapped view.

static is_secure(detection: Detection) bool

Return whether a detection is treated as secure.

detection_in_scope(detection: Detection, *, include_tentative: bool = False, include_disputed: bool = False) bool

Return whether a detection belongs in the wrapped view.

detections(detection_type: str | None = None, *, include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = False) list[Detection]

Return filtered detections from the wrapped view.

context_detections(detection_type: str, *, include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = False) list[Detection]

Return filtered detections for one context.

context_molecules(detection_type: str, *, include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = False) list[Molecule]

Return unique filtered molecules detected in one context.

accepted_molecules(*, include_isotopologues: bool = False) list[Molecule]

Return filtered molecule records accepted in the wrapped view.

ism_detections(**kwargs) list[Detection]

Return filtered ISM/CSM detections.

ism_molecules(**kwargs) list[Molecule]

Return filtered ISM/CSM molecules.

ppd_detections(**kwargs) list[Detection]

Return filtered protoplanetary-disk detections.

ppd_molecules(**kwargs) list[Molecule]

Return filtered protoplanetary-disk molecules.

ice_detections(**kwargs) list[Detection]

Return filtered ice detections.

ice_molecules(**kwargs) list[Molecule]

Return filtered ice molecules.

exgal_detections(**kwargs) list[Detection]

Return filtered extragalactic detections.

exgal_molecules(**kwargs) list[Molecule]

Return filtered extragalactic molecules.

exoplanet_detections(**kwargs) list[Detection]

Return filtered exoplanet-atmosphere detections.

exoplanet_molecules(**kwargs) list[Molecule]

Return filtered exoplanet-atmosphere molecules.

source_counts(detection_type: str = 'ISM/CSM', *, include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = False, key: str = 'nick', group_diffuse_cloud: bool = False, diffuse_cloud_label: str = 'DiffuseCloud') Counter

Count filtered source contributions for detections in this view.

facility_counts(detection_type: str = 'ISM/CSM', *, include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = False, key: str = 'nick') Counter

Count filtered telescope/facility contributions.

molecule_labels(molecules: Iterable[Molecule]) set[str]

Return molecule labels from a molecule iterable.

class astromol.models.Ref(bibcode: str, author: str, journal: str, year: int, month: int = None, day: int = None, volume: str = None, page: str = None, title: str = None, doi: str = None, note: str = None)

A single bibliographic reference.

property sortdate

Build a date for sorting/ordering purposes. Uses the 1st for any unknown month or day. Two papers from 1937 with no month both get Jan 1 1937, but a paper from March 1937 sorts after January 1937.

class astromol.models.HistoryEvent(kind: str, summary: str, date: str = None, census: str = None, fields: list[str] = <factory>, legacy_version: str = None)

A semantic database-history event exposed through a record.

class astromol.models.RecordHistory(introduced: dict = None, accepted: dict = None, last_modified: str = None, events: list[HistoryEvent] = <factory>)

Semantic update history for a database record.

property introduced_census

Census release where this record entered astromol tracking.

property introduced_context

Context for record introduction, such as confirmed or tentative.

property accepted_census

Census release where this record first became accepted/confirmed.

property accepted_context

Context for first accepted/confirmed census membership.

class astromol.models.Telescope(name: str, nick: str, shortname: str, type: str, wavelength: list, diameter: float = None, latitude: float = None, longitude: float = None, built: int = None, decommissioned: int = None, note: str = None, latex_name: str = None, history: RecordHistory = None)

An observing facility or instrument.

property active

True if the telescope has not been decommissioned.

class astromol.models.Source(name: str, nick: str, type: str, ra: str = None, dec: str = None, simbad_url: str = None, latex_name: str = None, note: str = None, history: RecordHistory = None)

An astronomical object where molecules have been detected.

class astromol.models.RotationalConstants(A: float = None, B: float = None, C: float = None, refs: list = <factory>, note: str = None)

Rotational constants of a molecule in MHz.

property ref

Legacy alias for the first reference, if present.

class astromol.models.DipoleMoment(a: float = None, b: float = None, c: float = None, refs: list = <factory>, note: str = None)

Dipole moment components of a molecule in Debye.

property ref

Legacy alias for the first reference, if present.

property total

Total dipole moment magnitude in Debye.

class astromol.models.Molecule(name: str, formula: str, table_formula: str = None, label: str = None, note: str = None, iupac_name: str = None, selfies: str = None, synonyms: list[str] = <factory>, smiles: str = None, canonical_smiles: str = None, inchi: str = None, inchikey: str = None, radical_override: bool = None, fullerene: bool = False, pah: bool = False, n_rings: int = 0, cyclic: bool = False, tags: dict[str, list[str]]=<factory>, rotcon: RotationalConstants = None, dipole: DipoleMoment = None, refs: dict = None, isotopologue_of: str = None, latex_section_override: str = None, latex_body: str = None, history: RecordHistory = None)

A chemical species detected (or potentially detectable) in the ISM/CSM.

The optional smiles and selfies fields are retained as identifiers or future display metadata only; they are stored but not interpreted here.

property introduced_census

Census release where this molecule entered astromol tracking.

property introduced_context

Context for molecule introduction, such as confirmed or tentative.

property accepted_census

Census release where this molecule first became accepted/confirmed.

property accepted_context

Context for first accepted/confirmed census membership.

property atom_counts

Elemental composition with isotopic substitutions collapsed.

Examples

HCOOH -> {‘H’: 2, ‘C’: 1, ‘O’: 2} CH -> {‘C’: 1, ‘H’: 1}

Use isotope_counts if isotope labels need to be retained.

property atoms

Legacy alias for atom_counts.

property isotope_counts

Elemental composition retaining isotope labels where present.

property mass

Exact/monoisotopic molecular mass in amu.

property average_mass

Average molecular mass from terrestrial isotopic abundances.

property nominal_mass

Nominal integer mass of the formula.

property natoms

Total number of nuclei in the formula.

property charge

Formal charge of the molecule.

property cation

True if positively charged.

property anion

True if negatively charged.

property neutral

True if not charged.

property nelectrons

Total number of electrons after correcting for formal charge.

This is the sum of neutral atomic numbers minus the molecular charge. A cation has fewer electrons; an anion has more.

property odd_electron

True if the molecule has an odd number of electrons.

property radical

Whether the molecule should be treated as a radical.

If radical_override is set, the curated value is returned. Otherwise, radical character is inferred from the odd-electron rule.

property du

Degree of unsaturation using the original astromol convention.

This is only computed for molecules containing H/D, C, N, O, Cl, F, and S. It is a formula-based heuristic, not a structure assignment. Returns None outside the domain where the simple expression is useful.

property maxdu

Maximum degree of unsaturation for the same heavy-atom inventory.

This preserves the original astromol convention and is only computed for the same limited element set as du.

property is_linear

True if the molecule is linear. Determined by having only a B rotational constant (no A or C). Returns None if no rotational constants are available.

property kappa

Ray’s asymmetry parameter. Ranges from -1 (prolate) to +1 (oblate). Linear rotors are treated as the perfectly prolate limit, kappa = -1. Nonlinear rotors require all three rotational constants.

class astromol.models.Detection(id: str, molecule: str, sources: list, telescopes: list, wavelengths: list, year: int, type: str, note: str = None, status: str = 'secure', status_note: str = None, first: bool = False, month: int = None, day: int = None, refs: dict = None, confirms: list = <factory>, confirmed_by: list = <factory>, disputes: list = <factory>, disputed_by: list = <factory>, supersedes: list = <factory>, superseded_by: list = <factory>, latex_text: str = None, history: RecordHistory = None)

A specific detection event of a molecule in an astronomical source.

property introduced_census

Census release where this detection entered astromol tracking.

property introduced_context

Context for detection introduction, such as confirmed or tentative.

property accepted_census

Census release where this detection first became accepted/confirmed.

property accepted_context

Context for first accepted/confirmed census membership.

property sortdate

Build a date for sorting/ordering purposes. Uses the 1st for any unknown month or day.

Validation helpers for astromol production data.

class astromol.validation.ValidationIssue(severity: str, code: str, record: str, message: str)

One validation issue found in the production data.

class astromol.validation.ValidationReport(issues: list[ValidationIssue] = <factory>)

Collection of validation issues.

astromol.validation.validate_database(db: Database | None = None) ValidationReport

Validate production records and return a report.

Database() already validates parsing, required dataclass values, duplicate primary keys, reference resolution, and relationship targets. This layer adds semantic consistency checks that are useful before releases and data-update commits.

astromol.validation.format_issue(issue: ValidationIssue) str

Return one issue formatted for command-line output.

astromol.validation.format_report(report: ValidationReport) str

Return a human-readable validation report.

LaTeX output helpers for census manuscripts.

class astromol.latex.TableColumn(header: str, anchor: str, molecules: list[Molecule])

One logical molecule-table column.

class astromol.latex.DetectionRateFit(label: str, onset_year: int, slope: float, r_value: float, r_squared: float)

Linear detection-rate fit for one molecule-size category.

astromol.latex.endinput(value: object) str

Return a LaTeX input fragment terminated with \endinput.

astromol.latex.write_fragments(fragments: dict[str, str], output_dir: str | Path = '.') None

Write filename-to-content LaTeX fragments to output_dir.

Return a hyperlinked mhchem formula for a molecule.

Return a linked molecule formula with a tentative marker if needed.

astromol.latex.linked_header(anchor: str, text: str) str

Return a hyperlinked table-column header.

astromol.latex.first_detection_sort_keys(detections: Iterable[Detection]) dict[str, tuple]

Return first-detection sort keys by molecule label.

astromol.latex.molecules_by_first_detection(molecules: Iterable[Molecule], detections: Iterable[Detection]) list[Molecule]

Sort molecules by first detection represented in detections.

astromol.latex.split_legacy_pair_column(values: list[Molecule]) tuple[list[Molecule], list[Molecule]]

Split legacy paired table columns using the historical midpoint rule.

astromol.latex.split_balanced_columns(values: list[Molecule], max_rows: int) list[list[Molecule]]

Split values into balanced chunks with no chunk over max_rows.

astromol.latex.table_rows(columns: list[list[Molecule]]) list[str]

Render molecule columns as LaTeX table rows.

astromol.latex.table_column_rows(columns: list[TableColumn]) list[str]

Render logical table columns as LaTeX rows.

astromol.latex.table_column_header(columns: list[TableColumn]) str

Render logical table-column headers with grouped split columns.

astromol.latex.atom_reference_table_header(atom_counts: Iterable[int]) list[str]

Return grouped atom-count and species/reference table headers.

astromol.latex.tabular_spec(ncols: int) str

Return a flexible full-width tabular specification.

astromol.latex.species_reference_tabular_spec(npairs: int) str

Return a full-width tabular spec for species/reference column pairs.

astromol.latex.single_reference_tabular_spec(width: str = '\\columnwidth') str

Return a tabular spec for one species/reference column pair.

astromol.latex.latex_table_fragment(*, caption: str, tabular_spec: str, header: str, rows: list[str], label: str) str

Render a complete LaTeX table fragment.

astromol.latex.molecule_count(view: CensusView) int

Number of accepted ISM/CSM molecules in the view.

astromol.latex.element_count(view: CensusView) int

Number of unique elements in accepted ISM/CSM molecules.

astromol.latex.context_molecule_count(view: CensusView, detection_type: str, *, include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = True) int

Count unique molecules in one detection context.

astromol.latex.ppd_molecule_count(view: CensusView) int

Number of non-isotopologue molecules detected in PPDs.

astromol.latex.ppd_isotopologue_count(view: CensusView) int

Number of isotopologue entries detected in PPDs.

astromol.latex.exgal_molecule_count(view: CensusView) int

Number of accepted extragalactic molecules.

astromol.latex.exgal_percent(view: CensusView) int

Accepted extragalactic molecules as a percentage of ISM/CSM molecules.

astromol.latex.exoplanet_molecule_count(view: CensusView) int

Number of accepted exoplanet-atmosphere molecules.

astromol.latex.ice_molecule_count(view: CensusView) int

Number of accepted interstellar-ice molecules.

astromol.latex.molecule_detections_by_label(detections: Iterable[Detection]) dict[str, list[Detection]]

Group detections by molecule label.

astromol.latex.radio_percent(view: CensusView) int

Percentage of ISM/CSM molecules detected at radio wavelengths.

astromol.latex.facility_count(view: CensusView) int

Number of facilities contributing to accepted ISM/CSM detections.

astromol.latex.hydrocarbon_molecules(view: CensusView) list[Molecule]

ISM/CSM molecules with C and H and a computable degree of unsaturation.

astromol.latex.saturated_hydrocarbons(view: CensusView) list[Molecule]

Hydrocarbon molecules with zero degree of unsaturation.

astromol.latex.unsaturated_hydrocarbons(view: CensusView) list[Molecule]

Hydrocarbon molecules with nonzero degree of unsaturation.

astromol.latex.saturated_hydrocarbon_count(view: CensusView) int

Number of saturated hydrocarbon molecules.

astromol.latex.saturated_hydrocarbon_percent(view: CensusView) int

Saturated hydrocarbons as a percentage of hydrocarbon molecules.

astromol.latex.unsaturated_hydrocarbon_percent(view: CensusView) int

Unsaturated hydrocarbons as a percentage of hydrocarbon molecules.

astromol.latex.saturated_hydrocarbon_list(view: CensusView) str

LaTeX list of saturated hydrocarbon formulas.

astromol.latex.molecule_source_types(view: CensusView) dict[str, set[str]]

Map ISM/CSM molecule labels to source types represented in detections.

astromol.latex.radical_percent_by_source_type(view: CensusView, source_type: str) int

Percentage of molecules detected in a source type that are radicals.

astromol.latex.first_detection_years(view: CensusView) list[int]

First accepted ISM/CSM detection year for each molecule.

astromol.latex.detection_rate_since(view: CensusView, start_year: int) float

Linear cumulative-detection rate since start_year.

astromol.latex.scalar_fragments(view: CensusView) dict[str, str]

Return standard scalar LaTeX input fragments for a census view.

astromol.latex.write_scalar_fragments(view: CensusView, output_dir: str | Path = '.') dict[str, str]

Write standard scalar LaTeX fragments and return generated content.

astromol.latex.rate_fit_end_year(view: CensusView, detections: Iterable[Detection]) int

Return the final year to use for rate-table fits.

astromol.latex.category_detection_years(detections: Iterable[Detection], category: int | str) list[int]

Return first-detection years for one atom-count rate category.

astromol.latex.cumulative_counts_by_year(detection_years: Iterable[int], *, onset_year: int, end_year: int) tuple[ndarray, ndarray]

Return years and cumulative detection counts since the onset year.

astromol.latex.linear_rate_fit(detection_years: Iterable[int], *, onset_year: int, end_year: int) tuple[float, float, float] | None

Return slope, Pearson R, and R^2 for cumulative detections since onset.

astromol.latex.rate_by_atoms_fits(view: CensusView) list[DetectionRateFit]

Return detection-rate fits by atom-count category for ISM/CSM molecules.

astromol.latex.rate_by_atoms_table_fragment(view: CensusView) str

Return the detection-rate-by-atoms table as a LaTeX fragment.

astromol.latex.rate_by_atoms_table_fragments(view: CensusView, filename: str = 'rates_by_atoms_table.tex') dict[str, str]

Return the detection-rate-by-atoms table fragment.

astromol.latex.write_rate_by_atoms_table(view: CensusView, output_dir: str | Path = '.', filename: str = 'rates_by_atoms_table.tex') dict[str, str]

Write the detection-rate-by-atoms table and return content.

astromol.latex.sorted_count_entries(counts: dict[str, int]) list[tuple[str, int]]

Return count entries sorted descending by count, then by label.

astromol.latex.paired_count_table_rows(entries: list[tuple[str, int]]) list[str]

Render count entries into two side-by-side table-column pairs.

astromol.latex.paired_count_table_fragment(*, caption: str, label: str, item_header: str, count_header: str, entries: list[tuple[str, int]]) str

Return a two-column-pair LaTeX count table fragment.

astromol.latex.facility_table_entries(view: CensusView) list[tuple[str, int]]

Return observing-facility contribution counts for the facility table.

astromol.latex.facility_table_fragment(view: CensusView) str

Return the observing-facility count table as a LaTeX fragment.

astromol.latex.facility_table_fragments(view: CensusView, filename: str = 'facilities_table.tex') dict[str, str]

Return the observing-facility count table fragment.

astromol.latex.write_facility_table(view: CensusView, output_dir: str | Path = '.', filename: str = 'facilities_table.tex') dict[str, str]

Write the observing-facility count table and return content.

astromol.latex.source_table_entries(view: CensusView) list[tuple[str, int]]

Return source contribution counts for the source table.

astromol.latex.source_table_fragment(view: CensusView) str

Return the source contribution count table as a LaTeX fragment.

astromol.latex.source_table_fragments(view: CensusView, filename: str = 'source_table.tex') dict[str, str]

Return the source contribution count table fragment.

astromol.latex.write_source_table(view: CensusView, output_dir: str | Path = '.', filename: str = 'source_table.tex') dict[str, str]

Write the source contribution count table and return content.

astromol.latex.ism_table_molecules(view: CensusView) list[Molecule]

Return non-isotopologue ISM/CSM molecules for the main molecule table.

astromol.latex.ism_table_detections(view: CensusView) list[Detection]

Return non-isotopologue ISM/CSM detections for table ordering.

astromol.latex.ism_table_columns(view: CensusView) tuple[list[list[Molecule]], list[list[Molecule]]]

Return legacy ISM/CSM table columns for a census view.

astromol.latex.balanced_ism_table_columns(view: CensusView, *, max_rows: int = 23, max_columns: int = 7) list[list[TableColumn]]

Return balanced ISM/CSM table columns packed into table groups.

astromol.latex.legacy_ism_table_fragments(view: CensusView, basename: str = 'ism_table') dict[str, str]

Return the two legacy 2021-style ISM/CSM molecule table fragments.

astromol.latex.balanced_ism_table_fragments(view: CensusView, basename: str = 'ism_table', *, max_rows: int = 23, max_columns: int = 7) dict[str, str]

Return balanced, future-oriented ISM/CSM molecule table fragments.

astromol.latex.ism_table_fragments(view: CensusView, basename: str = 'ism_table', *, layout: str = 'balanced', max_rows: int = 23, max_columns: int = 7) dict[str, str]

Return ISM/CSM molecule table fragments.

layout="legacy" reproduces the two historical audit tables. layout="balanced" produces future-oriented tables constrained by max_rows and max_columns.

astromol.latex.write_ism_tables(view: CensusView, output_dir: str | Path = '.', basename: str = 'ism_table', *, layout: str = 'balanced', max_rows: int = 23, max_columns: int = 7) dict[str, str]

Write standard ISM/CSM molecule tables and return generated content.

astromol.latex.first_context_detection_by_molecule(detections: Iterable[Detection]) dict[str, Detection]

Return the first secure detection per molecule, falling back to tentative.

astromol.latex.exgal_table_detections(view: CensusView) list[Detection]

Return non-isotopologue exgal detections for the molecule table.

Secure detections are included by accepted census membership. Tentative detections are included by introduced census membership and rendered with a dagger marker.

astromol.latex.chunked_atom_groups(atom_counts: list[int], *, first_group_size: int, group_size: int) list[tuple[int, ...]]

Split atom-count labels into first-page and continuation groups.

astromol.latex.exgal_table_atom_groups(view: CensusView) list[tuple[int, ...]]

Return non-empty atom-count groups for the exgal molecule table.

astromol.latex.exgal_table_columns(view: CensusView, atom_groups: Iterable[Iterable[int]] | None = None) list[list[list[Detection]]]

Return exgal table columns split by configured atom-count groups.

astromol.latex.observation_ref_bibcodes(detection: Detection) list[str]

Return observation-reference BibTeX keys for a detection.

astromol.latex.reference_numbers(bibcodes: Iterable[str], references: dict[str, int]) str

Assign and render stable numeric reference labels for BibTeX keys.

astromol.latex.detection_reference_table_rows(columns: list[list[Detection]], references: dict[str, int]) list[str]

Render rows for molecule/reference table columns.

astromol.latex.single_detection_reference_table_rows(detections: Iterable[Detection], references: dict[str, int]) list[str]

Render rows for a one-column species/reference table.

astromol.latex.numbered_reference_notes(references: dict[str, int]) str

Render numbered citation notes from BibTeX key to index mapping.

astromol.latex.exgal_table_fragment(view: CensusView) str

Return the external-galaxy molecule table as a LaTeX fragment.

astromol.latex.exgal_table_fragments(view: CensusView, filename: str = 'exgal_table.tex') dict[str, str]

Return the external-galaxy molecule table fragment.

astromol.latex.write_exgal_table(view: CensusView, output_dir: str | Path = '.', filename: str = 'exgal_table.tex') dict[str, str]

Write the external-galaxy molecule table and return generated content.

astromol.latex.ppd_table_detections(view: CensusView) list[Detection]

Return PPD detections for the molecule table, including isotopologues.

The PPD table intentionally includes isotope records. Ordering is parent-first: each parent molecule is followed by any detected PPD isotopologues that point to it.

astromol.latex.ppd_table_atom_groups(view: CensusView) list[tuple[int, ...]]

Return non-empty atom-count groups for the PPD molecule table.

astromol.latex.ppd_table_columns(view: CensusView, atom_groups: Iterable[Iterable[int]] | None = None) list[list[list[Detection]]]

Return PPD table columns split by configured atom-count groups.

astromol.latex.ppd_table_fragment(view: CensusView) str

Return the protoplanetary-disk molecule table as a LaTeX fragment.

astromol.latex.ppd_table_fragments(view: CensusView, filename: str = 'ppd_table.tex') dict[str, str]

Return the protoplanetary-disk molecule table fragment.

astromol.latex.write_ppd_table(view: CensusView, output_dir: str | Path = '.', filename: str = 'ppd_table.tex') dict[str, str]

Write the protoplanetary-disk molecule table and return content.

astromol.latex.parent_first_context_detections(db, detections: Iterable[Detection], *, include_isotopologues: bool) list[Detection]

Order context detections in database order, parent before isotopologues.

astromol.latex.exoplanet_table_detections(view: CensusView, *, include_isotopologues: bool = False) list[Detection]

Return exoplanet detections for the molecule table.

astromol.latex.exoplanet_table_fragment(view: CensusView, *, include_isotopologues: bool = False) str

Return the exoplanet-atmosphere molecule table as a LaTeX fragment.

astromol.latex.exoplanet_table_fragments(view: CensusView, filename: str = 'exo_table.tex', *, include_isotopologues: bool = False) dict[str, str]

Return the exoplanet-atmosphere molecule table fragment.

astromol.latex.write_exoplanet_table(view: CensusView, output_dir: str | Path = '.', filename: str = 'exo_table.tex', *, include_isotopologues: bool = False) dict[str, str]

Write the exoplanet-atmosphere table and return content.

astromol.latex.ice_table_detections(view: CensusView, *, include_tentative: bool = True, include_isotopologues: bool = False) list[Detection]

Return ice detections for the molecule table.

astromol.latex.ice_table_fragment(view: CensusView, *, include_tentative: bool = True, include_isotopologues: bool = False) str

Return the interstellar-ice molecule table as a LaTeX fragment.

astromol.latex.ice_table_fragments(view: CensusView, filename: str = 'ice_table.tex', *, include_tentative: bool = True, include_isotopologues: bool = False) dict[str, str]

Return the interstellar-ice molecule table fragment.

astromol.latex.write_ice_table(view: CensusView, output_dir: str | Path = '.', filename: str = 'ice_table.tex', *, include_tentative: bool = True, include_isotopologues: bool = False) dict[str, str]

Write the interstellar-ice table and return content.

Public figure API.

The implementation is split into private/focused modules, but public callers should continue importing figure helpers from astromol.figures.

class astromol.figures.defaultdict

defaultdict(default_factory=None, /, […]) –> dict with default factory

The default factory is called without arguments to produce a new value when a key is not present, in __getitem__ only. A defaultdict compares equal to a dict with the same items. All remaining arguments are treated the same as if they were passed to the dict constructor, including keyword arguments.

copy() a shallow copy of D.
default_factory

Factory for default value called by __missing__().

astromol.figures.dataclass(cls=None, /, *, init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False, match_args=True, kw_only=False, slots=False, weakref_slot=False)

Add dunder methods based on the fields defined in the class.

Examines PEP 526 __annotations__ to determine fields.

If init is true, an __init__() method is added to the class. If repr is true, a __repr__() method is added. If order is true, rich comparison dunder methods are added. If unsafe_hash is true, a __hash__() method is added. If frozen is true, fields may not be assigned to after instance creation. If match_args is true, the __match_args__ tuple is added. If kw_only is true, then by default all fields are keyword-only. If slots is true, a new class with a __slots__ attribute is returned.

class astromol.figures.date

date(year, month, day) –> date object

ctime()

Return ctime() style string.

classmethod fromisocalendar()

int, int, int -> Construct a date from the ISO year, week number and weekday.

This is the inverse of the date.isocalendar() function

classmethod fromisoformat()

str -> Construct a date from a string in ISO 8601 format.

classmethod fromordinal()

int -> date corresponding to a proleptic Gregorian ordinal.

classmethod fromtimestamp(timestamp, /)

Create a date from a POSIX timestamp.

The timestamp is a number, e.g. created via time.time(), that is interpreted as local time.

isocalendar()

Return a named tuple containing ISO year, week number, and weekday.

isoformat()

Return string in ISO 8601 format, YYYY-MM-DD.

isoweekday()

Return the day of the week represented by the date. Monday == 1 … Sunday == 7

replace()

Return date with new specified fields.

strftime()

format -> strftime() style string.

timetuple()

Return time tuple, compatible with time.localtime().

classmethod today()

Current date or datetime: same as self.__class__.fromtimestamp(time.time()).

toordinal()

Return proleptic Gregorian ordinal. January 1 of year 1 is day 1.

weekday()

Return the day of the week represented by the date. Monday == 0 … Sunday == 6

class astromol.figures.Path(*args, **kwargs)

PurePath subclass that can make system calls.

Path represents a filesystem path but unlike PurePath, also offers methods to do system calls on path objects. Depending on your system, instantiating a Path will return either a PosixPath or a WindowsPath object. You can also instantiate a PosixPath or WindowsPath directly, but cannot instantiate a WindowsPath on a POSIX system or vice versa.

stat(*, follow_symlinks=True)

Return the result of the stat() system call on this path, like os.stat() does.

lstat()

Like stat(), except if the path points to a symlink, the symlink’s status information is returned, rather than its target’s.

exists(*, follow_symlinks=True)

Whether this path exists.

This method normally follows symlinks; to check whether a symlink exists, add the argument follow_symlinks=False.

is_dir()

Whether this path is a directory.

is_file()

Whether this path is a regular file (also True for symlinks pointing to regular files).

is_mount()

Check if this path is a mount point

Whether this path is a symbolic link.

is_junction()

Whether this path is a junction.

is_block_device()

Whether this path is a block device.

is_char_device()

Whether this path is a character device.

is_fifo()

Whether this path is a FIFO.

is_socket()

Whether this path is a socket.

samefile(other_path)

Return whether other_path is the same or not as this file (as returned by os.path.samefile()).

open(mode='r', buffering=-1, encoding=None, errors=None, newline=None)

Open the file pointed to by this path and return a file object, as the built-in open() function does.

read_bytes()

Open the file in bytes mode, read it, and close the file.

read_text(encoding=None, errors=None)

Open the file in text mode, read it, and close the file.

write_bytes(data)

Open the file in bytes mode, write to it, and close the file.

write_text(data, encoding=None, errors=None, newline=None)

Open the file in text mode, write to it, and close the file.

iterdir()

Yield path objects of the directory contents.

The children are yielded in arbitrary order, and the special entries ‘.’ and ‘..’ are not included.

glob(pattern, *, case_sensitive=None)

Iterate over this subtree and yield all existing files (of any kind, including directories) matching the given relative pattern.

rglob(pattern, *, case_sensitive=None)

Recursively yield all existing files (of any kind, including directories) matching the given relative pattern, anywhere in this subtree.

walk(top_down=True, on_error=None, follow_symlinks=False)

Walk the directory tree from this directory, similar to os.walk().

classmethod cwd()

Return a new path pointing to the current working directory.

classmethod home()

Return a new path pointing to the user’s home directory (as returned by os.path.expanduser(‘~’)).

absolute()

Return an absolute version of this path by prepending the current working directory. No normalization or symlink resolution is performed.

Use resolve() to get the canonical path to a file.

resolve(strict=False)

Make the path absolute, resolving all symlinks on the way and also normalizing it.

owner()

Return the login name of the file owner.

group()

Return the group name of the file gid.

Return the path to which the symbolic link points.

touch(mode=438, exist_ok=True)

Create this file with the given access mode, if it doesn’t exist.

mkdir(mode=511, parents=False, exist_ok=False)

Create a new directory at this given path.

chmod(mode, *, follow_symlinks=True)

Change the permissions of the path, like os.chmod().

lchmod(mode)

Like chmod(), except if the path points to a symlink, the symlink’s permissions are changed, rather than its target’s.

Remove this file or link. If the path is a directory, use rmdir() instead.

rmdir()

Remove this directory. The directory must be empty.

rename(target)

Rename this path to the target path.

The target path may be absolute or relative. Relative paths are interpreted relative to the current working directory, not the directory of the Path object.

Returns the new Path instance pointing to the target path.

replace(target)

Rename this path to the target path, overwriting if that path exists.

The target path may be absolute or relative. Relative paths are interpreted relative to the current working directory, not the directory of the Path object.

Returns the new Path instance pointing to the target path.

Make this path a symlink pointing to the target path. Note the order of arguments (link, target) is the reverse of os.symlink.

Make this path a hard link pointing to the same file as target.

Note the order of arguments (self, target) is the reverse of os.link’s.

expanduser()

Return a new path with expanded ~ and ~user constructs (as returned by os.path.expanduser)

class astromol.figures.CensusView(db: object, scope: str = 'census', census: str | None = None)

A filtered view of astromol records for a census boundary or live data.

Use for_census() for frozen/historical census outputs and current() for the live database. In census mode, accepted records are selected by history.accepted.census <= census. In current mode, accepted records are selected regardless of census label. Context queries exclude isotopologues by default; pass include_isotopologues=True for isotope-expanded views.

classmethod for_census(db, census: str | int) CensusView

Create a view frozen at a census boundary.

classmethod current(db) CensusView

Create a live view of all currently accepted records.

property is_current: bool

Whether this view represents live database contents.

property census_year: int | None

The integer census boundary, or None for current views.

accepted_record(record) bool

Return whether a molecule or detection is accepted in this view.

introduced_record(record) bool

Return whether a record had entered tracking by this view.

static is_secure(detection: Detection) bool

Return whether a detection is treated as secure.

detection_in_scope(detection: Detection, *, include_tentative: bool = False, include_disputed: bool = False) bool

Return whether a detection belongs in this view.

Secure detections require accepted history. Tentative and disputed detections are included only when requested, and then by introduced history rather than accepted history.

detections(detection_type: str | None = None, *, include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = False) list[Detection]

Return detections in this view, optionally restricted by type.

Isotopologue detections are excluded by default. Set include_isotopologues=True when the expanded isotopologue inventory is wanted.

context_detections(detection_type: str, *, include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = False) list[Detection]

Return detections for one context such as "ISM/CSM".

context_molecules(detection_type: str, *, include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = False) list[Molecule]

Return unique molecules detected in one context.

Isotopologues are excluded by default and can be included with include_isotopologues=True.

accepted_molecules(*, include_isotopologues: bool = False) list[Molecule]

Return molecule records accepted in this view by molecule history.

Isotopologues are excluded by default and can be included with include_isotopologues=True.

ism_detections(**kwargs) list[Detection]

Return ISM/CSM detections in this view.

ism_molecules(**kwargs) list[Molecule]

Return ISM/CSM molecules in this view.

ppd_detections(**kwargs) list[Detection]

Return protoplanetary-disk detections in this view.

ppd_molecules(**kwargs) list[Molecule]

Return protoplanetary-disk molecules in this view.

ice_detections(**kwargs) list[Detection]

Return ice detections in this view.

ice_molecules(**kwargs) list[Molecule]

Return ice molecules in this view.

exgal_detections(**kwargs) list[Detection]

Return extragalactic detections in this view.

exgal_molecules(**kwargs) list[Molecule]

Return extragalactic molecules in this view.

exoplanet_detections(**kwargs) list[Detection]

Return exoplanet-atmosphere detections in this view.

exoplanet_molecules(**kwargs) list[Molecule]

Return exoplanet-atmosphere molecules in this view.

source_counts(detection_type: str = 'ISM/CSM', *, include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = False, key: str = 'nick', group_diffuse_cloud: bool = False, diffuse_cloud_label: str = 'DiffuseCloud') Counter

Count source contributions for detections in this view.

key may be "nick", "name", or "latex_name". Set group_diffuse_cloud=True to consolidate all diffuse-cloud/LOS sources under one label for historical manuscript table reproduction.

facility_counts(detection_type: str = 'ISM/CSM', *, include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = False, key: str = 'nick') Counter

Count telescope/facility contributions for detections in this view.

molecule_labels(molecules: Iterable[Molecule]) set[str]

Return molecule labels from a molecule iterable.

filtered(*, molecule_filter: Callable[[Molecule], bool] | None = None, detection_filter: Callable[[Detection], bool] | None = None) FilteredCensusView

Return a custom view that filters records from this view.

Use this when a standard census/current view is the correct historical boundary, but an analysis should be restricted to a special subset such as carbon-bearing molecules, detections from one source type, or detections observed with one wavelength family.

class astromol.figures.Detection(id: str, molecule: str, sources: list, telescopes: list, wavelengths: list, year: int, type: str, note: str = None, status: str = 'secure', status_note: str = None, first: bool = False, month: int = None, day: int = None, refs: dict = None, confirms: list = <factory>, confirmed_by: list = <factory>, disputes: list = <factory>, disputed_by: list = <factory>, supersedes: list = <factory>, superseded_by: list = <factory>, latex_text: str = None, history: RecordHistory = None)

A specific detection event of a molecule in an astronomical source.

property introduced_census

Census release where this detection entered astromol tracking.

property introduced_context

Context for detection introduction, such as confirmed or tentative.

property accepted_census

Census release where this detection first became accepted/confirmed.

property accepted_context

Context for first accepted/confirmed census membership.

property sortdate

Build a date for sorting/ordering purposes. Uses the 1st for any unknown month or day.

class astromol.figures.DetectionTrend(label: str, start_year: int, stop_year: int | None, slope: float)

Linear trend fitted to a section of a cumulative detection curve.

class astromol.figures.CumulativeDetectionData(years: ndarray, counts: ndarray, first_detection_years: dict[str, int], trends: tuple[DetectionTrend, ...], show_facility_markers: bool = False)

Data needed to plot cumulative detections over time.

property total: int

Final cumulative detection count.

property start_year: int

First year in the cumulative series.

property end_year: int

Last year in the cumulative series.

class astromol.figures.CumulativeByAtomsSeries(category: int | str, label: str, color: str, years: ndarray, counts: ndarray, first_detection_years: dict[str, int])

One cumulative-detection series for an atom-count category.

property final_count: int

Final count for this series.

class astromol.figures.CumulativeByAtomsData(years: ndarray, series: tuple[CumulativeByAtomsSeries, ...])

Data needed to plot cumulative detections grouped by atom count.

property start_year: int

First year in the cumulative series.

property end_year: int

Last year in the cumulative series.

property max_count: int

Largest cumulative count across all plotted series.

property total: int

Total number of molecules counted across all series.

class astromol.figures.RollingRateHeatmapData(years: ndarray, labels: tuple[str, ...], matrix: ndarray, window: int, vmax: float)

Data needed to plot rolling detection rates by atom-count category.

property start_year: int

First year in the rolling-rate series.

property end_year: int

Last year in the rolling-rate series.

class astromol.figures.PeriodicHeatmapCell(symbol: str, atomic_number: int, atomic_mass: float, name: str, group: int, y_position: float, count: int)

One displayed cell in the periodic-table heatmap.

property x_position: float

Left x-coordinate for this periodic-table cell.

class astromol.figures.PeriodicHeatmapData(cells: tuple[PeriodicHeatmapCell, ...], element_counts: dict[str, int], molecule_count: int)

Data needed to plot the elemental-composition periodic heatmap.

property detected_element_count: int

Number of elements present in one or more molecules.

property max_count: int

Largest molecule count for any element.

class astromol.figures.DUHistogramData(values: tuple[float, ...], molecule_labels: tuple[str, ...], formula_labels: tuple[str, ...], molecule_count: int)

Data needed to plot degree-of-unsaturation histograms.

property saturated_count: int

Number of included molecules with DU = 0.

property unsaturated_count: int

Number of included molecules with DU > 0.

property unsaturated_percent: int

Integer unsaturated percentage, matching legacy truncation.

property max_du: float

Largest degree of unsaturation in the sample.

histogram_counts(bins: tuple[float, ...] = (np.float64(-0.25), np.float64(0.25), np.float64(0.75), np.float64(1.25), np.float64(1.75), np.float64(2.25), np.float64(2.75), np.float64(3.25), np.float64(3.75), np.float64(4.25), np.float64(4.75), np.float64(5.25), np.float64(5.75), np.float64(6.25), np.float64(6.75), np.float64(7.25), np.float64(7.75), np.float64(8.25), np.float64(8.75), np.float64(9.25), np.float64(9.75), np.float64(10.25), np.float64(10.75), np.float64(11.25), np.float64(11.75), np.float64(12.25))) ndarray

Return counts in the legacy half-DU-width bins.

property counts_by_value: dict[float, int]

Return exact DU-value counts.

value_counts(*, include_negative_du: bool = True) dict[float, int]

Return exact DU-value counts, optionally excluding domain artifacts.

class astromol.figures.KappaHistogramData(values: tuple[float, ...], molecule_labels: tuple[str, ...], molecule_count: int)

Data needed to plot Ray asymmetry-parameter histograms.

property min_kappa: float

Smallest Ray asymmetry parameter in the sample.

property max_kappa: float

Largest Ray asymmetry parameter in the sample.

histogram_counts(bins: int = 100) ndarray

Return histogram counts using the legacy integer-bin convention.

class astromol.figures.MoleculeTypeCategory(key: str, label: str, plural_label: str, color: str, percent_color: str, count: int, fraction: float)

One molecule-type category used by the type ring chart.

property percent: float

Category percentage of the molecule sample.

class astromol.figures.MoleculeTypeData(categories: tuple[MoleculeTypeCategory, ...], molecule_count: int)

Data needed to plot the molecule-type ring chart.

property counts: dict[str, int]

Category counts keyed by short category name.

property fractions: dict[str, float]

Category fractions keyed by short category name.

class astromol.figures.SourceTypeCategory(key: str, label: str, color: str, count: int, fraction: float, label_y: float, percent_y: float)

One generalized first-detection source category.

property percent: float

Category percentage of the molecule sample.

class astromol.figures.SourceTypeData(categories: tuple[SourceTypeCategory, ...], molecule_count: int)

Data needed to plot the generalized source-type ring chart.

property counts: dict[str, int]

Generalized source-type counts keyed by category name.

property fractions: dict[str, float]

Generalized source-type fractions keyed by category name.

class astromol.figures.IndividualSourceData(categories: tuple[SourceTypeCategory, ...], molecule_count: int)

Data needed to plot the individual first-detection source ring chart.

property counts: dict[str, int]

Individual-source contribution counts keyed by category name.

property fractions: dict[str, float]

Individual-source contribution fractions keyed by category name.

class astromol.figures.MoleculeTypesForSource(key: str, label: str, source_count: int, counts_by_type: dict[str, int])

Molecule-type counts credited to one generalized first-detection source.

property total_type_count: int

Total molecule-type credits in this source category.

class astromol.figures.MoleculeTypeBySourceData(categories: tuple[MoleculeTypesForSource, ...], molecule_count: int, overall_type_counts: dict[str, int])

Data needed to plot molecule-type mixes by source category.

property counts: dict[str, dict[str, int]]

Nested counts keyed first by source category and then molecule type.

property source_counts: dict[str, int]

Source-category molecule counts keyed by source category.

class astromol.figures.DUBySourceTypeCategory(key: str, label: str, color: str, values: tuple[float, ...])

DU values credited to one generalized first-detection source category.

property count: int

Number of DU values in this source category.

class astromol.figures.DUBySourceTypeData(categories: tuple[DUBySourceTypeCategory, ...], molecule_count: int)

Data needed to plot DU distributions by generalized source category.

property counts: dict[str, int]

DU-value counts keyed by generalized source category.

property values_by_source: dict[str, tuple[float, ...]]

DU values keyed by generalized source category.

class astromol.figures.RelativeDUBySourceTypeCategory(key: str, label: str, color: str, values: tuple[float, ...])

Relative-DU values credited to one generalized source category.

property count: int

Number of relative-DU values in this source category.

class astromol.figures.RelativeDUBySourceTypeData(categories: tuple[RelativeDUBySourceTypeCategory, ...], molecule_count: int)

Data needed to plot relative-DU distributions by source category.

property counts: dict[str, int]

Relative-DU value counts keyed by source category.

property values_by_source: dict[str, tuple[float, ...]]

Relative-DU values keyed by source category.

class astromol.figures.MassBySourceTypeCategory(key: str, label: str, color: str, masses: tuple[float, ...])

Molecular masses credited to one generalized source category.

property count: int

Number of molecular masses in this source category.

class astromol.figures.MassBySourceTypeData(categories: tuple[MassBySourceTypeCategory, ...], molecule_count: int, mass_range: tuple[float, float])

Data needed to plot molecular-mass distributions by source category.

property counts: dict[str, int]

Molecular-mass counts keyed by generalized source category.

property masses_by_source: dict[str, tuple[float, ...]]

Molecular masses keyed by generalized source category.

class astromol.figures.WavelengthBySourceTypeCategory(key: str, label: str, counts_by_wavelength: dict[str, int])

First-detection wavelength counts for one source category.

property count: int

Total wavelength credits in this source category.

count_for_display_wavelength(wavelength: str) int

Return counts for a displayed wavelength, combining UV/Vis if needed.

class astromol.figures.WavelengthBySourceTypeData(categories: tuple[WavelengthBySourceTypeCategory, ...], molecule_count: int)

Data needed to plot wavelength mixes by source category.

property counts: dict[str, dict[str, int]]

Nested counts keyed first by source category, then wavelength.

class astromol.figures.MassByWavelengthSeries(key: str, label: str, color: str, masses: tuple[float, ...], annotation_xy: tuple[float, float], truncate_at_data_max: bool = False, zorder: int | None = None)

Molecular masses contributing to one wavelength KDE trace.

property count: int

Number of molecule masses in the wavelength sample.

class astromol.figures.MassByWavelengthData(series: tuple[MassByWavelengthSeries, ...], molecule_count: int)

Data needed to plot molecular mass distributions by wavelength.

property counts: dict[str, int]

Sample counts keyed by wavelength label.

class astromol.figures.MoleculesByWavelengthAtomsSeries(key: str, label: str, plot: str, atom_counts: tuple[int, ...])

Atom counts contributing to one wavelength-panel distribution.

property count: int

Number of molecules in this wavelength sample.

class astromol.figures.MoleculesByWavelengthAtomsData(series: tuple[MoleculesByWavelengthAtomsSeries, ...], molecule_count: int)

Data needed to plot atom-count distributions by detection wavelength.

property counts: dict[str, int]

Sample counts keyed by wavelength label.

property max_atoms: int

Largest atom count in any wavelength sample.

matrix(bins: tuple[int | str, ...] = (2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, '13+')) ndarray

Return wavelength-by-atom-count matrix for discrete heatmaps.

class astromol.figures.DetectionRateByAtomsPoint(category: int | str, label: str, x_position: float, count: int, first_year: int | None, rate: float)

One average detection-rate point for an atom-count category.

class astromol.figures.DetectionRateByAtomsData(end_year: int, points: tuple[DetectionRateByAtomsPoint, ...])

Data needed to plot average detection rate by atom-count category.

property visible_points: tuple[DetectionRateByAtomsPoint, ...]

Return points visible in the legacy 2-12 atom x-axis range.

class astromol.figures.FacilityShare(nick: str, label: str, start_year: int, end_year: int, detection_count: int, total_window_detections: int, active_at_view: bool)

One facility’s share of first detections during its operating window.

property fraction: float

Facility contribution fraction during its operating window.

property percent: int

Integer percentage label, matching legacy truncation.

class astromol.figures.FacilityShareData(end_year: int, facilities: tuple[FacilityShare, ...])

Data needed to plot facility shares.

class astromol.figures.ScopeDetectionSeries(nick: str, label: str, start_year: int, fit_stop_year: int, color: str, years: ndarray, counts: ndarray, detection_count: int, rate: float)

Cumulative first-detection contribution series for one facility.

property final_count: int

Final cumulative contribution count.

class astromol.figures.ScopesByYearData(years: ndarray, series: tuple[ScopeDetectionSeries, ...], end_year: int)

Data needed to plot cumulative facility contributions over time.

property max_count: int

Largest final cumulative contribution count.

astromol.figures.first_detections_by_molecule(view: CensusView, detection_type: str = 'ISM/CSM', *, include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = False) dict[str, Detection]

Return the first detection record for each molecule in a view.

astromol.figures.first_detection_years_by_molecule(view: CensusView, detection_type: str = 'ISM/CSM', *, include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = False) dict[str, int]

Return the first detection year for each molecule in a view.

astromol.figures.cumulative_by_atoms_series_specs(view: CensusView) tuple[dict[str, object], ...]

Return the default atom-count palette for a census/current view.

Legacy 2018/2021 reproduction views keep the original census palette. Current and future-facing views use the color-blind-friendly palette.

astromol.figures.cumulative_by_atoms_data(view: CensusView, detection_type: str = 'ISM/CSM', *, start_year: int | None = None, end_year: int | None = None, include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = False, series_specs: tuple[dict[str, object], ...] | None = None) CumulativeByAtomsData

Return cumulative-detection data grouped by atom-count category.

The default grouping follows the legacy figure: 2-12 atoms, a true 13+ category excluding PAHs and fullerenes, and separate PAH/fullerene traces.

astromol.figures.annual_detection_counts(first_detection_years: dict[str, int], years: ndarray) ndarray

Return annual first-detection counts over fixed plot years.

astromol.figures.trailing_rolling_detection_rate(first_detection_years: dict[str, int], years: ndarray, *, window: int = 10) ndarray

Return trailing rolling detection rates in detections per year.

A 10-year value at 2026 counts detections from 2017 through 2026 and divides by 10. The fixed denominator keeps rates comparable across years.

astromol.figures.rolling_rate_by_atoms_heatmap_data(view: CensusView, detection_type: str = 'ISM/CSM', *, start_year: int | None = None, end_year: int | None = None, include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = False, series_specs: tuple[dict[str, object], ...] | None = None, window: int = 10, vmax: float = 2.0) RollingRateHeatmapData

Return rolling detection-rate heatmap data grouped by atom count.

astromol.figures.periodic_heatmap_data(view: CensusView, detection_type: str = 'ISM/CSM', *, include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = False) PeriodicHeatmapData

Return element-composition counts for the periodic-table heatmap.

astromol.figures.du_histogram_data(view: CensusView, detection_type: str = 'ISM/CSM', *, include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = False, include_fullerenes: bool = False) DUHistogramData

Return degree-of-unsaturation values for the legacy histogram domain.

astromol.figures.kappa_histogram_data(view: CensusView, detection_type: str = 'ISM/CSM', *, include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = False) KappaHistogramData

Return Ray asymmetry-parameter values for molecules with A/B/C constants.

astromol.figures.molecule_type_data(view: CensusView, detection_type: str = 'ISM/CSM', *, include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = False) MoleculeTypeData

Return molecule-type category counts for a census view.

Categories are counted independently, so one molecule may contribute to more than one category. This preserves the legacy manuscript convention used for neutral radical species, cyclic ions, PAHs, and fullerenes.

astromol.figures.source_type_data(view: CensusView, detection_type: str = 'ISM/CSM', *, include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = False) SourceTypeData

Return generalized first-detection source-type counts for a view.

Each molecule can receive credit for multiple source categories if its first detection lists sources in multiple categories, but it is credited at most once per generalized category.

astromol.figures.individual_source_data(view: CensusView, detection_type: str = 'ISM/CSM', *, include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = False) IndividualSourceData

Return individual first-detection source contribution counts.

This preserves the legacy convention: each listed source on a first detection contributes one count. The four named sources are counted individually; every other source contribution is counted in Other. The denominator remains the number of first-detected molecules, so percentages may sum to more than 100%.

astromol.figures.molecule_type_by_source_type_data(view: CensusView, detection_type: str = 'ISM/CSM', *, include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = False) MoleculeTypeBySourceData

Return molecule-type counts for generalized first-detection sources.

Source categories are credited once per molecule. Molecule-type categories are counted independently within each source category, preserving the legacy convention that a molecule can contribute to multiple type wedges.

astromol.figures.du_by_source_type_data(view: CensusView, detection_type: str = 'ISM/CSM', *, include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = False, include_fullerenes: bool = False) DUBySourceTypeData

Return DU values grouped by generalized first-detection source type.

Each molecule is credited at most once per source category, matching the legacy convention used for source-type trend figures. Fullerenes are excluded by default because their extreme DU values dominate this comparison.

astromol.figures.relative_du_by_source_type_data(view: CensusView, detection_type: str = 'ISM/CSM', *, include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = False, include_fullerenes: bool = False) RelativeDUBySourceTypeData

Return relative-DU values grouped by first-detection source type.

Relative DU is defined as du / maxdu using the same formula-domain convention as the legacy code. Each molecule is credited at most once per source category.

astromol.figures.mass_by_source_type_data(view: CensusView, detection_type: str = 'ISM/CSM', *, include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = False, include_fullerenes: bool = False) MassBySourceTypeData

Return molecular masses grouped by generalized first-detection source.

Each molecule is credited at most once per source category, matching the legacy source-type figures. Fullerenes are excluded by default because their masses dominate this comparison.

astromol.figures.wavelength_by_source_type_data(view: CensusView, detection_type: str = 'ISM/CSM', *, include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = False, include_fullerenes: bool = True) WavelengthBySourceTypeData

Return first-detection wavelength counts by generalized source type.

Each molecule is credited at most once per source category, matching the legacy source/wavelength pie-grid convention. Within a credited source category, every wavelength listed for the first detection is counted.

astromol.figures.mass_by_wavelength_data(view: CensusView, detection_type: str = 'ISM/CSM', *, include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = False, include_fullerenes: bool = True) MassByWavelengthData

Return molecular masses grouped by first-detection wavelength.

astromol.figures.molecules_by_wavelength_atoms_data(view: CensusView, detection_type: str = 'ISM/CSM', *, include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = False, include_fullerenes: bool = False) MoleculesByWavelengthAtomsData

Return molecule atom counts grouped by first-detection wavelength.

astromol.figures.detection_rate_by_atoms_data(view: CensusView, detection_type: str = 'ISM/CSM', *, end_year: int | None = None, include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = False, categories: tuple[dict[str, object], ...] = ({'category': 2, 'label': '2', 'x': 2}, {'category': 3, 'label': '3', 'x': 3}, {'category': 4, 'label': '4', 'x': 4}, {'category': 5, 'label': '5', 'x': 5}, {'category': 6, 'label': '6', 'x': 6}, {'category': 7, 'label': '7', 'x': 7}, {'category': 8, 'label': '8', 'x': 8}, {'category': 9, 'label': '9', 'x': 9}, {'category': 10, 'label': '10', 'x': 10}, {'category': 11, 'label': '11', 'x': 11}, {'category': 12, 'label': '12', 'x': 12}, {'category': '13+', 'label': '13+', 'x': 13}, {'category': 'PAHs', 'label': 'PAHs', 'x': 15}, {'category': 'Fullerenes', 'label': 'Fullerenes', 'x': 17})) DetectionRateByAtomsData

Return average detections/year by atom-count category.

The rate is the number of first detections in a category divided by the number of years from that category’s first detection through end_year. This matches the legacy det_per_year_per_atom figure definition.

astromol.figures.facility_share_data(view: CensusView, detection_type: str = 'ISM/CSM', *, end_year: int | None = None, top_n: int = 9, facility_nicks: tuple[str, ...] | None = None, include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = False, use_legacy_2021_selection: bool = True) FacilityShareData

Return facility-share data for first molecule detections.

Facilities are ranked by their number of first detections, then displayed by descending share of all first detections that occurred during their operational window. The 2021 published figure used a facility set that is preserved when use_legacy_2021_selection is true.

astromol.figures.scopes_by_year_data(view: CensusView, detection_type: str = 'ISM/CSM', *, start_year: int = 1965, end_year: int | None = None, min_detections: int = 10, include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = False, cutoffs: dict[str, int] | None = None, colors_by_shortname: dict[str, str] | None = None) ScopesByYearData

Return cumulative facility first-detection contributions by year.

astromol.figures.cumulative_counts_by_year(first_detection_years: dict[str, int], *, start_year: int | None = None, end_year: int | None = None) tuple[ndarray, ndarray]

Return cumulative detection counts for each year in a range.

astromol.figures.linear_cumulative_rate(years: ndarray, counts: ndarray, *, start_year: int, stop_year: int | None = None) float

Fit a linear cumulative-detection rate over a year range.

stop_year is included in the fit. This makes plot annotations read as closed date ranges, such as 1968-2005 and 2005-2021.

astromol.figures.cumulative_detection_trend_ranges(view: CensusView, end_year: int) tuple[tuple[str, int, int | None], ...]

Return census-aware trend ranges for cumulative-detection plots.

astromol.figures.cumulative_detection_data(view: CensusView, detection_type: str = 'ISM/CSM', *, start_year: int | None = None, end_year: int | None = None, include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = False) CumulativeDetectionData

Return cumulative-detection data for a census view.

By default, the data represent secure, non-isotopologue ISM/CSM molecule detections. For census views, the default end year is the census boundary; for current views, it is the current calendar year.

astromol.figures.plot_cumulative_detections(data: CumulativeDetectionData, *, ax=None, color: str = 'dodgerblue', linewidth: float = 4, annotate_trends: bool = True, annotate_total: bool = True, annotate_facilities: bool | None = None, text_size: int = 24)

Plot cumulative detections and return (figure, axes).

astromol.figures.write_cumulative_detections_plot(data: CumulativeDetectionData, output_path: str | Path, *, file_format: str | None = None) Path

Write the cumulative-detections plot and return the output path.

astromol.figures.plot_cumulative_by_atoms(data: CumulativeByAtomsData, *, ax=None, linewidth: float = 2.5, text_size: int = 24, legend_text_size: int = 16, legend_x: float = 0.1, legend_y: float = 0.92, legend_step: float = 0.04, y_axis_padding_fraction: float = 0.05)

Plot cumulative ISM/CSM detections grouped by atom-count category.

astromol.figures.write_cumulative_by_atoms_plot(data: CumulativeByAtomsData, output_path: str | Path, *, file_format: str | None = None) Path

Write the cumulative-by-atoms plot and return the output path.

astromol.figures.plot_stacked_cumulative_by_atoms(data: CumulativeByAtomsData, *, ax=None, text_size: int = 24, legend_text_size: int = 16, legend_x: float = 0.1, legend_y: float = 0.92, legend_step: float = 0.04, stack_alpha: float = 0.88, y_axis_padding_fraction: float = 0.04)

Plot cumulative ISM/CSM detections as a stacked atom-count history.

astromol.figures.write_stacked_cumulative_by_atoms_plot(data: CumulativeByAtomsData, output_path: str | Path, *, file_format: str | None = None) Path

Write the stacked cumulative-by-atoms plot and return the output path.

astromol.figures.plot_periodic_heatmap(data: PeriodicHeatmapData, *, ax=None, figure_size: tuple[float, float] = (20, 9.5))

Plot a periodic-table heatmap of element occurrence in molecules.

astromol.figures.write_periodic_heatmap(data: PeriodicHeatmapData, output_path: str | Path, *, file_format: str | None = None) Path

Write the periodic-table heatmap and return the output path.

astromol.figures.plot_du_histogram(data: DUHistogramData, *, ax=None, bins: tuple[float, ...] | None = None, text_size: int = 24, annotation_size: int = 16, facecolor: str = 'dodgerblue', edgecolor: str = 'royalblue', alpha: float = 0.25)

Plot the legacy degree-of-unsaturation histogram.

astromol.figures.write_du_histogram(data: DUHistogramData, output_path: str | Path, *, file_format: str | None = None) Path

Write the degree-of-unsaturation histogram and return the output path.

astromol.figures.plot_kappa_histogram(data: KappaHistogramData, *, ax=None, bins: int = 100, figure_size: tuple[float, float] = (8.0, 4.8), text_size: int = 24, facecolor: str = 'dodgerblue', edgecolor: str = 'dodgerblue', alpha: float = 0.25, show_shape_guide: bool = True)

Plot the Ray asymmetry-parameter histogram.

astromol.figures.write_kappa_histogram(data: KappaHistogramData, output_path: str | Path, *, bins: int = 100, file_format: str | None = None) Path

Write the Ray asymmetry-parameter histogram and return the output path.

astromol.figures.plot_du_bar_chart(data: DUHistogramData, *, ax=None, text_size: int = 24, annotation_size: int = 16, facecolor: str = 'dodgerblue', edgecolor: str = 'black', alpha: float = 0.65, bar_width: float = 0.32, include_negative_du: bool = False)

Plot exact degree-of-unsaturation counts as a discrete bar chart.

astromol.figures.write_du_bar_chart(data: DUHistogramData, output_path: str | Path, *, file_format: str | None = None) Path

Write the exact-value degree-of-unsaturation bar chart.

astromol.figures.plot_type_pie_chart(data: MoleculeTypeData, *, ax=None, figure_size: tuple[float, float] = (10, 8), ring_width: float = 0.1, ring_gap: float = 0.02, label_text_size: int = 13, label_y_offsets: tuple[float, ...] | None = None, percent_text_size: int = 11, remainder_color: str = '#EEEEEE', order: str = 'count')

Plot the molecule-type concentric ring chart.

astromol.figures.write_type_pie_chart(data: MoleculeTypeData, output_path: str | Path, *, file_format: str | None = None, order: str = 'count') Path

Write the molecule-type ring chart and return the output path.

astromol.figures.plot_source_pie_chart(data: SourceTypeData, *, ax=None, figure_size: tuple[float, float] = (10, 8), ring_width: float = 0.1, ring_gap: float = 0.02, label_text_size: int = 14, percent_text_size: int = 12, remainder_color: str = '#EEEEEE', diffuse_cloud_label: str = 'Diffuse Cloud', order: str = 'count')

Plot the generalized source-type concentric ring chart.

astromol.figures.write_source_pie_chart(data: SourceTypeData, output_path: str | Path, *, file_format: str | None = None, diffuse_cloud_label: str = 'Diffuse Cloud', pad_inches: float = -0.65, order: str = 'count') Path

Write the generalized source-type ring chart and return the path.

astromol.figures.plot_individual_source_pie_chart(data: IndividualSourceData, *, ax=None, figure_size: tuple[float, float] = (10, 8), ring_width: float = 0.1, ring_gap: float = 0.02, label_text_size: int = 14, percent_text_size: int = 12, remainder_color: str = '#EEEEEE', order: str = 'count')

Plot the individual first-detection source concentric ring chart.

astromol.figures.write_individual_source_pie_chart(data: IndividualSourceData, output_path: str | Path, *, file_format: str | None = None, pad_inches: float = -0.65, order: str = 'count') Path

Write the individual-source ring chart and return the path.

astromol.figures.plot_molecule_type_by_source_type(data: MoleculeTypeBySourceData, *, figure_size: tuple[float, float] = (15, 12), label_text_size: int = 26, title_text_size: int = 30, legend_text_size: int = 26, wedge_alpha: float = 0.5, source_label_overrides: dict[str, str] | None = None)

Plot molecule-type pie charts within generalized source categories.

astromol.figures.write_molecule_type_by_source_type(data: MoleculeTypeBySourceData, output_path: str | Path, *, file_format: str | None = None, source_label_overrides: dict[str, str] | None = None) Path

Write the molecule-type-by-source pie grid and return the path.

astromol.figures.plot_molecule_type_by_source_enrichment_matrix(data: MoleculeTypeBySourceData, *, figure_size: tuple[float, float] = (12, 8), axes_bounds: tuple[float, float, float, float] = (0.205, 0.15, 0.62, 0.775), colorbar_bounds: tuple[float, float, float, float] = (0.86, 0.15, 0.035, 0.775), source_label_overrides: dict[str, str] | None = None, text_size: int = 24, factor_text_size: int = 21, count_text_size: int = 17, depletion_limit: float = 0.25, enrichment_limit: float = 4.0)

Plot the production molecule-type/source enrichment matrix.

Cell values are fractional enrichments relative to the overall secure ISM/CSM molecule-type mix. Color is log-scaled and centered on 1x.

astromol.figures.write_molecule_type_by_source_enrichment_matrix(data: MoleculeTypeBySourceData, output_path: str | Path, *, file_format: str | None = None, source_label_overrides: dict[str, str] | None = None) Path

Write the production molecule-type/source enrichment matrix.

astromol.figures.plot_du_by_source_type(data: DUBySourceTypeData, *, ax=None, bandwidth: float = 0.5, figure_size: tuple[float, float] = (10, 8), text_size: int = 24, source_label_overrides: dict[str, str] | None = None, count_label_overrides: dict[str, tuple[float, float]] | None = None, ylabel: str = 'Probability Density Estimate')

Plot DU KDE distributions by generalized first-detection source type.

astromol.figures.write_du_by_source_type(data: DUBySourceTypeData, output_path: str | Path, *, bandwidth: float = 0.5, source_label_overrides: dict[str, str] | None = None, count_label_overrides: dict[str, tuple[float, float]] | None = None, ylabel: str = 'Probability Density Estimate', file_format: str | None = None) Path

Write the DU-by-source KDE plot and return the output path.

astromol.figures.plot_relative_du_by_source_type(data: RelativeDUBySourceTypeData, *, axes=None, bandwidth: float = 0.5, figure_size: tuple[float, float] = (10, 8), text_size: int = 18, label_size: int = 24, source_label_overrides: dict[str, str] | None = None)

Plot the legacy relative-DU KDE panel by source type.

astromol.figures.write_relative_du_by_source_type(data: RelativeDUBySourceTypeData, output_path: str | Path, *, bandwidth: float = 0.5, source_label_overrides: dict[str, str] | None = None, file_format: str | None = None) Path

Write the relative-DU-by-source KDE plot and return the output path.

astromol.figures.plot_mass_by_source_type(data: MassBySourceTypeData, *, ax=None, bandwidth: float = 0.5, figure_size: tuple[float, float] = (10, 8), text_size: int = 24, source_label_overrides: dict[str, str] | None = None)

Plot legacy molecular-mass KDE distributions by source type.

astromol.figures.write_mass_by_source_type(data: MassBySourceTypeData, output_path: str | Path, *, bandwidth: float = 0.5, source_label_overrides: dict[str, str] | None = None, file_format: str | None = None) Path

Write the mass-by-source KDE plot and return the output path.

astromol.figures.plot_wavelength_by_source_type(data: WavelengthBySourceTypeData, *, axes=None, figure_size: tuple[float, float] = (15, 12), text_size: int = 26, panel_label_size: int = 30, source_label_overrides: dict[str, str] | None = None)

Plot the legacy wavelength-by-source-type pie grid.

astromol.figures.write_wavelength_by_source_type(data: WavelengthBySourceTypeData, output_path: str | Path, *, source_label_overrides: dict[str, str] | None = None, file_format: str | None = None) Path

Write the wavelength-by-source-type pie grid and return the path.

astromol.figures.plot_wavelength_by_source_type_stacked_bar(data: WavelengthBySourceTypeData, *, ax=None, figure_size: tuple[float, float] = (8.0, 4.8), text_size: float = 18.0, tick_size: float = 16.0, segment_text_size: float = 13.0, show_segment_labels: bool = False, source_label_overrides: dict[str, str] | None = None)

Plot wavelength shares by source type as normalized stacked bars.

astromol.figures.write_wavelength_by_source_type_stacked_bar(data: WavelengthBySourceTypeData, output_path: str | Path, *, source_label_overrides: dict[str, str] | None = None, file_format: str | None = None) Path

Write the production wavelength/source stacked bar chart.

astromol.figures.plot_mass_by_wavelength(data: MassByWavelengthData, *, ax=None, bandwidth: float = 0.5, figure_size: tuple[float, float] = (10, 8), text_size: int = 24, legend_step: float = 0.05, label_mode: str = 'fixed', label_overrides: dict[str, tuple[float, float]] | None = None)

Plot KDE molecular-mass distributions by detection wavelength.

astromol.figures.write_mass_by_wavelength_plot(data: MassByWavelengthData, output_path: str | Path, *, bandwidth: float = 0.5, label_mode: str = 'fixed', label_overrides: dict[str, tuple[float, float]] | None = None, file_format: str | None = None) Path

Write the mass-by-wavelength KDE plot and return the output path.

astromol.figures.plot_mass_by_wavelength_boxplot(data: MassByWavelengthData, *, ax=None, figure_size: tuple[float, float] = (7.2, 4.8), text_size: float = 18.0, tick_size: float = 16.0, point_size: float = 22.0, point_alpha: float = 0.34, x_limit: tuple[float, float] = (0, 240), marker_mass: float = 80.0)

Plot wavelength mass distributions as horizontal boxes plus detections.

astromol.figures.write_mass_by_wavelength_boxplot(data: MassByWavelengthData, output_path: str | Path, *, file_format: str | None = None) Path

Write the production mass-by-wavelength boxplot and return the path.

astromol.figures.plot_du_by_source_type_boxplot(data: DUBySourceTypeData, *, ax=None, figure_size: tuple[float, float] = (7.2, 4.8), text_size: float = 18.0, tick_size: float = 16.0, point_size: float = 22.0, point_alpha: float = 0.34, include_negative_du: bool = False, x_limit: tuple[float, float] | None = None, source_label_overrides: dict[str, str] | None = None)

Plot DU distributions by source type as boxes plus exact detections.

astromol.figures.write_du_by_source_type_boxplot(data: DUBySourceTypeData, output_path: str | Path, *, include_negative_du: bool = False, source_label_overrides: dict[str, str] | None = None, file_format: str | None = None) Path

Write the production DU-by-source box/strip plot and return the path.

astromol.figures.plot_relative_du_by_source_type_boxplot(data: RelativeDUBySourceTypeData, *, ax=None, figure_size: tuple[float, float] = (7.2, 4.8), text_size: float = 18.0, tick_size: float = 16.0, point_size: float = 22.0, point_alpha: float = 0.34, include_negative_du: bool = False, x_limit: tuple[float, float] | None = None, source_label_overrides: dict[str, str] | None = None)

Plot relative-DU source distributions as boxes plus exact values.

astromol.figures.write_relative_du_by_source_type_boxplot(data: RelativeDUBySourceTypeData, output_path: str | Path, *, include_negative_du: bool = False, source_label_overrides: dict[str, str] | None = None, file_format: str | None = None) Path

Write the production relative-DU source box/strip plot.

astromol.figures.plot_mass_by_source_type_boxplot(data: MassBySourceTypeData, *, ax=None, figure_size: tuple[float, float] = (7.2, 4.8), text_size: float = 18.0, tick_size: float = 16.0, point_size: float = 22.0, point_alpha: float = 0.34, x_limit: tuple[float, float] | None = None, source_label_overrides: dict[str, str] | None = None)

Plot source-type mass distributions as boxes plus exact detections.

astromol.figures.write_mass_by_source_type_boxplot(data: MassBySourceTypeData, output_path: str | Path, *, source_label_overrides: dict[str, str] | None = None, file_format: str | None = None) Path

Write the production mass-by-source box/strip plot.

astromol.figures.plot_molecules_by_wavelength_atoms(data: MoleculesByWavelengthAtomsData, *, axes=None, bandwidth: float = 0.5, figure_size: tuple[float, float] = (10, 8), trace_color: str = 'dodgerblue', text_size: int = 18, panel_label_size: int = 24)

Plot atom-count distributions grouped by first-detection wavelength.

astromol.figures.write_molecules_by_wavelength_atoms_plot(data: MoleculesByWavelengthAtomsData, output_path: str | Path, *, bandwidth: float = 0.5, file_format: str | None = None) Path

Write the atom-count-by-wavelength plot and return the output path.

astromol.figures.plot_molecules_by_wavelength_atoms_bubble_heatmap(data: MoleculesByWavelengthAtomsData, *, ax=None, colorbar_ax=None, value_mode: str = 'count', figure_size: tuple[float, float] = (7.2, 4.8), text_size: float = 18.0, tick_size: float = 16.0, value_text_size: float = 12.0, colorbar_text_size: float = 12.0, min_bubble_size: float = 85.0, max_bubble_size: float = 1300.0, value_text_y_offset: float = 0.025)

Plot atom-count/wavelength counts as a discrete bubble heatmap.

astromol.figures.write_molecules_by_wavelength_atoms_bubble_heatmap(data: MoleculesByWavelengthAtomsData, output_path: str | Path, *, file_format: str | None = None, value_mode: str = 'count') Path

Write the production atom-count/wavelength bubble heatmap.

astromol.figures.plot_rolling_rate_by_atoms_heatmap(data: RollingRateHeatmapData, *, ax=None, colorbar_ax=None, cmap: str = 'cividis', text_size: float = 8.5, tick_size: float = 7.2, colorbar_text_size: float = 7.2)

Plot rolling detection rates by atom-count category as a heatmap.

astromol.figures.write_rolling_rate_by_atoms_heatmap(data: RollingRateHeatmapData, output_path: str | Path, *, file_format: str | None = None) Path

Write the rolling-rate-by-atoms heatmap and return the output path.

astromol.figures.plot_detection_rate_by_atoms(data: DetectionRateByAtomsData, *, ax=None, facecolor: str = 'dodgerblue', edgecolor: str = '#0A1589', alpha: float = 0.9, text_size: int = 24, xlim: tuple[float, float] = (1, 12.8), ylim: tuple[float, float] | None = None)

Plot average detections/year by atom-count category.

astromol.figures.write_detection_rate_by_atoms_plot(data: DetectionRateByAtomsData, output_path: str | Path, *, file_format: str | None = None) Path

Write the detection-rate-by-atoms plot and return the output path.

astromol.figures.plot_detection_rate_by_atoms_comparison(current_data: DetectionRateByAtomsData, baseline_data: DetectionRateByAtomsData, *, ax=None, current_label: str = 'Current', baseline_label: str = '2021', marker_area_per_detection: float = 70, current_facecolor: str = 'dodgerblue', current_edgecolor: str = '#0A1589', baseline_edgecolor: str = 'black', current_alpha: float = 0.86, text_size: int = 24, legend_text_size: int = 18, xlim: tuple[float, float] = (1, 12.8), ylim: tuple[float, float] = (0, 1.0))

Plot current rate-by-atoms values over a 2021 comparison baseline.

Marker area uses a single absolute scale for both datasets, so area is directly comparable between the baseline and current views.

astromol.figures.write_detection_rate_by_atoms_comparison_plot(current_data: DetectionRateByAtomsData, baseline_data: DetectionRateByAtomsData, output_path: str | Path, *, file_format: str | None = None, current_label: str = 'Current', baseline_label: str = '2021') Path

Write the production detection-rate-by-atoms comparison plot.

astromol.figures.plot_facility_shares(data: FacilityShareData, *, axes=None, active_color: str = 'dodgerblue', inactive_color: str = '#F87070', remainder_color: str = '#F5F6FF', title_text_size: int = 17, date_text_size: int = 14, percent_text_size: int = 15, figure_size: tuple[float, float] = (8, 8), pie_radius: float = 0.9)

Plot facility shares as a 3x3 pie grid.

astromol.figures.write_facility_shares_plot(data: FacilityShareData, output_path: str | Path, *, file_format: str | None = None) Path

Write the facility-shares plot and return the output path.

astromol.figures.plot_facility_share_bars(data: FacilityShareData, *, ax=None, active_color: str = 'dodgerblue', inactive_color: str = '#F87070', figure_size: tuple[float, float] = (7.2, 4.8), axes_bounds: tuple[float, float, float, float] = (0.23, 0.15, 0.735, 0.82), label_text_size: int = 10, value_text_size: int = 10, axis_text_size: int = 10, tick_text_size: int = 9, legend_text_size: int = 9)

Plot facility shares as a horizontal bar chart.

This is the production-facing facility-share view. The pie-grid function is retained for legacy reproduction, while this bar view is easier to compare quantitatively and labels each denominator explicitly.

astromol.figures.write_facility_share_bars_plot(data: FacilityShareData, output_path: str | Path, *, file_format: str | None = None) Path

Write the facility-share bar chart and return the output path.

astromol.figures.plot_scopes_by_year(data: ScopesByYearData, *, ax=None, figure_size: tuple[float, float] = (10, 8), axes_bounds: tuple[float, float, float, float] = (0.14, 0.13, 0.82, 0.82), text_size: int = 24, annotation_text_size: int = 18, line_width: float = 2.0, style: str = 'legacy')

Plot cumulative first-detection contributions for prolific facilities.

astromol.figures.write_scopes_by_year_plot(data: ScopesByYearData, output_path: str | Path, *, file_format: str | None = None, style: str = 'legacy') Path

Write the scopes-by-year plot and return the output path.

PowerPoint slide generation helpers for census products.

The slide code is intentionally split into selection, layout, and rendering steps. That makes the visually tuned PowerPoint output auditable before it is written to a binary .pptx file.

class astromol.slides.SlideBox(left: float, top: float, width: float, height: float)

A PowerPoint box expressed in slide inches.

property right: float

Right edge in inches.

property bottom: float

Bottom edge in inches.

class astromol.slides.FormulaRun(text: str, baseline: str = 'normal', italic: bool = False)

One formatted PowerPoint text run for a molecule formula.

class astromol.slides.SlideMoleculeEntry(molecule: Molecule, display_formula: str)

A molecule selected for a slide, with display metadata.

property label: str

Stable molecule label.

property natoms: int

Number of atoms in the molecule.

class astromol.slides.SlideGroupSpec(label: str, natoms: int, ncols: int, label_box: SlideBox, column_boxes: tuple[SlideBox, ...], natoms_greater: bool = False)

Static layout specification for one atom-count group.

class astromol.slides.SlideColumnPlan(box: SlideBox, molecules: tuple[SlideMoleculeEntry, ...], estimated_capacity: int)

Molecules assigned to one rendered column.

property overflow: int

Estimated number of rows beyond the column capacity.

class astromol.slides.SlideGroupPlan(spec: SlideGroupSpec, columns: tuple[SlideColumnPlan, ...])

Rendered plan for one atom-count group.

property molecules: tuple[SlideMoleculeEntry, ...]

All molecules in this group.

class astromol.slides.MoleculeSlideLayout(groups: tuple[~astromol.slides.SlideGroupPlan, ...], title: str, total: int, profile: str = 'legacy', slide_width_pt: int = 1920, slide_height_pt: int = 1080, title_box: ~astromol.slides.SlideBox = SlideBox(left=0.35, top=0.22, width=18.33, height=1.18), credit_box: ~astromol.slides.SlideBox = SlideBox(left=22.15, top=0.22, width=4.166666666666667, height=1.25), total_box: ~astromol.slides.SlideBox = SlideBox(left=6.35, top=10.6, width=6.0, height=1.4), footer_box: ~astromol.slides.SlideBox = SlideBox(left=6.35, top=12.2, width=6.0, height=1.0), molecule_font_pt: float = 22, group_label_font_pt: float = 26, total_font_pt: float = 45, footer_font_pt: float = 32, total_line_width_pt: float = 6, package_version: str = 'development', last_updated: str | None = None, detection_type: str = 'ISM/CSM', include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = False, warnings: tuple[str, ...] = <factory>)

Complete molecule-slide layout plan.

property molecules: tuple[SlideMoleculeEntry, ...]

All molecule entries in slide order.

astromol.slides.legacy_molecule_slide_specs() tuple[SlideGroupSpec, ...]

Return the historically tuned molecule-slide layout specification.

astromol.slides.balanced_molecule_slide_specs(entries: list[SlideMoleculeEntry]) tuple[tuple[SlideGroupSpec, ...], float]

Return adaptive slide group specs and the chosen molecule font size.

The balanced profile keeps all atom-count groups in a single molecule band and adapts by choosing a readable font size, deriving column counts from row capacity, estimating per-group widths from display formulas, and distributing remaining horizontal space as group gaps.

astromol.slides.compact_molecule_slide_specs(entries: list[SlideMoleculeEntry]) tuple[tuple[SlideGroupSpec, ...], float]

Return compact slide specs for sparse molecule inventories.

astromol.slides.balanced_total_box(specs: tuple[SlideGroupSpec, ...]) SlideBox

Return a count box centered under the first six molecule columns.

astromol.slides.compact_total_box(specs: tuple[SlideGroupSpec, ...]) SlideBox

Return a centered count box for a compact slide layout.

astromol.slides.rendered_group_label_box(group: SlideGroupPlan, profile: str) SlideBox

Return the textbox used for rendering a group label.

astromol.slides.group_label_alignment(group: SlideGroupPlan, profile: str, PP_ALIGN)

Return label alignment for a group header.

astromol.slides.balanced_column_width(entries: list[SlideMoleculeEntry], font_pt: float) float

Estimate a readable PowerPoint column width for formula entries.

astromol.slides.balanced_label_width(label: str) float

Return a minimum group width that leaves room for the atom-count label.

astromol.slides.compact_label_width(label: str) float

Return a minimum compact-profile group width for one-line labels.

astromol.slides.selected_molecule_slide_entries(view: CensusView, *, detection_type: str = 'ISM/CSM', include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = False) list[SlideMoleculeEntry]

Return molecules selected for a molecule-summary slide.

The default is the main secure, non-isotopologue ISM/CSM inventory. Ordering follows first accepted detection order within the selected view, which is the order used for the manuscript molecule tables.

astromol.slides.first_detection_sort_keys(detections: list[Detection]) dict[str, tuple]

Return first-detection sort keys by molecule label.

astromol.slides.build_molecule_slide_layout(view: CensusView, *, detection_type: str = 'ISM/CSM', include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = False, profile: str = 'legacy', title: str = 'Known Interstellar Molecules', last_updated: str | None = None) MoleculeSlideLayout

Build a molecule-slide layout plan without writing PowerPoint output.

astromol.slides.estimated_column_capacity(box: SlideBox, *, font_pt: float = 22) int

Return a conservative estimated row capacity for a column box.

astromol.slides.selected_records_last_modified(entries: list[SlideMoleculeEntry]) str | None

Return the latest molecule-history modification date in selected entries.

astromol.slides.package_version() str

Return installed package version, or a traceable development label.

astromol.slides.repository_git_label() str | None

Return the current repository short hash, with dirty marker if needed.

astromol.slides.slide_version_label(version: str) str

Return display text for the slide package-version line.

astromol.slides.molecule_slide_report(layout: MoleculeSlideLayout) str

Return a concise Markdown report for a molecule slide layout.

astromol.slides.write_molecule_slide_report(layout: MoleculeSlideLayout, output_path: str | Path) Path

Write a molecule-slide layout report and return its path.

astromol.slides.write_molecule_slide(view: CensusView, output_path: str | Path = 'astro_molecules.pptx', *, detection_type: str = 'ISM/CSM', include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = False, profile: str = 'legacy', title: str = 'Known Interstellar Molecules', last_updated: str | None = None) Path

Write a molecule-summary PowerPoint slide and return the output path.

astromol.slides.build_ppd_detection_slide_layout(view: CensusView, *, include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = True, profile: str = 'compact', title: str = 'Protoplanetary Disk Molecules', last_updated: str | None = None) MoleculeSlideLayout

Build the PPD molecule/isotopologue slide layout plan.

astromol.slides.write_ppd_detection_slide(view: CensusView, output_path: str | Path = 'ppd_molecules.pptx', *, include_tentative: bool = False, include_disputed: bool = False, include_isotopologues: bool = True, profile: str = 'compact', title: str = 'Protoplanetary Disk Molecules', last_updated: str | None = None) Path

Write a PPD molecule/isotopologue PowerPoint slide.

astromol.slides.render_molecule_slide(layout: MoleculeSlideLayout)

Render a molecule-slide layout to a python-pptx Presentation.

astromol.slides.format_slide_date(value: str | None) str

Format ISO dates for slide display.

astromol.slides.powerpoint_formula_runs(formula: str) list[FormulaRun]

Return formatted runs for a molecule formula in PowerPoint text.

This is not a full LaTeX or mhchem parser. It handles the formula forms used by astromol table formulas: atom counts, leading isomer/conformer labels, terminal charges, and isotope forms such as ^{13} or [13C].

astromol.slides.strip_formula_wrappers(formula: str) str

Remove common formula wrappers not meaningful in PowerPoint text.

astromol.slides.is_atom_count_token(tokens: list[str], index: int) bool

Return whether a numeric token should be shown as an atom subscript.

astromol.slides.is_terminal_charge(tokens: list[str], index: int) bool

Return whether a plus/minus token is a terminal molecular charge.

Registry of standard astromol generated outputs.

The registry is intentionally metadata-first: each entry has a stable name, human-readable label, description, and the callable pieces needed to generate the product. This gives docs, notebooks, automated bundles, and future CLI commands one canonical list of standard outputs.

class astromol.registry.FigureOutputSpec(name: str, label: str, description: str, data_builder: ~collections.abc.Callable[[~astromol.registry.OutputContext], ~typing.Any], writer: ~collections.abc.Callable[[...], ~pathlib.Path], writer_kwargs: ~collections.abc.Callable[[~astromol.registry.OutputContext], ~collections.abc.Mapping[str, ~typing.Any]] = <function _empty_kwargs>, baseline_data_builder: ~collections.abc.Callable[[~astromol.registry.OutputContext], ~typing.Any] | None = None)

One standard figure product.

writer_kwargs() Mapping[str, Any]

Return no keyword arguments for a registry entry.

build_data(context: OutputContext) Any

Build the primary data object for this figure.

write(context: OutputContext, output_path: str | Path) Path

Write this figure to output_path.

class astromol.registry.OutputContext(view: CensusView, view_choice: str = 'current', baseline_view: CensusView | None = None, cache: dict[str, ~typing.Any]=<factory>)

Shared context for generating standard outputs from one selected view.

cached(key: str, builder: Callable[[], Any]) Any

Return a cached intermediate data product.

class astromol.registry.SlideOutputSpec(name: str, label: str, description: str, filename_template: str, writer: ~collections.abc.Callable[[...], ~pathlib.Path], writer_kwargs: ~collections.abc.Callable[[~astromol.registry.OutputContext], ~collections.abc.Mapping[str, ~typing.Any]] = <function _empty_kwargs>, layout_builder: ~collections.abc.Callable[[...], ~typing.Any] | None = None, report_label: str | None = None, report_description: str | None = None, report_filename_template: str | None = None)

One standard PowerPoint slide plus its optional layout report.

writer_kwargs() Mapping[str, Any]

Return no keyword arguments for a registry entry.

filename(context: OutputContext) str

Return this slide’s filename for the selected context.

report_filename(context: OutputContext) str | None

Return this slide’s layout-report filename when configured.

write_slide(context: OutputContext, output_dir: str | Path) Path

Write this PowerPoint slide.

write_report(context: OutputContext, output_dir: str | Path) Path | None

Write this slide’s layout report when configured.

class astromol.registry.TableOutputSpec(name: str, label: str, description: str, writer: Callable[[CensusView, Path], Any])

One standard LaTeX table-fragment product group.

write(view: CensusView, output_dir: str | Path) list[Path]

Write this table group and return generated .tex paths.

astromol.registry.figure_output_names() tuple[str, ...]

Return stable names for standard figure outputs.

astromol.registry.slide_output_names() tuple[str, ...]

Return stable names for standard slide outputs.

astromol.registry.table_output_names() tuple[str, ...]

Return stable names for standard table output groups.

Generate standard astromol output bundles.

This module powers the GitHub Actions workflow that publishes the latest standard figures and PowerPoint slides. It intentionally uses the public table, figure, and slide APIs so automated products exercise the same code paths that users call from notebooks or local scripts.

class astromol.outputs.GeneratedProduct(label: str, path: Path, description: str)

One generated output file for the static product index.

class astromol.outputs.FigureProductGroup(name: str, label: str, description: str, png_product: GeneratedProduct | None = None, pdf_product: GeneratedProduct | None = None)

One figure with its available download formats.

astromol.outputs.view_from_choice(db: Database, choice: str) CensusView

Return a census/current view from a command-line choice.

astromol.outputs.generate_standard_outputs(output_dir: str | Path = PosixPath('build/astromol_outputs'), *, view_choice: str = 'current', formats: tuple[str, ...] = ('png', 'pdf'), clean: bool = True, include_tables: bool = True, include_slides: bool = True) list[GeneratedProduct]

Generate standard latest astromol products and return their paths.

astromol.outputs.parse_args(argv: list[str] | None = None) Namespace

Parse command-line arguments for the output generator.

astromol.outputs.main(argv: list[str] | None = None) int

Command-line entry point for standard output generation.