Skip to content

aimbat._cli

Modules:

Name Description
align

Align seismograms using ICCS or MCCC.

common
data

Manage data sources in an AIMBAT project.

event

View and manage events in the AIMBAT project.

pick

Interactively pick phase arrival times and processing parameters.

plot

Create plots for seismograms and ICCS results.

project

Manage AIMBAT projects.

seismogram

View and manage seismograms in the AIMBAT project.

shell

Interactive AIMBAT shell with tab-completion and command history.

snapshot

View and manage snapshots of processing parameters.

station

View and manage stations.

utils

Utilities for AIMBAT.

align

Align seismograms using ICCS or MCCC.

This command aligns seismograms using either the ICCS or MCCC algorithm. Both commands update the pick stored in t1. If t1 is None, t0 is used as starting point instead, with the resulting pick stored in t1.

Functions:

Name Description
cli_iccs_run

Run the ICCS algorithm to align seismograms for an event.

cli_mccc_run

Run the MCCC algorithm to refine arrival time picks for an event.

cli_iccs_run

cli_iccs_run(
    event_id: Annotated[UUID, event_parameter()],
    *,
    autoselect: Annotated[
        bool,
        Parameter(
            name=autoselect,
            help="Whether to automatically de-select seismograms whose cross-correlation with the stack falls below `min_cc`, and re-select them if the cross-correlation later exceeds `min_cc`.",
        ),
    ] = False,
    autoflip: Annotated[
        bool,
        Parameter(
            name=autoflip,
            help="Whether to automatically flip seismograms (multiply data by -1) when the cross-correlation is negative.",
        ),
    ] = False,
    _: DebugParameter = DebugParameter(),
) -> None

Run the ICCS algorithm to align seismograms for an event.

Iteratively cross-correlates seismograms against a running stack to refine arrival time picks (t1). If t1 is not yet set, t0 is used as the starting point.

Source code in src/aimbat/_cli/align.py
@app.command(name="iccs")
@simple_exception
def cli_iccs_run(
    event_id: Annotated[UUID, event_parameter()],
    *,
    autoselect: Annotated[
        bool,
        Parameter(
            name="autoselect",
            help="Whether to automatically de-select seismograms whose"
            " cross-correlation with the stack falls below `min_cc`, and"
            " re-select them if the cross-correlation later exceeds `min_cc`.",
        ),
    ] = False,
    autoflip: Annotated[
        bool,
        Parameter(
            name="autoflip",
            help="Whether to automatically flip seismograms (multiply data"
            " by -1) when the cross-correlation is negative.",
        ),
    ] = False,
    _: DebugParameter = DebugParameter(),
) -> None:
    """Run the ICCS algorithm to align seismograms for an event.

    Iteratively cross-correlates seismograms against a running stack to refine
    arrival time picks (`t1`). If `t1` is not yet set, `t0` is used as the
    starting point.
    """
    from sqlmodel import Session

    from aimbat.core import create_iccs_instance, resolve_event, run_iccs
    from aimbat.db import engine

    with Session(engine) as session:
        event = resolve_event(session, event_id)
        iccs = create_iccs_instance(session, event).iccs
        run_iccs(session, event, iccs, autoflip, autoselect)

cli_mccc_run

cli_mccc_run(
    event_id: Annotated[UUID, event_parameter()],
    *,
    all_seismograms: Annotated[
        bool,
        Parameter(
            name=all,
            help="Include all seismograms of an event in MCCC processing, not just the currently selected ones.",
        ),
    ] = False,
    _: DebugParameter = DebugParameter(),
) -> None

Run the MCCC algorithm to refine arrival time picks for an event.

Multi-channel cross-correlation simultaneously determines the optimal time shifts for all seismograms. Results are stored in t1.

Source code in src/aimbat/_cli/align.py
@app.command(name="mccc")
@simple_exception
def cli_mccc_run(
    event_id: Annotated[UUID, event_parameter()],
    *,
    all_seismograms: Annotated[
        bool,
        Parameter(
            name="all",
            help="Include all seismograms of an event in MCCC processing, "
            "not just the currently selected ones.",
        ),
    ] = False,
    _: DebugParameter = DebugParameter(),
) -> None:
    """Run the MCCC algorithm to refine arrival time picks for an event.

    Multi-channel cross-correlation simultaneously determines the optimal time
    shifts for all seismograms. Results are stored in `t1`.
    """
    from sqlmodel import Session

    from aimbat.core import create_iccs_instance, resolve_event, run_mccc
    from aimbat.db import engine

    with Session(engine) as session:
        event = resolve_event(session, event_id)
        iccs = create_iccs_instance(session, event).iccs
        run_mccc(session, event, iccs, all_seismograms)

common

Classes:

Name Description
DebugParameter

Shared parameter that adds --debug to any CLI command.

EventDebugParameters

Parameters for commands that operate on individual events, with optional debug mode.

IccsPlotParameters

Shared parameters for ICCS plot commands (--context, --all).

JsonDumpParameters

Shared parameters for JSON dump commands (--alias, --debug).

TableParameters

Shared parameters for table display commands (--raw, --debug).

Functions:

Name Description
event_parameter

Return a cyclopts Parameter for selecting a single event by UUID or prefix.

event_parameter_is_all

Return True if event_id is the literal string "all" (case-insensitive).

event_parameter_with_all

Return a cyclopts Parameter for selecting an event or the literal "all".

id_parameter

Return a cyclopts Parameter for selecting a record by UUID or unique prefix.

json_to_table

Print a JSON dict or list of dicts as a rich table driven by a Pydantic model.

open_in_editor

Write initial_content to a temporary Markdown file, open it in $EDITOR,

print_error_panel

Print an exception to the console in a red panel.

simple_exception

Decorator to handle exceptions and print them to the console.

station_parameter_is_all

Return True if station_id is the literal string "all" (case-insensitive).

station_parameter_with_all

Return a cyclopts Parameter for selecting a station or the literal "all".

use_event_parameter

Return a cyclopts Parameter for linking data to an existing event record.

use_matrix_image

Return a cyclopts Parameter for switching from stack to matrix image plots.

use_station_parameter

Return a cyclopts Parameter for linking data to an existing station record.

DebugParameter dataclass

Bases: _DebugTrait

Shared parameter that adds --debug to any CLI command.

Parameters:

Name Type Description Default
debug bool

Enable verbose logging for troubleshooting.

False

Attributes:

Name Type Description
debug bool

Enable verbose logging for troubleshooting.

Source code in src/aimbat/_cli/common/_parameters.py
@Parameter(name="*")
@dataclass
class DebugParameter(_DebugTrait):
    """Shared parameter that adds `--debug` to any CLI command."""

    pass

debug class-attribute instance-attribute

debug: bool = False

Enable verbose logging for troubleshooting.

EventDebugParameters dataclass

Bases: _DebugTrait, _EventContextTrait

Parameters for commands that operate on individual events, with optional debug mode.

Parameters:

Name Type Description Default
event_id UUID
required
debug bool

Enable verbose logging for troubleshooting.

False

Attributes:

Name Type Description
debug bool

Enable verbose logging for troubleshooting.

Source code in src/aimbat/_cli/common/_parameters.py
@Parameter(name="*")
@dataclass
class EventDebugParameters(_DebugTrait, _EventContextTrait):
    """Parameters for commands that operate on individual events, with optional debug mode."""

    pass

debug class-attribute instance-attribute

debug: bool = False

Enable verbose logging for troubleshooting.

IccsPlotParameters dataclass

Shared parameters for ICCS plot commands (--context, --all).

Parameters:

Name Type Description Default
context bool
True
all_seismograms bool
False
Source code in src/aimbat/_cli/common/_parameters.py
@Parameter(name="*")
@dataclass
class IccsPlotParameters:
    """Shared parameters for ICCS plot commands (`--context`, `--all`)."""

    context: Annotated[
        bool,
        Parameter(
            help="Plot seismograms with extra context instead of the short tapered ones used for cross-correlation"
        ),
    ] = True
    all_seismograms: Annotated[
        bool,
        Parameter(
            name="all",
            help="Include all seismograms in the plot, even if not used in stack.",
        ),
    ] = False

JsonDumpParameters dataclass

Bases: _ByAliasTrait, _DebugTrait

Shared parameters for JSON dump commands (--alias, --debug).

Parameters:

Name Type Description Default
debug bool

Enable verbose logging for troubleshooting.

False
by_alias bool
False

Attributes:

Name Type Description
debug bool

Enable verbose logging for troubleshooting.

Source code in src/aimbat/_cli/common/_parameters.py
@Parameter(name="*")
@dataclass
class JsonDumpParameters(_ByAliasTrait, _DebugTrait):
    """Shared parameters for JSON dump commands (`--alias`, `--debug`)."""

    pass

debug class-attribute instance-attribute

debug: bool = False

Enable verbose logging for troubleshooting.

TableParameters dataclass

Bases: _TableParametersTrait, _DebugTrait

Shared parameters for table display commands (--raw, --debug).

Parameters:

Name Type Description Default
debug bool

Enable verbose logging for troubleshooting.

False
raw bool
False

Attributes:

Name Type Description
debug bool

Enable verbose logging for troubleshooting.

Source code in src/aimbat/_cli/common/_parameters.py
@Parameter(name="*")
@dataclass
class TableParameters(_TableParametersTrait, _DebugTrait):
    """Shared parameters for table display commands (`--raw`, `--debug`)."""

    pass

debug class-attribute instance-attribute

debug: bool = False

Enable verbose logging for troubleshooting.

event_parameter

event_parameter(help: str | None = None) -> Parameter

Return a cyclopts Parameter for selecting a single event by UUID or prefix.

Parameters:

Name Type Description Default
help str | None

Custom help string; falls back to a generic event UUID prompt.

None
Source code in src/aimbat/_cli/common/_parameters.py
def event_parameter(help: str | None = None) -> Parameter:
    """Return a cyclopts `Parameter` for selecting a single event by UUID or prefix.

    Args:
        help: Custom help string; falls back to a generic event UUID prompt.
    """
    from aimbat.models import AimbatEvent

    return Parameter(
        name=["event", "event-id"],
        help=help or "UUID (or unique prefix) of event to process.",
        env_var="DEFAULT_EVENT_ID",
        converter=_make_uuid_converter(AimbatEvent),
    )

event_parameter_is_all

event_parameter_is_all(
    event_id: UUID | Literal["all"],
) -> TypeIs[Literal["all"]]

Return True if event_id is the literal string "all" (case-insensitive).

Source code in src/aimbat/_cli/common/_parameters.py
def event_parameter_is_all(event_id: UUID | Literal["all"]) -> TypeIs[Literal["all"]]:
    """Return `True` if `event_id` is the literal string `"all"` (case-insensitive)."""
    if isinstance(event_id, str) and event_id.lower() == "all":
        return True
    return False

event_parameter_with_all

event_parameter_with_all(
    help: str | None = None,
) -> Parameter

Return a cyclopts Parameter for selecting an event or the literal "all".

Parameters:

Name Type Description Default
help str | None

Custom help string; falls back to a generic prompt.

None
Source code in src/aimbat/_cli/common/_parameters.py
def event_parameter_with_all(help: str | None = None) -> Parameter:
    """Return a cyclopts `Parameter` for selecting an event or the literal `"all"`.

    Args:
        help: Custom help string; falls back to a generic prompt.
    """
    from aimbat.models import AimbatEvent

    return Parameter(
        name=["event", "event-id"],
        help=help
        or '"all" for all events, or UUID (or unique prefix) of event to process.',
        env_var="DEFAULT_EVENT_ID",
        converter=_make_uuid_converter(AimbatEvent, allow_all=True),
        show_choices=False,
    )

id_parameter

id_parameter(
    model_class: type, help: str = ""
) -> Parameter

Return a cyclopts Parameter for selecting a record by UUID or unique prefix.

Parameters:

Name Type Description Default
model_class type

AIMBAT model class used to resolve short UUID prefixes.

required
help str

Custom help string; falls back to a generic UUID prompt if empty.

''
Source code in src/aimbat/_cli/common/_parameters.py
def id_parameter(model_class: type, help: str = "") -> Parameter:
    """Return a cyclopts `Parameter` for selecting a record by UUID or unique prefix.

    Args:
        model_class: AIMBAT model class used to resolve short UUID prefixes.
        help: Custom help string; falls back to a generic UUID prompt if empty.
    """
    return Parameter(
        name="id",
        help=help or "UUID (or any unique prefix).",
        converter=_make_uuid_converter(model_class),
    )

json_to_table

json_to_table(
    data: dict[str, Any] | list[dict[str, Any]],
    model: type[BaseModel],
    title: str | None = None,
    raw: bool = False,
    col_specs: dict[str, RichColSpec] | None = None,
    column_order: list[str] | None = None,
    key_header: str = "Property",
    value_header: str = "Value",
) -> None

Print a JSON dict or list of dicts as a rich table driven by a Pydantic model.

Parameters:

Name Type Description Default
data dict[str, Any] | list[dict[str, Any]]

A single row (dict) or list of rows to display.

required
model type[BaseModel]

Pydantic model whose field metadata drives column configuration.

required
title str | None

Optional table title.

None
raw bool

If True, ignore RichColSpec metadata and render using only type-based heuristics. Useful for a quick unformatted view.

False
col_specs dict[str, RichColSpec] | None

Optional per-field overrides. Each entry is merged on top of the spec derived from the model field, so only the attributes that differ need to be set. Ignored when raw=True.

None
column_order list[str] | None

Optional list of field names that should appear first, in that order. Fields not listed appear after in model-declaration order.

None
key_header str

Header for the property-name column in vertical (dict) tables.

'Property'
value_header str

Header for the value column in vertical (dict) tables.

'Value'
Source code in src/aimbat/_cli/common/_table.py
def json_to_table(
    data: dict[str, Any] | list[dict[str, Any]],
    model: type[BaseModel],
    title: str | None = None,
    raw: bool = False,
    col_specs: dict[str, RichColSpec] | None = None,
    column_order: list[str] | None = None,
    key_header: str = "Property",
    value_header: str = "Value",
) -> None:
    """Print a JSON dict or list of dicts as a rich table driven by a Pydantic model.

    Args:
        data: A single row (dict) or list of rows to display.
        model: Pydantic model whose field metadata drives column configuration.
        title: Optional table title.
        raw: If `True`, ignore `RichColSpec` metadata and render using only
            type-based heuristics. Useful for a quick unformatted view.
        col_specs: Optional per-field overrides. Each entry is merged on top of
            the spec derived from the model field, so only the attributes that
            differ need to be set. Ignored when `raw=True`.
        column_order: Optional list of field names that should appear first, in
            that order. Fields not listed appear after in model-declaration order.
        key_header: Header for the property-name column in vertical (dict) tables.
        value_header: Header for the value column in vertical (dict) tables.
    """
    console = Console()
    table = Table(title=title)

    data_list = [data] if isinstance(data, dict) else data
    if not data_list:
        console.print(table)
        return

    # Build specs from model field metadata (skipped in raw mode).
    specs: dict[str, RichColSpec] = {}
    if not raw:
        for name, field in model.model_fields.items():
            spec: RichColSpec | None = None
            # Pydantic Field uses json_schema_extra; SQLModel Field uses schema_extra
            # which spreads its keys directly into _attributes_set on the FieldInfo.
            for source in (
                field.json_schema_extra,
                getattr(field, "_attributes_set", None),
            ):
                if isinstance(source, dict):
                    candidate = source.get("rich")
                    if isinstance(candidate, RichColSpec):
                        spec = candidate
                        break
            specs[name] = spec if spec is not None else RichColSpec()

        # Apply caller-supplied overrides. model_fields_set tracks which fields
        # were explicitly provided, so only those replace the model-derived spec.
        if col_specs:
            for name, override in col_specs.items():
                base = specs.get(name, RichColSpec())
                specs[name] = base.model_copy(
                    update={k: getattr(override, k) for k in override.model_fields_set}
                )

    def _ordered(names: list[str]) -> list[str]:
        if not column_order:
            return names
        ordered = [n for n in column_order if n in names]
        rest = [n for n in names if n not in set(column_order)]
        return ordered + rest

    def _fmt_val(name: str, val: Any) -> str:
        if raw:
            return "" if val is None else str(val)
        if val is None or val is NaT:
            return _MISSING_MARKER
        spec = specs.get(name)
        if spec and spec.formatter:
            return spec.formatter(val)
        if isinstance(val, bool):
            return fmt_bool(val)
        if isinstance(val, float):
            return fmt_float(val)
        if isinstance(val, Timedelta):
            return fmt_timedelta(val)
        if isinstance(val, (Timestamp, datetime)):
            return fmt_timestamp(val)
        low_key = name.lower()
        if (
            isinstance(val, str)
            and val.strip()
            and any(k in low_key for k in ("time", "date", "modified"))
        ):
            try:
                dt = to_datetime(val)
                return fmt_timestamp(dt)
            except (ValueError, TypeError):
                return str(val)
        return str(val)

    field_names = _ordered(list(model.model_fields.keys()))

    if isinstance(data, dict):
        # Vertical table
        table.add_column(key_header, style="cyan")
        table.add_column(value_header)
        for name in field_names:
            if name not in data:
                continue
            spec = specs.get(name)
            if spec and spec.display_title:
                label = spec.display_title
            else:
                field = model.model_fields[name]
                label = field.title if field.title else name
            table.add_row(label, _fmt_val(name, data[name]))
    else:
        # Horizontal table — restrict to fields present in data.
        data_keys: set[str] = set()
        for item in data_list:
            data_keys.update(item.keys())
        visible_fields = [n for n in field_names if n in data_keys]

        for name in visible_fields:
            spec = specs.get(name)
            field = model.model_fields[name]
            header = (
                spec.display_title
                if spec and spec.display_title
                else field.title or name
            )
            kwargs: dict[str, Any] = {}
            default_justify = _justify_for_annotation(field.annotation)
            if default_justify:
                kwargs["justify"] = default_justify
            if spec:
                if spec.justify:
                    kwargs["justify"] = spec.justify
                if spec.style:
                    kwargs["style"] = spec.style
                if spec.no_wrap is not None:
                    kwargs["no_wrap"] = spec.no_wrap
                if spec.highlight is not None:
                    kwargs["highlight"] = spec.highlight
            table.add_column(header, **kwargs)

        for item in data:
            table.add_row(*[_fmt_val(n, item.get(n)) for n in visible_fields])

    console.print(table)

open_in_editor

open_in_editor(initial_content: str) -> str

Write initial_content to a temporary Markdown file, open it in $EDITOR, and return the (possibly updated) content after the editor exits.

The temporary file uses delete=False so that it can be opened by a second process on Windows (which prohibits opening a file that is already open). It is always removed in a finally block.

The editor command is taken from $EDITOR or $VISUAL. If neither is set, notepad is used on Windows and vi elsewhere. To use a GUI editor that does not block by default (e.g. VS Code), set EDITOR="code --wait".

Source code in src/aimbat/_cli/common/_parameters.py
def open_in_editor(initial_content: str) -> str:
    """Write `initial_content` to a temporary Markdown file, open it in `$EDITOR`,
    and return the (possibly updated) content after the editor exits.

    The temporary file uses `delete=False` so that it can be opened by a
    second process on Windows (which prohibits opening a file that is already
    open). It is always removed in a `finally` block.

    The editor command is taken from `$EDITOR` or `$VISUAL`. If neither is
    set, `notepad` is used on Windows and `vi` elsewhere. To use a GUI editor
    that does not block by default (e.g. VS Code), set
    ``EDITOR="code --wait"``.
    """
    import os
    import shlex
    import subprocess
    import tempfile

    editor = os.environ.get("EDITOR") or os.environ.get("VISUAL")
    if not editor:
        editor = "notepad" if sys.platform == "win32" else "vi"

    with tempfile.NamedTemporaryFile(
        mode="w",
        suffix=".md",
        delete=False,
        encoding="utf-8",
    ) as tmp:
        tmp.write(initial_content)
        tmp_path = tmp.name

    try:
        subprocess.run([*shlex.split(editor), tmp_path], check=False)
        with open(tmp_path, encoding="utf-8") as f:
            return f.read()
    finally:
        os.unlink(tmp_path)

print_error_panel

print_error_panel(e: Exception) -> None

Print an exception to the console in a red panel.

Source code in src/aimbat/_cli/common/_decorators.py
def print_error_panel(e: Exception) -> None:
    """Print an exception to the console in a red panel."""
    from rich.console import Console
    from rich.panel import Panel

    console = Console(stderr=True)
    panel = Panel(
        f"{e}",
        title="Error",
        title_align="left",
        border_style="red",
        expand=True,
    )
    console.print(panel)

simple_exception

simple_exception(func: F) -> F

Decorator to handle exceptions and print them to the console.

Using this decorator prints only the exception to the console without traceback, and then exits. In debugging mode this decorator returns the callable unchanged.

Source code in src/aimbat/_cli/common/_decorators.py
def simple_exception[F: Callable[..., Any]](func: F) -> F:
    """Decorator to handle exceptions and print them to the console.

    Using this decorator prints only the exception to the console without
    traceback, and then exits. In debugging mode this decorator returns the
    callable unchanged.
    """
    import sys
    from functools import wraps

    @wraps(func)
    def wrapper(*args: Any, **kwargs: Any) -> Any:
        if settings.log_level in ("TRACE", "DEBUG"):
            return func(*args, **kwargs)
        try:
            return func(*args, **kwargs)
        except Exception as e:
            print_error_panel(e)
            sys.exit(1)

    return wrapper  # type: ignore

station_parameter_is_all

station_parameter_is_all(
    station_id: UUID | Literal["all"],
) -> TypeIs[Literal["all"]]

Return True if station_id is the literal string "all" (case-insensitive).

Source code in src/aimbat/_cli/common/_parameters.py
def station_parameter_is_all(
    station_id: UUID | Literal["all"],
) -> TypeIs[Literal["all"]]:
    """Return `True` if `station_id` is the literal string `"all"` (case-insensitive)."""
    if isinstance(station_id, str) and station_id.lower() == "all":
        return True
    return False

station_parameter_with_all

station_parameter_with_all(
    help: str | None = None,
) -> Parameter

Return a cyclopts Parameter for selecting a station or the literal "all".

Parameters:

Name Type Description Default
help str | None

Custom help string; falls back to a generic prompt.

None
Source code in src/aimbat/_cli/common/_parameters.py
def station_parameter_with_all(help: str | None = None) -> Parameter:
    """Return a cyclopts `Parameter` for selecting a station or the literal `"all"`.

    Args:
        help: Custom help string; falls back to a generic prompt.
    """
    from aimbat.models import AimbatStation

    return Parameter(
        name=["station", "station-id"],
        help=help
        or '"all" for all stations, or UUID (or unique prefix) of station to process.',
        converter=_make_uuid_converter(AimbatStation, allow_all=True),
        show_choices=False,
    )

use_event_parameter

use_event_parameter() -> Parameter

Return a cyclopts Parameter for linking data to an existing event record.

Source code in src/aimbat/_cli/common/_parameters.py
def use_event_parameter() -> Parameter:
    """Return a cyclopts `Parameter` for linking data to an existing event record."""
    from aimbat.models import AimbatEvent

    return Parameter(
        name="use-event",
        help="UUID (or unique prefix) of an existing event to link to instead of"
        " extracting one from each data source.",
        converter=_make_uuid_converter(AimbatEvent),
    )

use_matrix_image

use_matrix_image() -> Parameter

Return a cyclopts Parameter for switching from stack to matrix image plots.

Source code in src/aimbat/_cli/common/_parameters.py
def use_matrix_image() -> Parameter:
    """Return a cyclopts `Parameter` for switching from stack to matrix image plots."""
    return Parameter(
        name="matrix",
        help="Use matrix image instead of stack plot.",
    )

use_station_parameter

use_station_parameter() -> Parameter

Return a cyclopts Parameter for linking data to an existing station record.

Source code in src/aimbat/_cli/common/_parameters.py
def use_station_parameter() -> Parameter:
    """Return a cyclopts `Parameter` for linking data to an existing station record."""
    from aimbat.models import AimbatStation

    return Parameter(
        name="use-station",
        help="UUID (or unique prefix) of an existing station to link to instead of"
        " extracting one from each data source.",
        converter=_make_uuid_converter(AimbatStation),
    )

data

Manage data sources in an AIMBAT project.

A data source is a file that AIMBAT reads seismogram waveforms and metadata from. When a data source is added, AIMBAT extracts and stores the associated station, event, and seismogram records in the project database — provided the data type supports it.

Supported data types (--type):

  • sac (default): SAC waveform file. Extracts station, event, and seismogram data automatically.
  • json_station: JSON file containing station metadata only. No seismogram is created.
  • json_event: JSON file containing event metadata only. No seismogram is created.

Typical workflow:

aimbat project create
aimbat data add *.sac
aimbat event list          # list events created from SAC headers
aimbat snapshot create "initial import" --event-id <ID>

Re-adding a data source that is already in the project is safe — existing records are reused rather than duplicated.

Functions:

Name Description
cli_data_add

Add or update data sources in the AIMBAT project.

cli_data_dump

Dump AIMBAT datasources table as a JSON string.

cli_data_list

Print a table of data sources registered in the AIMBAT project.

cli_data_add

cli_data_add(
    data_sources: Annotated[
        list[Path],
        Parameter(
            name="sources",
            help="One or more data source paths to add.",
            consume_multiple=1,
            negative_iterable=(),
            validator=Path(exists=True),
        ),
    ],
    *,
    data_type: Annotated[
        DataType,
        Parameter(
            name="type",
            help="Format of the data sources. Determines which metadata (station, event, seismogram) can be extracted automatically.",
        ),
    ] = SAC,
    station_id: Annotated[
        UUID | None, use_station_parameter()
    ] = None,
    event_id: Annotated[
        UUID | None, use_event_parameter()
    ] = None,
    dry_run: Annotated[
        bool,
        Parameter(
            name="dry-run",
            help="Preview which records would be added without modifying the database.",
        ),
    ] = False,
    show_progress_bar: Annotated[
        bool,
        Parameter(
            name="progress",
            help="Display a progress bar while ingesting sources.",
        ),
    ] = True,
    _: DebugParameter = DebugParameter(),
) -> None

Add or update data sources in the AIMBAT project.

Each data source is processed according to --type. For sac (the default), AIMBAT extracts station, event, and seismogram metadata directly from the file. For types that cannot extract a station or event (e.g. a format that only carries waveform data), supply --use-station and/or --use-event to link to records that already exist in the project.

Station and event deduplication is automatic: if a matching record already exists it is reused. Re-running data add on the same files is safe.

Use --dry-run to preview what would be added without touching the database.

Source code in src/aimbat/_cli/data.py
@app.command(name="add")
@simple_exception
def cli_data_add(
    data_sources: Annotated[
        list[Path],
        Parameter(
            name="sources",
            help="One or more data source paths to add.",
            consume_multiple=1,
            negative_iterable=(),
            validator=validators.Path(exists=True),
        ),
    ],
    *,
    data_type: Annotated[
        DataType,
        Parameter(
            name="type",
            help="Format of the data sources. Determines which metadata"
            " (station, event, seismogram) can be extracted automatically.",
        ),
    ] = DataType.SAC,
    station_id: Annotated[uuid.UUID | None, use_station_parameter()] = None,
    event_id: Annotated[uuid.UUID | None, use_event_parameter()] = None,
    dry_run: Annotated[
        bool,
        Parameter(
            name="dry-run",
            help="Preview which records would be added without modifying the database.",
        ),
    ] = False,
    show_progress_bar: Annotated[
        bool,
        Parameter(
            name="progress", help="Display a progress bar while ingesting sources."
        ),
    ] = True,
    _: DebugParameter = DebugParameter(),
) -> None:
    """Add or update data sources in the AIMBAT project.

    Each data source is processed according to `--type`. For `sac` (the
    default), AIMBAT extracts station, event, and seismogram metadata directly
    from the file. For types that cannot extract a station or event (e.g. a
    format that only carries waveform data), supply `--use-station` and/or
    `--use-event` to link to records that already exist in the project.

    Station and event deduplication is automatic: if a matching record already
    exists it is reused. Re-running `data add` on the same files is safe.

    Use `--dry-run` to preview what would be added without touching the
    database.
    """
    from aimbat.core import add_data_to_project
    from aimbat.db import engine

    disable_progress_bar = not show_progress_bar

    with Session(engine) as session:
        if dry_run:
            results = add_data_to_project(
                session,
                data_sources,
                data_type,
                station_id=station_id,
                event_id=event_id,
                dry_run=True,
                disable_progress_bar=disable_progress_bar,
            )
            _print_dry_run_results(*results)
        else:
            add_data_to_project(
                session,
                data_sources,
                data_type,
                station_id=station_id,
                event_id=event_id,
                dry_run=False,
                disable_progress_bar=disable_progress_bar,
            )

cli_data_dump

cli_data_dump(
    *,
    dump_parameters: JsonDumpParameters = JsonDumpParameters(),
) -> None

Dump AIMBAT datasources table as a JSON string.

Output can be piped or redirected for use in external tools or scripts.

Source code in src/aimbat/_cli/data.py
@app.command(name="dump")
@simple_exception
def cli_data_dump(
    *,
    dump_parameters: JsonDumpParameters = JsonDumpParameters(),
) -> None:
    """Dump AIMBAT datasources table as a JSON string.

    Output can be piped or redirected for use in external tools or scripts.
    """
    from rich import print_json

    from aimbat.core import dump_data_table
    from aimbat.db import engine

    with Session(engine) as session:
        print_json(data=dump_data_table(session, by_alias=dump_parameters.by_alias))

cli_data_list

cli_data_list(
    event_id: Annotated[
        UUID | Literal["all"], event_parameter_with_all()
    ],
    *,
    table_parameters: TableParameters = TableParameters(),
) -> None

Print a table of data sources registered in the AIMBAT project.

Source code in src/aimbat/_cli/data.py
@app.command(name="list")
@simple_exception
def cli_data_list(
    event_id: Annotated[uuid.UUID | Literal["all"], event_parameter_with_all()],
    *,
    table_parameters: TableParameters = TableParameters(),
) -> None:
    """Print a table of data sources registered in the AIMBAT project."""
    from aimbat.core import dump_data_table, resolve_event
    from aimbat.db import engine
    from aimbat.logger import logger
    from aimbat.models import AimbatDataSource, AimbatSeismogram, RichColSpec
    from aimbat.utils import uuid_shortener

    from .common import json_to_table

    raw = table_parameters.raw

    with Session(engine) as session:
        logger.debug("Printing data sources table.")

        if event_parameter_is_all(event_id):
            data = dump_data_table(session)
            title = "Data sources for all events"
        else:
            event = resolve_event(session, event_id)
            data = dump_data_table(session, event.id)
            _time = event.time.strftime("%Y-%m-%d %H:%M:%S") if not raw else event.time
            _id = uuid_shortener(session, event) if not raw else event.id
            title = f"Data sources for event {_time} (ID={_id})"

        col_specs = {
            "id": RichColSpec(
                formatter=lambda x: uuid_shortener(
                    session, AimbatDataSource, str_uuid=x
                )
            ),
            "seismogram_id": RichColSpec(
                formatter=lambda x: uuid_shortener(
                    session, AimbatSeismogram, str_uuid=x
                )
            ),
        }

        json_to_table(
            model=AimbatDataSource,
            data=data,
            title=title,
            raw=raw,
            col_specs=col_specs,
        )

event

View and manage events in the AIMBAT project.

Functions:

Name Description
cli_event_delete

Delete existing event.

cli_event_dump

Dump the contents of the AIMBAT event table to JSON.

cli_event_list

Print a table of events stored in the AIMBAT project.

cli_event_note_edit

Open the event note in $EDITOR and save changes on exit.

cli_event_note_read

Display the note attached to an event, rendered as Markdown.

cli_event_parameter_dump

Dump event parameter table to json.

cli_event_parameter_get

Get parameter value for an event.

cli_event_parameter_list

List processing parameter for an event or all events.

cli_event_parameter_set

Set parameter value for an event.

cli_event_quality_dump

Dump event quality statistics to JSON.

cli_event_quality_list

Show aggregated quality statistics for an event or all events.

cli_event_delete

cli_event_delete(
    event_id: Annotated[UUID, event_parameter()],
    *,
    _: DebugParameter = DebugParameter(),
) -> None

Delete existing event.

Source code in src/aimbat/_cli/event.py
@app.command(name="delete")
@simple_exception
def cli_event_delete(
    event_id: Annotated[uuid.UUID, event_parameter()],
    *,
    _: DebugParameter = DebugParameter(),
) -> None:
    """Delete existing event."""
    from aimbat.core import delete_event, resolve_event
    from aimbat.db import engine

    with Session(engine) as session:
        event = resolve_event(session, event_id)
        delete_event(session, event.id)

cli_event_dump

cli_event_dump(
    *,
    dump_parameters: JsonDumpParameters = JsonDumpParameters(),
) -> None

Dump the contents of the AIMBAT event table to JSON.

Output can be piped or redirected for use in external tools or scripts.

Source code in src/aimbat/_cli/event.py
@app.command(name="dump")
@simple_exception
def cli_event_dump(
    *, dump_parameters: JsonDumpParameters = JsonDumpParameters()
) -> None:
    """Dump the contents of the AIMBAT event table to JSON.

    Output can be piped or redirected for use in external tools or scripts.
    """
    from rich import print_json

    from aimbat.core import dump_event_table
    from aimbat.db import engine

    with Session(engine) as session:
        print_json(dump_event_table(session, by_alias=dump_parameters.by_alias))

cli_event_list

cli_event_list(
    *, table_parameters: TableParameters = TableParameters()
) -> None

Print a table of events stored in the AIMBAT project.

Source code in src/aimbat/_cli/event.py
@app.command(name="list")
@simple_exception
def cli_event_list(
    *,
    table_parameters: TableParameters = TableParameters(),
) -> None:
    """Print a table of events stored in the AIMBAT project."""

    from aimbat.core import dump_event_table
    from aimbat.db import engine
    from aimbat.logger import logger
    from aimbat.models import AimbatEventRead

    from .common import json_to_table

    if raw := table_parameters.raw:
        exclude = {"short_id"}
    else:
        exclude = {"id"}

    with Session(engine) as session:
        logger.info("Printing AIMBAT events table.")

        json_to_table(
            data=dump_event_table(
                session, from_read_model=True, by_title=False, exclude=exclude
            ),
            model=AimbatEventRead,
            title="AIMBAT Events",
            raw=raw,
        )

cli_event_note_edit

cli_event_note_edit(
    event_id: Annotated[UUID, event_parameter()],
    *,
    _: DebugParameter = DebugParameter(),
) -> None

Open the event note in $EDITOR and save changes on exit.

The note is written to a temporary Markdown file. When the editor closes, the updated content is saved back to the database. If the file is left unchanged, no write is performed.

On Windows, set the EDITOR environment variable to your preferred editor (e.g. notepad, notepad++). The editor must be a blocking process; for GUI editors that do not block by default (such as VS Code), pass the appropriate wait flag (e.g. EDITOR="code --wait").

Source code in src/aimbat/_cli/event.py
@_note.command(name="edit")
@simple_exception
def cli_event_note_edit(
    event_id: Annotated[uuid.UUID, event_parameter()],
    *,
    _: DebugParameter = DebugParameter(),
) -> None:
    """Open the event note in `$EDITOR` and save changes on exit.

    The note is written to a temporary Markdown file. When the editor closes,
    the updated content is saved back to the database. If the file is left
    unchanged, no write is performed.

    On Windows, set the `EDITOR` environment variable to your preferred editor
    (e.g. `notepad`, `notepad++`). The editor must be a blocking process; for
    GUI editors that do not block by default (such as VS Code), pass the
    appropriate wait flag (e.g. `EDITOR="code --wait"`).
    """
    from aimbat.core import get_note_content, resolve_event, save_note
    from aimbat.db import engine

    with Session(engine) as session:
        event = resolve_event(session, event_id)
        original = get_note_content(session, "event", event.id)

    updated = open_in_editor(original)

    if updated != original:
        with Session(engine) as session:
            event = resolve_event(session, event_id)
            save_note(session, "event", event.id, updated)

cli_event_note_read

cli_event_note_read(
    event_id: Annotated[UUID, event_parameter()],
    *,
    _: DebugParameter = DebugParameter(),
) -> None

Display the note attached to an event, rendered as Markdown.

Source code in src/aimbat/_cli/event.py
@_note.command(name="read")
@simple_exception
def cli_event_note_read(
    event_id: Annotated[uuid.UUID, event_parameter()],
    *,
    _: DebugParameter = DebugParameter(),
) -> None:
    """Display the note attached to an event, rendered as Markdown."""
    from rich.console import Console
    from rich.markdown import Markdown

    from aimbat.core import get_note_content, resolve_event
    from aimbat.db import engine

    with Session(engine) as session:
        event = resolve_event(session, event_id)
        content = get_note_content(session, "event", event.id)

    Console().print(Markdown(content) if content else "(no note)")

cli_event_parameter_dump

cli_event_parameter_dump(
    *,
    dump_parameters: JsonDumpParameters = JsonDumpParameters(),
) -> None

Dump event parameter table to json.

Source code in src/aimbat/_cli/event.py
@_parameter.command(name="dump")
@simple_exception
def cli_event_parameter_dump(
    *,
    dump_parameters: JsonDumpParameters = JsonDumpParameters(),
) -> None:
    """Dump event parameter table to json."""
    from rich import print_json
    from sqlmodel import Session

    from aimbat.core import dump_event_parameter_table
    from aimbat.db import engine

    by_alias = dump_parameters.by_alias

    with Session(engine) as session:
        print_json(data=dump_event_parameter_table(session, by_alias=by_alias))

cli_event_parameter_get

cli_event_parameter_get(
    name: EventParameter,
    *,
    event_debug_parameters: EventDebugParameters,
) -> None

Get parameter value for an event.

Parameters:

Name Type Description Default
name EventParameter

Event parameter name.

required
Source code in src/aimbat/_cli/event.py
@_parameter.command(name="get")
@simple_exception
def cli_event_parameter_get(
    name: EventParameter, *, event_debug_parameters: EventDebugParameters
) -> None:
    """Get parameter value for an event.

    Args:
        name: Event parameter name.
    """

    from sqlmodel import Session

    from aimbat.core import resolve_event
    from aimbat.db import engine

    event_id = event_debug_parameters.event_id

    with Session(engine) as session:
        event = resolve_event(session, event_id)
        value = event.parameters.model_dump(mode="json").get(name)
        print(value)

cli_event_parameter_list

cli_event_parameter_list(
    event_id: Annotated[
        UUID | Literal["all"], event_parameter_with_all()
    ],
    *,
    table_parameters: TableParameters = TableParameters(),
) -> None

List processing parameter for an event or all events.

Displays all event-level parameters (e.g. time window, bandpass filter settings, minimum cc) in a table.

Source code in src/aimbat/_cli/event.py
@_parameter.command(name="list")
@simple_exception
def cli_event_parameter_list(
    event_id: Annotated[uuid.UUID | Literal["all"], event_parameter_with_all()],
    *,
    table_parameters: TableParameters = TableParameters(),
) -> None:
    """List processing parameter for an event or all events.

    Displays all event-level parameters (e.g. time window, bandpass filter
    settings, minimum cc) in a table.
    """

    from aimbat.core import dump_event_parameter_table, resolve_event
    from aimbat.db import engine
    from aimbat.models import AimbatEventParameters, RichColSpec
    from aimbat.utils import uuid_shortener

    from .common import json_to_table

    raw = table_parameters.raw

    with Session(engine) as session:
        if event_parameter_is_all(event_id):
            title = "Event parameters for all events"
            data = dump_event_parameter_table(session)
        else:
            event = resolve_event(session, event_id)
            title = f"Event parameters for event: {uuid_shortener(session, event) if not raw else str(event.id)}"
            data = dump_event_parameter_table(
                session, event_id=event.id, exclude={"event_id"}
            )

        column_order = ["id"]
        col_specs = {
            "id": RichColSpec(
                formatter=lambda x: uuid_shortener(
                    session, AimbatEventParameters, str_uuid=x
                )
            ),
            "event_id": RichColSpec(
                formatter=lambda x: uuid_shortener(session, AimbatEvent, str_uuid=x)
            ),
        }

        json_to_table(
            model=AimbatEventParameters,
            title=title,
            data=data,
            raw=raw,
            col_specs=col_specs,
            column_order=column_order,
        )

cli_event_parameter_set

cli_event_parameter_set(
    name: EventParameter,
    value: str,
    *,
    event_debug_parameters: EventDebugParameters,
) -> None

Set parameter value for an event.

Parameters:

Name Type Description Default
name EventParameter

Event parameter name.

required
value str

New parameter value.

required
Source code in src/aimbat/_cli/event.py
@_parameter.command(name="set")
@simple_exception
def cli_event_parameter_set(
    name: EventParameter, value: str, *, event_debug_parameters: EventDebugParameters
) -> None:
    """Set parameter value for an event.

    Args:
        name: Event parameter name.
        value: New parameter value.
    """
    from sqlmodel import Session

    from aimbat.core import resolve_event, set_event_parameter
    from aimbat.db import engine

    event_id = event_debug_parameters.event_id

    with Session(engine) as session:
        event = resolve_event(session, event_id)
        set_event_parameter(session, event.id, name, value, validate_iccs=True)

cli_event_quality_dump

cli_event_quality_dump(
    *,
    dump_parameters: JsonDumpParameters = JsonDumpParameters(),
) -> None

Dump event quality statistics to JSON.

Output can be piped or redirected for use in external tools or scripts.

Source code in src/aimbat/_cli/event.py
@_quality.command(name="dump")
@simple_exception
def cli_event_quality_dump(
    *, dump_parameters: JsonDumpParameters = JsonDumpParameters()
) -> None:
    """Dump event quality statistics to JSON.

    Output can be piped or redirected for use in external tools or scripts.
    """
    from rich import print_json

    from aimbat.core import dump_event_quality_table
    from aimbat.db import engine

    with Session(engine) as session:
        data = dump_event_quality_table(session, by_alias=dump_parameters.by_alias)

    print_json(data=data)

cli_event_quality_list

cli_event_quality_list(
    event_id: Annotated[
        UUID | Literal["all"], event_parameter_with_all()
    ],
    *,
    table_parameters: TableParameters = TableParameters(),
) -> None

Show aggregated quality statistics for an event or all events.

Displays ICCS and MCCC quality metrics (means, SEMs, RMSE) aggregated across the seismograms of each event.

Source code in src/aimbat/_cli/event.py
@_quality.command(name="list")
@simple_exception
def cli_event_quality_list(
    event_id: Annotated[uuid.UUID | Literal["all"], event_parameter_with_all()],
    *,
    table_parameters: TableParameters = TableParameters(),
) -> None:
    """Show aggregated quality statistics for an event or all events.

    Displays ICCS and MCCC quality metrics (means, SEMs, RMSE) aggregated
    across the seismograms of each event.
    """
    from aimbat.core import dump_event_quality_table
    from aimbat.db import engine
    from aimbat.models import RichColSpec, SeismogramQualityStats
    from aimbat.utils import uuid_shortener

    from .common import json_to_table

    raw = table_parameters.raw
    is_all = event_parameter_is_all(event_id)

    with Session(engine) as session:
        if is_all:
            title = "Quality statistics for all events"
            exclude = None
        else:
            label = (
                str(event_id)
                if raw
                else uuid_shortener(session, AimbatEvent, str_uuid=str(event_id))
            )
            title = f"Quality statistics for event: {label}"
            exclude = {"event_id"}

        col_specs = {
            "event_id": RichColSpec(
                formatter=lambda x: uuid_shortener(session, AimbatEvent, str_uuid=x),
            ),
        }

        data = dump_event_quality_table(
            session,
            event_id=None if event_parameter_is_all(event_id) else event_id,
            exclude=exclude,
        )

    json_to_table(
        data=data,
        model=SeismogramQualityStats,
        title=title,
        raw=raw,
        col_specs=col_specs,
    )

pick

Interactively pick phase arrival times and processing parameters.

These commands open an interactive matplotlib plot for an event. Use --event-id or set the DEFAULT_EVENT_ID environment variable to choose which event to pick. Click on the plot to set the chosen value, then close the window to save it.

Functions:

Name Description
cli_pick_min_cc

Interactively pick a new minimum cross-correlation for auto-selection.

cli_pick_timewindow

Interactively pick a new cross-correlation time window for an event.

cli_update_phase_pick

Interactively pick a new phase arrival time (t1) for an event.

cli_pick_min_cc

cli_pick_min_cc(
    event_id: Annotated[UUID, event_parameter()],
    *,
    iccs_plot_parameters: IccsPlotParameters = IccsPlotParameters(),
    use_matrix_image: Annotated[
        bool, use_matrix_image()
    ] = True,
    _: DebugParameter = DebugParameter(),
) -> None

Interactively pick a new minimum cross-correlation for auto-selection.

Opens an interactive plot; click to set the cc threshold. Seismograms whose cross-correlation with the stack falls below this value will be automatically de-selected when running ICCS with --autoselect.

Source code in src/aimbat/_cli/pick.py
@app.command(name="cc")
@simple_exception
def cli_pick_min_cc(
    event_id: Annotated[UUID, event_parameter()],
    *,
    iccs_plot_parameters: IccsPlotParameters = IccsPlotParameters(),
    use_matrix_image: Annotated[bool, use_matrix_image()] = True,
    _: DebugParameter = DebugParameter(),
) -> None:
    """Interactively pick a new minimum cross-correlation for auto-selection.

    Opens an interactive plot; click to set the cc threshold. Seismograms
    whose cross-correlation with the stack falls below this value will be
    automatically de-selected when running ICCS with `--autoselect`.
    """
    from sqlmodel import Session

    from aimbat.core import create_iccs_instance, resolve_event
    from aimbat.db import engine
    from aimbat.plot import update_min_cc

    with Session(engine) as session:
        event = resolve_event(session, event_id)
        iccs = create_iccs_instance(session, event).iccs
        update_min_cc(
            session,
            event,
            iccs,
            iccs_plot_parameters.context,
            all_seismograms=iccs_plot_parameters.all_seismograms,
            return_fig=False,
        )

cli_pick_timewindow

cli_pick_timewindow(
    event_id: Annotated[UUID, event_parameter()],
    *,
    iccs_plot_parameters: IccsPlotParameters = IccsPlotParameters(),
    use_matrix_image: Annotated[
        bool, use_matrix_image()
    ] = False,
    _: DebugParameter = DebugParameter(),
) -> None

Interactively pick a new cross-correlation time window for an event.

Opens an interactive plot; click to set the left and right window boundaries, then close the window to save. The window controls which portion of each seismogram is used during ICCS alignment.

Source code in src/aimbat/_cli/pick.py
@app.command(name="window")
@simple_exception
def cli_pick_timewindow(
    event_id: Annotated[UUID, event_parameter()],
    *,
    iccs_plot_parameters: IccsPlotParameters = IccsPlotParameters(),
    use_matrix_image: Annotated[bool, use_matrix_image()] = False,
    _: DebugParameter = DebugParameter(),
) -> None:
    """Interactively pick a new cross-correlation time window for an event.

    Opens an interactive plot; click to set the left and right window boundaries,
    then close the window to save. The window controls which portion of each
    seismogram is used during ICCS alignment.
    """
    from sqlmodel import Session

    from aimbat.core import create_iccs_instance, resolve_event
    from aimbat.db import engine
    from aimbat.plot import update_timewindow

    with Session(engine) as session:
        event = resolve_event(session, event_id)
        iccs = create_iccs_instance(session, event).iccs
        update_timewindow(
            session,
            event,
            iccs,
            iccs_plot_parameters.context,
            all_seismograms=iccs_plot_parameters.all_seismograms,
            use_matrix_image=use_matrix_image,
            return_fig=False,
        )

cli_update_phase_pick

cli_update_phase_pick(
    event_id: Annotated[UUID, event_parameter()],
    *,
    iccs_plot_parameters: IccsPlotParameters = IccsPlotParameters(),
    use_matrix_image: Annotated[
        bool, use_matrix_image()
    ] = False,
    _: DebugParameter = DebugParameter(),
) -> None

Interactively pick a new phase arrival time (t1) for an event.

Opens an interactive plot; click to place the new pick, then close the window to save. The pick is stored as t1 for each seismogram in the ICCS instance.

Source code in src/aimbat/_cli/pick.py
@app.command(name="phase")
@simple_exception
def cli_update_phase_pick(
    event_id: Annotated[UUID, event_parameter()],
    *,
    iccs_plot_parameters: IccsPlotParameters = IccsPlotParameters(),
    use_matrix_image: Annotated[bool, use_matrix_image()] = False,
    _: DebugParameter = DebugParameter(),
) -> None:
    """Interactively pick a new phase arrival time (t1) for an event.

    Opens an interactive plot; click to place the new pick, then close the window
    to save. The pick is stored as `t1` for each seismogram in the ICCS instance.
    """
    from sqlmodel import Session

    from aimbat.core import create_iccs_instance, resolve_event
    from aimbat.db import engine
    from aimbat.plot import update_pick

    with Session(engine) as session:
        event = resolve_event(session, event_id)
        iccs = create_iccs_instance(session, event).iccs
        update_pick(
            session,
            iccs,
            context=iccs_plot_parameters.context,
            all_seismograms=iccs_plot_parameters.all_seismograms,
            use_matrix_image=use_matrix_image,
            return_fig=False,
        )

plot

Create plots for seismograms and ICCS results.

Available plots:

  • data: raw seismograms sorted by epicentral distance.
  • stack: the ICCS cross-correlation stack for an event.
  • matrix: seismograms displayed as a matrix image.

Most plot commands support --context / --no-context to toggle extra waveform context, and --all to include deselected seismograms.

Functions:

Name Description
cli_plot_matrix_image

Plot the ICCS seismograms of an event as a matrix image.

cli_plot_stack

Plot the ICCS stack of an event.

cli_seismogram_plot

Plot input seismograms in an event sorted by epicentral distance.

cli_plot_matrix_image

cli_plot_matrix_image(
    event_id: Annotated[UUID, event_parameter()],
    *,
    iccs_plot_parameters: IccsPlotParameters = IccsPlotParameters(),
    _: DebugParameter = DebugParameter(),
) -> None

Plot the ICCS seismograms of an event as a matrix image.

The matrix is assembled from individual waveforms, with each row representing a different seismogram.

Source code in src/aimbat/_cli/plot.py
@app.command(name="matrix")
@simple_exception
def cli_plot_matrix_image(
    event_id: Annotated[UUID, event_parameter()],
    *,
    iccs_plot_parameters: IccsPlotParameters = IccsPlotParameters(),
    _: DebugParameter = DebugParameter(),
) -> None:
    """Plot the ICCS seismograms of an event as a matrix image.

    The matrix is assembled from individual waveforms, with each row
    representing a different seismogram.
    """
    from sqlmodel import Session

    from aimbat.core import (
        create_iccs_instance,
        resolve_event,
    )
    from aimbat.db import engine
    from aimbat.plot import plot_matrix_image

    with Session(engine) as session:
        event = resolve_event(session, event_id)
        iccs = create_iccs_instance(session, event).iccs
        plot_matrix_image(
            iccs,
            iccs_plot_parameters.context,
            all_seismograms=iccs_plot_parameters.all_seismograms,
            return_fig=False,
        )

cli_plot_stack

cli_plot_stack(
    event_id: Annotated[UUID, event_parameter()],
    *,
    iccs_plot_parameters: IccsPlotParameters = IccsPlotParameters(),
    _: DebugParameter = DebugParameter(),
) -> None

Plot the ICCS stack of an event.

Source code in src/aimbat/_cli/plot.py
@app.command(name="stack")
@simple_exception
def cli_plot_stack(
    event_id: Annotated[UUID, event_parameter()],
    *,
    iccs_plot_parameters: IccsPlotParameters = IccsPlotParameters(),
    _: DebugParameter = DebugParameter(),
) -> None:
    """Plot the ICCS stack of an event."""
    from sqlmodel import Session

    from aimbat.core import create_iccs_instance, resolve_event
    from aimbat.db import engine
    from aimbat.plot import plot_stack

    with Session(engine) as session:
        event = resolve_event(session, event_id)
        iccs = create_iccs_instance(session, event).iccs
        plot_stack(
            iccs,
            iccs_plot_parameters.context,
            all_seismograms=iccs_plot_parameters.all_seismograms,
            return_fig=False,
        )

cli_seismogram_plot

cli_seismogram_plot(
    event_id: Annotated[UUID, event_parameter()],
    *,
    _: DebugParameter = DebugParameter(),
) -> None

Plot input seismograms in an event sorted by epicentral distance.

Source code in src/aimbat/_cli/plot.py
@app.command(name="seismograms")
@simple_exception
def cli_seismogram_plot(
    event_id: Annotated[UUID, event_parameter()],
    *,
    _: DebugParameter = DebugParameter(),
) -> None:
    """Plot input seismograms in an event sorted by epicentral distance."""
    from sqlmodel import Session

    from aimbat.core import resolve_event
    from aimbat.db import engine
    from aimbat.plot import plot_seismograms

    with Session(engine) as session:
        event = resolve_event(session, event_id)
        plot_seismograms(session, event, return_fig=False)

project

Manage AIMBAT projects.

This command manages projects. By default, the project consists of a file called aimbat.db in the current working directory. All aimbat commands must be executed from the same directory. The location (and name) of the project file may also be specified by setting the AIMBAT_PROJECT environment variable to the desired filename. Alternatively, aimbat can be executed with a database url directly.

Functions:

Name Description
cli_project_create

Create a new AIMBAT project in the current directory.

cli_project_delete

Delete project (note: this does not delete seismogram files).

cli_project_info

Show information on an existing project.

cli_project_create

cli_project_create(
    *, _: DebugParameter = DebugParameter()
) -> None

Create a new AIMBAT project in the current directory.

Initialises a new project database (aimbat.db by default). Run this once before adding data with aimbat data add.

Source code in src/aimbat/_cli/project.py
@app.command(name="create")
@simple_exception
def cli_project_create(*, _: DebugParameter = DebugParameter()) -> None:
    """Create a new AIMBAT project in the current directory.

    Initialises a new project database (`aimbat.db` by default). Run this
    once before adding data with `aimbat data add`.
    """
    from aimbat.core import create_project
    from aimbat.db import engine

    create_project(engine)

cli_project_delete

cli_project_delete(
    *, _: DebugParameter = DebugParameter()
) -> None

Delete project (note: this does not delete seismogram files).

Source code in src/aimbat/_cli/project.py
@app.command(name="delete")
@simple_exception
def cli_project_delete(*, _: DebugParameter = DebugParameter()) -> None:
    """Delete project (note: this does *not* delete seismogram files)."""
    from aimbat.core import delete_project
    from aimbat.db import engine

    delete_project(engine)

cli_project_info

cli_project_info(
    event_id: Annotated[
        UUID | None, event_parameter()
    ] = None,
    *,
    _: DebugParameter = DebugParameter(),
) -> None

Show information on an existing project.

Source code in src/aimbat/_cli/project.py
@app.command(name="info")
@simple_exception
def cli_project_info(
    event_id: Annotated[UUID | None, event_parameter()] = None,
    *,
    _: DebugParameter = DebugParameter(),
) -> None:
    """Show information on an existing project."""

    from rich.console import Console
    from rich.panel import Panel
    from rich.table import Table
    from sqlalchemy.exc import NoResultFound
    from sqlmodel import Session, select

    import aimbat.core._event as event
    import aimbat.core._seismogram as seismogram
    import aimbat.core._station as station
    from aimbat.core import resolve_event
    from aimbat.core._project import _project_exists
    from aimbat.db import engine
    from aimbat.models import AimbatEvent, AimbatSeismogram, AimbatStation

    if not _project_exists(engine):
        raise RuntimeError(
            'No AIMBAT project found. Try running "aimbat project create" first.'
        )

    with Session(engine) as session:
        grid = Table.grid(expand=False)
        grid.add_column()
        grid.add_column(justify="left")
        if engine.driver == "pysqlite":
            if engine.url.database == ":memory:":
                grid.add_row("AIMBAT Project: ", "in-memory database")
            else:
                grid.add_row("AIMBAT Project File: ", str(engine.url.database))

        events = len(session.exec(select(AimbatEvent)).all())
        completed_events = len(event.get_completed_events(session))
        stations = len(session.exec(select(AimbatStation)).all())
        seismograms = len(session.exec(select(AimbatSeismogram)).all())
        selected_seismograms = len(
            seismogram.get_selected_seismograms(session, all_events=True)
        )

        grid.add_row(
            "Number of Events (total/completed): ",
            f"({events}/{completed_events})",
        )

        try:
            target_event = resolve_event(session, event_id)
            target_event_id = target_event.id
            active_stations = len(
                station.get_stations_in_event(session, target_event.id)
            )
            seismograms_in_event = len(target_event.seismograms)
            selected_seismograms_in_event = len(
                seismogram.get_selected_seismograms(session, event_id=target_event_id)
            )
        except (NoResultFound, ValueError, RuntimeError):
            target_event_id = None
            active_stations = None
            seismograms_in_event = None
            selected_seismograms_in_event = None

        event_label = "Selected Event ID: "
        grid.add_row(event_label, f"{target_event_id}")
        grid.add_row(
            "Number of Stations in Project (total/selected event): ",
            f"({stations}/{active_stations})",
        )

        grid.add_row(
            "Number of Seismograms in Project (total/selected): ",
            f"({seismograms}/{selected_seismograms})",
        )
        grid.add_row(
            "Number of Seismograms in Selected Event (total/selected): ",
            f"({seismograms_in_event}/{selected_seismograms_in_event})",
        )

        console = Console()
        console.print(
            Panel(grid, title="Project Info", title_align="left", border_style="dim")
        )

seismogram

View and manage seismograms in the AIMBAT project.

Functions:

Name Description
cli_seismogram_delete

Delete existing seismogram.

cli_seismogram_dump

Dump the contents of the AIMBAT seismogram table to JSON.

cli_seismogram_list

Print information on the seismograms in an event.

cli_seismogram_note_edit

Open the seismogram note in $EDITOR and save changes on exit.

cli_seismogram_note_read

Display the note attached to a seismogram, rendered as Markdown.

cli_seismogram_parameter_dump

Dump seismogram parameter table to json.

cli_seismogram_parameter_get

Get the value of a processing parameter.

cli_seismogram_parameter_list

List processing parameter values for seismograms in an event.

cli_seismogram_parameter_reset

Reset all processing parameters to their default values.

cli_seismogram_parameter_set

Set value of a processing parameter.

cli_seismogram_delete

cli_seismogram_delete(
    seismogram_id: Annotated[
        UUID,
        id_parameter(
            AimbatSeismogram,
            help="UUID (or unique prefix) of seismogram to delete.",
        ),
    ],
    *,
    _: DebugParameter = DebugParameter(),
) -> None

Delete existing seismogram.

Source code in src/aimbat/_cli/seismogram.py
@app.command(name="delete")
@simple_exception
def cli_seismogram_delete(
    seismogram_id: Annotated[
        UUID,
        id_parameter(
            AimbatSeismogram, help="UUID (or unique prefix) of seismogram to delete."
        ),
    ],
    *,
    _: DebugParameter = DebugParameter(),
) -> None:
    """Delete existing seismogram."""
    from sqlmodel import Session

    from aimbat.core import delete_seismogram
    from aimbat.db import engine

    with Session(engine) as session:
        delete_seismogram(session, seismogram_id)

cli_seismogram_dump

cli_seismogram_dump(
    *,
    dump_parameters: JsonDumpParameters = JsonDumpParameters(),
) -> None

Dump the contents of the AIMBAT seismogram table to JSON.

Output can be piped or redirected for use in external tools or scripts.

Source code in src/aimbat/_cli/seismogram.py
@app.command(name="dump")
@simple_exception
def cli_seismogram_dump(
    *,
    dump_parameters: JsonDumpParameters = JsonDumpParameters(),
) -> None:
    """Dump the contents of the AIMBAT seismogram table to JSON.

    Output can be piped or redirected for use in external tools or scripts.
    """
    from rich import print_json
    from sqlmodel import Session

    from aimbat.core import dump_seismogram_table
    from aimbat.db import engine

    with Session(engine) as session:
        print_json(
            data=dump_seismogram_table(session, by_alias=dump_parameters.by_alias)
        )

cli_seismogram_list

cli_seismogram_list(
    event_id: Annotated[
        UUID | Literal["all"], event_parameter_with_all()
    ],
    *,
    table_parameters: TableParameters = TableParameters(),
) -> None

Print information on the seismograms in an event.

Source code in src/aimbat/_cli/seismogram.py
@app.command(name="list")
@simple_exception
def cli_seismogram_list(
    event_id: Annotated[UUID | Literal["all"], event_parameter_with_all()],
    *,
    table_parameters: TableParameters = TableParameters(),
) -> None:
    """Print information on the seismograms in an event."""
    from sqlmodel import Session

    from aimbat.core import dump_seismogram_table, resolve_event
    from aimbat.db import engine
    from aimbat.models import AimbatSeismogramRead
    from aimbat.utils import uuid_shortener

    from .common import json_to_table

    if raw := table_parameters.raw:
        exclude = {"short_id", "short_event_id"}
    else:
        exclude = {"id", "event_id"}

    with Session(engine) as session:
        if event_parameter_is_all(event_id):
            title = "AIMBAT seismograms for all events"
            data = dump_seismogram_table(session, from_read_model=True, exclude=exclude)
        else:
            event = resolve_event(session, event_id)
            if raw:
                title = f"AIMBAT seismograms for event {event.time} (ID={event.id})"
                exclude.add("event_id")
            else:
                title = f"AIMBAT seismograms for event {event.time.strftime('%Y-%m-%d %H:%M:%S')}"
                title += f" (ID={uuid_shortener(session, event)})"
                exclude.add("short_event_id")
            data = dump_seismogram_table(
                session,
                from_read_model=True,
                event_id=event.id,
                exclude=exclude,
            )

        json_to_table(data, model=AimbatSeismogramRead, title=title, raw=raw)

cli_seismogram_note_edit

cli_seismogram_note_edit(
    seismogram_id: Annotated[
        UUID,
        id_parameter(
            AimbatSeismogram,
            help="UUID (or unique prefix) of seismogram.",
        ),
    ],
    *,
    _: DebugParameter = DebugParameter(),
) -> None

Open the seismogram note in $EDITOR and save changes on exit.

Source code in src/aimbat/_cli/seismogram.py
@_note.command(name="edit")
@simple_exception
def cli_seismogram_note_edit(
    seismogram_id: Annotated[
        UUID,
        id_parameter(AimbatSeismogram, help="UUID (or unique prefix) of seismogram."),
    ],
    *,
    _: DebugParameter = DebugParameter(),
) -> None:
    """Open the seismogram note in `$EDITOR` and save changes on exit."""
    from sqlmodel import Session

    from aimbat.core import get_note_content, save_note
    from aimbat.db import engine

    with Session(engine) as session:
        original = get_note_content(session, "seismogram", seismogram_id)

    updated = open_in_editor(original)

    if updated != original:
        with Session(engine) as session:
            save_note(session, "seismogram", seismogram_id, updated)

cli_seismogram_note_read

cli_seismogram_note_read(
    seismogram_id: Annotated[
        UUID,
        id_parameter(
            AimbatSeismogram,
            help="UUID (or unique prefix) of seismogram.",
        ),
    ],
    *,
    _: DebugParameter = DebugParameter(),
) -> None

Display the note attached to a seismogram, rendered as Markdown.

Source code in src/aimbat/_cli/seismogram.py
@_note.command(name="read")
@simple_exception
def cli_seismogram_note_read(
    seismogram_id: Annotated[
        UUID,
        id_parameter(AimbatSeismogram, help="UUID (or unique prefix) of seismogram."),
    ],
    *,
    _: DebugParameter = DebugParameter(),
) -> None:
    """Display the note attached to a seismogram, rendered as Markdown."""
    from rich.console import Console
    from rich.markdown import Markdown
    from sqlmodel import Session

    from aimbat.core import get_note_content
    from aimbat.db import engine

    with Session(engine) as session:
        content = get_note_content(session, "seismogram", seismogram_id)

    Console().print(Markdown(content) if content else "(no note)")

cli_seismogram_parameter_dump

cli_seismogram_parameter_dump(
    *,
    dump_parameters: JsonDumpParameters = JsonDumpParameters(),
) -> None

Dump seismogram parameter table to json.

Source code in src/aimbat/_cli/seismogram.py
@parameter.command(name="dump")
@simple_exception
def cli_seismogram_parameter_dump(
    *,
    dump_parameters: JsonDumpParameters = JsonDumpParameters(),
) -> None:
    """Dump seismogram parameter table to json."""
    from rich import print_json
    from sqlmodel import Session

    from aimbat.core import dump_seismogram_parameter_table
    from aimbat.db import engine

    with Session(engine) as session:
        print_json(
            data=dump_seismogram_parameter_table(
                session, by_alias=dump_parameters.by_alias
            )
        )

cli_seismogram_parameter_get

cli_seismogram_parameter_get(
    name: SeismogramParameter,
    *,
    seismogram_id: Annotated[
        UUID,
        id_parameter(
            AimbatSeismogram,
            help="UUID (or unique prefix) of seismogram to query.",
        ),
    ],
    _: DebugParameter = DebugParameter(),
) -> None

Get the value of a processing parameter.

Parameters:

Name Type Description Default
name SeismogramParameter

Name of the seismogram parameter.

required
Source code in src/aimbat/_cli/seismogram.py
@parameter.command(name="get")
@simple_exception
def cli_seismogram_parameter_get(
    name: SeismogramParameter,
    *,
    seismogram_id: Annotated[
        UUID,
        id_parameter(
            AimbatSeismogram, help="UUID (or unique prefix) of seismogram to query."
        ),
    ],
    _: DebugParameter = DebugParameter(),
) -> None:
    """Get the value of a processing parameter.

    Args:
        name: Name of the seismogram parameter.
    """
    from sqlalchemy.exc import NoResultFound
    from sqlmodel import Session

    from aimbat.db import engine
    from aimbat.models import AimbatSeismogram

    with Session(engine) as session:
        seismogram = session.get(AimbatSeismogram, seismogram_id)
        if seismogram is None:
            raise NoResultFound(f"Unable to find seismogram with id: {seismogram_id}.")
        value = seismogram.parameters.model_dump(mode="json").get(name)
        print(value)

cli_seismogram_parameter_list

cli_seismogram_parameter_list(
    event_id: Annotated[
        UUID | Literal["all"], event_parameter_with_all()
    ],
    *,
    table_parameters: TableParameters = TableParameters(),
) -> None

List processing parameter values for seismograms in an event.

Displays per-seismogram parameters (e.g. select, flip, t1 pick) in a table. Use seismogram parameter set to modify individual values.

Source code in src/aimbat/_cli/seismogram.py
@parameter.command(name="list")
@simple_exception
def cli_seismogram_parameter_list(
    event_id: Annotated[UUID | Literal["all"], event_parameter_with_all()],
    *,
    table_parameters: TableParameters = TableParameters(),
) -> None:
    """List processing parameter values for seismograms in an event.

    Displays per-seismogram parameters (e.g. `select`, `flip`, `t1` pick)
    in a table. Use `seismogram parameter set` to modify individual values.
    """

    from sqlmodel import Session

    from aimbat.core import dump_seismogram_parameter_table, resolve_event
    from aimbat.db import engine
    from aimbat.models import AimbatSeismogram, AimbatSeismogramParameters, RichColSpec
    from aimbat.utils import uuid_shortener
    from aimbat.utils.formatters import fmt_flip

    from .common import json_to_table

    raw = table_parameters.raw

    with Session(engine) as session:
        if event_parameter_is_all(event_id):
            event = None
            title = "Seismogram parameters for all events"
        else:
            event = resolve_event(session, event_id)
            title = f"Seismogram parameters for event: {uuid_shortener(session, event) if not raw else str(event.id)}"

        data = dump_seismogram_parameter_table(
            session, event_id=event.id if event else None
        )

        json_to_table(
            data=data,
            model=AimbatSeismogramParameters,
            title=title,
            raw=raw,
            col_specs={
                "id": RichColSpec(
                    style="yellow",
                    no_wrap=True,
                    highlight=False,
                    formatter=lambda x: uuid_shortener(
                        session, AimbatSeismogramParameters, str_uuid=str(x)
                    ),
                ),
                "seismogram_id": RichColSpec(
                    style="magenta",
                    no_wrap=True,
                    highlight=False,
                    formatter=lambda x: uuid_shortener(
                        session, AimbatSeismogram, str_uuid=str(x)
                    ),
                ),
                "flip": RichColSpec(formatter=fmt_flip),
            },
            column_order=["id"],
        )

cli_seismogram_parameter_reset

cli_seismogram_parameter_reset(
    seismogram_id: Annotated[
        UUID,
        id_parameter(
            AimbatSeismogram,
            help="UUID (or unique prefix) of seismogram to reset parameters for.",
        ),
    ],
    *,
    _: DebugParameter = DebugParameter(),
) -> None

Reset all processing parameters to their default values.

Source code in src/aimbat/_cli/seismogram.py
@parameter.command(name="reset")
@simple_exception
def cli_seismogram_parameter_reset(
    seismogram_id: Annotated[
        UUID,
        id_parameter(
            AimbatSeismogram,
            help="UUID (or unique prefix) of seismogram to reset parameters for.",
        ),
    ],
    *,
    _: DebugParameter = DebugParameter(),
) -> None:
    """Reset all processing parameters to their default values."""
    from sqlmodel import Session

    from aimbat.core import reset_seismogram_parameters
    from aimbat.db import engine

    with Session(engine) as session:
        reset_seismogram_parameters(session, seismogram_id)

cli_seismogram_parameter_set

cli_seismogram_parameter_set(
    name: SeismogramParameter,
    value: str,
    *,
    seismogram_id: Annotated[
        UUID,
        id_parameter(
            AimbatSeismogram,
            help="UUID (or unique prefix) of seismogram to modify.",
        ),
    ],
    _: DebugParameter = DebugParameter(),
) -> None

Set value of a processing parameter.

Parameters:

Name Type Description Default
name SeismogramParameter

Name of the seismogram parameter.

required
value str

Value of the seismogram parameter.

required
Source code in src/aimbat/_cli/seismogram.py
@parameter.command(name="set")
@simple_exception
def cli_seismogram_parameter_set(
    name: SeismogramParameter,
    value: str,
    *,
    seismogram_id: Annotated[
        UUID,
        id_parameter(
            AimbatSeismogram, help="UUID (or unique prefix) of seismogram to modify."
        ),
    ],
    _: DebugParameter = DebugParameter(),
) -> None:
    """Set value of a processing parameter.

    Args:
        name: Name of the seismogram parameter.
        value: Value of the seismogram parameter.
    """
    from sqlmodel import Session

    from aimbat.core import set_seismogram_parameter
    from aimbat.db import engine

    with Session(engine) as session:
        set_seismogram_parameter(session, seismogram_id, name, value)

shell

Interactive AIMBAT shell with tab-completion and command history.

All CLI commands are available. Press Tab to complete commands, Ctrl+D or type exit to leave.

Shell-only commands

event switch [ID] Switch the shell's event context.

Functions:

Name Description
cli_shell

Start an interactive AIMBAT shell.

cli_shell

cli_shell(
    event_id: Annotated[
        UUID | None,
        event_parameter(
            help="Start the shell in the context of a specific event. Full UUID or any unique prefix as shown in the table. "
        ),
    ] = None,
    *,
    _: DebugParameter = DebugParameter(),
) -> None

Start an interactive AIMBAT shell.

Source code in src/aimbat/_cli/shell.py
@app.default
@simple_exception
def cli_shell(
    event_id: Annotated[
        uuid.UUID | None,
        event_parameter(
            help="Start the shell in the context of a specific event. "
            "Full UUID or any unique prefix as shown in the table. "
        ),
    ] = None,
    *,
    _: DebugParameter = DebugParameter(),
) -> None:
    """Start an interactive AIMBAT shell."""
    import os
    import shlex
    from pathlib import Path

    from cyclopts import CycloptsError
    from prompt_toolkit import PromptSession
    from prompt_toolkit.completion import NestedCompleter
    from prompt_toolkit.history import FileHistory
    from rich.console import Console

    from aimbat.app import app as aimbat_app

    console = Console()

    # Shell-local event context — None if no event specified.
    # Modified by `event switch`.
    shell_event_id: uuid.UUID | None = event_id

    # Propagate the shell event context to commands via the DEFAULT_EVENT_ID env
    # var, which all event_parameter() / event_parameter_with_all() converters
    # pick up as a fallback.  Explicit --event flags always take precedence.
    _prev_default_event = os.environ.get("DEFAULT_EVENT_ID")

    def _set_shell_event(eid: uuid.UUID | None) -> None:
        nonlocal shell_event_id
        shell_event_id = eid
        if eid is not None:
            os.environ["DEFAULT_EVENT_ID"] = str(eid)
        else:
            os.environ.pop("DEFAULT_EVENT_ID", None)

    _set_shell_event(shell_event_id)

    completion_dict = _build_completion_dict(aimbat_app)
    completion_dict.pop("shell", None)
    completion_dict.pop("tui", None)

    # Inject the shell-only `event switch` subcommand into tab completion.
    event_completions = completion_dict.get("event")
    if isinstance(event_completions, dict):
        event_completions["switch"] = None

    import sys

    pt_session: PromptSession[str] | None = None
    if sys.stdin.isatty():
        pt_session = PromptSession(
            history=FileHistory(str(Path.home() / ".aimbat_history")),
            completer=NestedCompleter.from_nested_dict(completion_dict),
            complete_while_typing=True,
        )

    console.print(
        "[bold]AIMBAT shell[/bold]  (Tab to complete, Ctrl+D or [bold]exit[/bold] to quit)"
    )

    current_bound = _check_iccs(console, None, startup=True, event_id=shell_event_id)

    def _prompt() -> str:
        if shell_event_id is not None:
            return f"aimbat [{str(shell_event_id)[:8]}]> "
        return "aimbat> "

    try:
        while True:
            try:
                if pt_session is not None:
                    text = pt_session.prompt(_prompt).strip()
                else:
                    raw = sys.stdin.readline()
                    if not raw:
                        break
                    text = raw.strip()
            except KeyboardInterrupt:
                continue
            except EOFError:
                break

            if not text:
                continue
            if text in ("exit", "quit", "q"):
                break

            try:
                tokens = shlex.split(text)
            except ValueError as exc:
                console.print(f"[red]Parse error:[/red] {exc}")
                continue

            # Strip a leading "aimbat" token typed out of habit and remind the user.
            if tokens and tokens[0] == "aimbat":
                tokens = tokens[1:]
                console.print("[dim]Tip: no need to type 'aimbat' in the shell.[/dim]")
                if not tokens:
                    continue

            # Shell-only: event switch [id]  — changes context.
            if tokens[:2] == ["event", "switch"]:
                if len(tokens) < 3:
                    # No argument: clear shell event context.
                    _set_shell_event(None)
                    current_bound = _check_iccs(
                        console, None, startup=True, event_id=None
                    )
                else:
                    try:
                        _set_shell_event(_parse_event_id(tokens[2]))
                        current_bound = _check_iccs(
                            console, None, startup=True, event_id=shell_event_id
                        )
                    except Exception as exc:
                        print_error_panel(exc)
                continue

            try:
                aimbat_app(tokens, exit_on_error=False)

                # Check ICCS for the event targeted by the command.  If the
                # user passed --event all (or no explicit flag), fall back to
                # the shell context event.
                explicit_flag = _extract_event_flag(tokens)
                check_event_id: uuid.UUID | None
                if explicit_flag and explicit_flag.lower() != "all":
                    check_event_id = _parse_event_id(explicit_flag)
                else:
                    check_event_id = shell_event_id
                current_bound = _check_iccs(
                    console, current_bound, event_id=check_event_id
                )
            except (CycloptsError, SystemExit):
                # Errors already printed by Cyclopts or subcommand
                pass
            except Exception as exc:
                print_error_panel(exc)
    finally:
        # Restore DEFAULT_EVENT_ID to whatever it was before the shell started.
        if _prev_default_event is not None:
            os.environ["DEFAULT_EVENT_ID"] = _prev_default_event
        else:
            os.environ.pop("DEFAULT_EVENT_ID", None)

snapshot

View and manage snapshots of processing parameters.

A snapshot captures the current event and seismogram processing parameters (e.g. time window, bandpass filter, picks) so they can be restored later. Use snapshot create before making experimental changes, and snapshot rollback to undo them if needed.

Functions:

Name Description
cli_snapshot_create

Create a new snapshot of current processing parameters.

cli_snapshot_delete

Delete existing snapshot.

cli_snapshot_details

Print information on the event parameters saved in a snapshot.

cli_snapshot_dump

Dump the contents of the AIMBAT snapshot tables to json.

cli_snapshot_list

Print information on the snapshots for an event.

cli_snapshot_note_edit

Open the snapshot note in $EDITOR and save changes on exit.

cli_snapshot_note_read

Display the note attached to a snapshot, rendered as Markdown.

cli_snapshot_preview

Preview the ICCS stack/matrix of a snapshot.

cli_snapshot_quality_dump

Dump snapshot quality statistics to JSON.

cli_snapshot_quality_list

Show aggregated quality statistics for snapshots of an event or all events.

cli_snapshot_rollback

Rollback to snapshot.

cli_snapshot_create

cli_snapshot_create(
    event_id: Annotated[UUID, event_parameter()],
    comment: str | None = None,
    *,
    _: DebugParameter = DebugParameter(),
) -> None

Create a new snapshot of current processing parameters.

Saves the current event and seismogram parameters for an event so they can be restored later with snapshot rollback.

Parameters:

Name Type Description Default
comment str | None

Optional description to help identify this snapshot later.

None
Source code in src/aimbat/_cli/snapshot.py
@app.command(name="create")
@simple_exception
def cli_snapshot_create(
    event_id: Annotated[UUID, event_parameter()],
    comment: str | None = None,
    *,
    _: DebugParameter = DebugParameter(),
) -> None:
    """Create a new snapshot of current processing parameters.

    Saves the current event and seismogram parameters for an event so
    they can be restored later with `snapshot rollback`.

    Args:
        comment: Optional description to help identify this snapshot later.
    """
    from sqlmodel import Session

    from aimbat.core import create_snapshot, resolve_event
    from aimbat.db import engine

    with Session(engine) as session:
        event = resolve_event(session, event_id)
        create_snapshot(session, event, comment)

cli_snapshot_delete

cli_snapshot_delete(
    snapshot_id: Annotated[
        UUID,
        id_parameter(
            AimbatSnapshot,
            help="UUID (or unique prefix) of snapshot to delete.",
        ),
    ],
    *,
    _: DebugParameter = DebugParameter(),
) -> None

Delete existing snapshot.

Source code in src/aimbat/_cli/snapshot.py
@app.command(name="delete")
@simple_exception
def cli_snapshot_delete(
    snapshot_id: Annotated[
        UUID,
        id_parameter(
            AimbatSnapshot,
            help="UUID (or unique prefix) of snapshot to delete.",
        ),
    ],
    *,
    _: DebugParameter = DebugParameter(),
) -> None:
    """Delete existing snapshot."""
    from sqlmodel import Session

    from aimbat.core import delete_snapshot
    from aimbat.db import engine

    with Session(engine) as session:
        delete_snapshot(session, snapshot_id)

cli_snapshot_details

cli_snapshot_details(
    snapshot_id: Annotated[
        UUID,
        id_parameter(
            AimbatSnapshot,
            help="UUID (or unique prefix) of snapshot to show details for.",
        ),
    ],
    *,
    table_parameters: TableParameters = TableParameters(),
) -> None

Print information on the event parameters saved in a snapshot.

Source code in src/aimbat/_cli/snapshot.py
@app.command(name="details")
@simple_exception
def cli_snapshot_details(
    snapshot_id: Annotated[
        UUID,
        id_parameter(
            AimbatSnapshot,
            help="UUID (or unique prefix) of snapshot to show details for.",
        ),
    ],
    *,
    table_parameters: TableParameters = TableParameters(),
) -> None:
    """Print information on the event parameters saved in a snapshot."""
    from sqlmodel import Session

    from aimbat.db import engine
    from aimbat.models import AimbatEventParametersSnapshot
    from aimbat.utils import uuid_shortener

    from .common import json_to_table

    with Session(engine) as session:
        snapshot = session.get(AimbatSnapshot, snapshot_id)

        if snapshot is None:
            raise ValueError(
                f"Unable to print snapshot parameters: snapshot with id={snapshot_id} not found."
            )

        raw = table_parameters.raw

        if raw:
            title = f"Saved event parameters in snapshot: {snapshot.id}"
        else:
            title = f"Saved event parameters in snapshot: {uuid_shortener(session, snapshot)}"

        parameters_snapshot = snapshot.event_parameters_snapshot

        json_to_table(
            data=parameters_snapshot.model_dump(
                mode="json", exclude={"id", "snapshot_id", "parameters_id"}
            ),
            model=AimbatEventParametersSnapshot,
            title=title,
            key_header="Parameter",
        )

cli_snapshot_dump

cli_snapshot_dump(
    *,
    dump_parameters: JsonDumpParameters = JsonDumpParameters(),
) -> None

Dump the contents of the AIMBAT snapshot tables to json.

Source code in src/aimbat/_cli/snapshot.py
@app.command(name="dump")
@simple_exception
def cli_snapshot_dump(
    *,
    dump_parameters: JsonDumpParameters = JsonDumpParameters(),
) -> None:
    """Dump the contents of the AIMBAT snapshot tables to json."""
    from rich import print_json
    from sqlmodel import Session

    from aimbat.core import (
        dump_event_parameter_snapshot_table,
        dump_event_quality_snapshot_table,
        dump_seismogram_parameter_snapshot_table,
        dump_seismogram_quality_snapshot_table,
        dump_snapshot_table,
    )
    from aimbat.db import engine

    with Session(engine) as session:
        data = {
            "snapshots": dump_snapshot_table(
                session, by_alias=dump_parameters.by_alias
            ),
            "event_parameters": dump_event_parameter_snapshot_table(
                session, by_alias=dump_parameters.by_alias
            ),
            "seismogram_parameters": dump_seismogram_parameter_snapshot_table(
                session, by_alias=dump_parameters.by_alias
            ),
            "event_quality": dump_event_quality_snapshot_table(
                session, by_alias=dump_parameters.by_alias
            ),
            "seismogram_quality": dump_seismogram_quality_snapshot_table(
                session, by_alias=dump_parameters.by_alias
            ),
        }
        print_json(data=data)

cli_snapshot_list

cli_snapshot_list(
    event_id: Annotated[
        UUID | Literal["all"], event_parameter_with_all()
    ],
    *,
    table_parameters: TableParameters = TableParameters(),
) -> None

Print information on the snapshots for an event.

Source code in src/aimbat/_cli/snapshot.py
@app.command(name="list")
@simple_exception
def cli_snapshot_list(
    event_id: Annotated[UUID | Literal["all"], event_parameter_with_all()],
    *,
    table_parameters: TableParameters = TableParameters(),
) -> None:
    """Print information on the snapshots for an event."""
    from sqlmodel import Session

    from aimbat.core import dump_snapshot_table, resolve_event
    from aimbat.db import engine
    from aimbat.logger import logger
    from aimbat.models import AimbatSnapshotRead
    from aimbat.utils import uuid_shortener

    from .common import json_to_table

    if raw := table_parameters.raw:
        exclude = {"short_id", "short_event_id"}
    else:
        exclude = {"id", "event_id"}

    with Session(engine) as session:
        logger.info("Printing AIMBAT snapshots table.")

        if event_parameter_is_all(event_id):
            event = None
            title = "AIMBAT snapshots for all events"
        else:
            event = resolve_event(session, event_id)
            if raw:
                time = event.time.isoformat()
                id = str(event.id)
                exclude.add("event_id")
            else:
                time = event.time.strftime("%Y-%m-%d %H:%M:%S")
                id = uuid_shortener(session, event)
                exclude.add("short_event_id")
            title = f"AIMBAT snapshots for event {time} (ID={id})"

        snapshot_data = dump_snapshot_table(
            session,
            from_read_model=True,
            event_id=event.id if event else None,
            exclude=exclude,
        )

        json_to_table(
            data=snapshot_data, model=AimbatSnapshotRead, title=title, raw=raw
        )

cli_snapshot_note_edit

cli_snapshot_note_edit(
    snapshot_id: Annotated[
        UUID,
        id_parameter(
            AimbatSnapshot,
            help="UUID (or unique prefix) of snapshot.",
        ),
    ],
    *,
    _: DebugParameter = DebugParameter(),
) -> None

Open the snapshot note in $EDITOR and save changes on exit.

Source code in src/aimbat/_cli/snapshot.py
@_note.command(name="edit")
@simple_exception
def cli_snapshot_note_edit(
    snapshot_id: Annotated[
        UUID,
        id_parameter(AimbatSnapshot, help="UUID (or unique prefix) of snapshot."),
    ],
    *,
    _: DebugParameter = DebugParameter(),
) -> None:
    """Open the snapshot note in `$EDITOR` and save changes on exit."""
    from sqlmodel import Session

    from aimbat.core import get_note_content, save_note
    from aimbat.db import engine

    with Session(engine) as session:
        original = get_note_content(session, "snapshot", snapshot_id)

    updated = open_in_editor(original)

    if updated != original:
        with Session(engine) as session:
            save_note(session, "snapshot", snapshot_id, updated)

cli_snapshot_note_read

cli_snapshot_note_read(
    snapshot_id: Annotated[
        UUID,
        id_parameter(
            AimbatSnapshot,
            help="UUID (or unique prefix) of snapshot.",
        ),
    ],
    *,
    _: DebugParameter = DebugParameter(),
) -> None

Display the note attached to a snapshot, rendered as Markdown.

Source code in src/aimbat/_cli/snapshot.py
@_note.command(name="read")
@simple_exception
def cli_snapshot_note_read(
    snapshot_id: Annotated[
        UUID,
        id_parameter(AimbatSnapshot, help="UUID (or unique prefix) of snapshot."),
    ],
    *,
    _: DebugParameter = DebugParameter(),
) -> None:
    """Display the note attached to a snapshot, rendered as Markdown."""
    from rich.console import Console
    from rich.markdown import Markdown
    from sqlmodel import Session

    from aimbat.core import get_note_content
    from aimbat.db import engine

    with Session(engine) as session:
        content = get_note_content(session, "snapshot", snapshot_id)

    Console().print(Markdown(content) if content else "(no note)")

cli_snapshot_preview

cli_snapshot_preview(
    snapshot_id: Annotated[
        UUID,
        id_parameter(
            AimbatSnapshot,
            help="UUID (or unique prefix) of snapshot to preview.",
        ),
    ],
    *,
    iccs_plot_parameters: IccsPlotParameters = IccsPlotParameters(),
    as_matrix: Annotated[
        bool, Parameter(name=matrix)
    ] = False,
    _: DebugParameter = DebugParameter(),
) -> None

Preview the ICCS stack/matrix of a snapshot.

Source code in src/aimbat/_cli/snapshot.py
@app.command(name="preview")
@simple_exception
def cli_snapshot_preview(
    snapshot_id: Annotated[
        UUID,
        id_parameter(
            AimbatSnapshot, help="UUID (or unique prefix) of snapshot to preview."
        ),
    ],
    *,
    iccs_plot_parameters: IccsPlotParameters = IccsPlotParameters(),
    as_matrix: Annotated[bool, Parameter(name="matrix")] = False,
    _: DebugParameter = DebugParameter(),
) -> None:
    """Preview the ICCS stack/matrix of a snapshot."""
    from sqlmodel import Session

    from aimbat.core import build_iccs_from_snapshot
    from aimbat.db import engine
    from aimbat.plot import plot_matrix_image, plot_stack

    with Session(engine) as session:
        iccs = build_iccs_from_snapshot(session, snapshot_id).iccs
        if as_matrix:
            plot_matrix_image(
                iccs,
                iccs_plot_parameters.context,
                all_seismograms=iccs_plot_parameters.all_seismograms,
                return_fig=False,
            )
        else:
            plot_stack(
                iccs,
                iccs_plot_parameters.context,
                all_seismograms=iccs_plot_parameters.all_seismograms,
                return_fig=False,
            )

cli_snapshot_quality_dump

cli_snapshot_quality_dump(
    *,
    dump_parameters: JsonDumpParameters = JsonDumpParameters(),
) -> None

Dump snapshot quality statistics to JSON.

Output can be piped or redirected for use in external tools or scripts.

Source code in src/aimbat/_cli/snapshot.py
@_quality.command(name="dump")
@simple_exception
def cli_snapshot_quality_dump(
    *, dump_parameters: JsonDumpParameters = JsonDumpParameters()
) -> None:
    """Dump snapshot quality statistics to JSON.

    Output can be piped or redirected for use in external tools or scripts.
    """
    from rich import print_json
    from sqlmodel import Session

    from aimbat.core import dump_snapshot_quality_table
    from aimbat.db import engine

    with Session(engine) as session:
        data = dump_snapshot_quality_table(session, by_alias=dump_parameters.by_alias)

    print_json(data=data)

cli_snapshot_quality_list

cli_snapshot_quality_list(
    event_id: Annotated[
        UUID | Literal["all"], event_parameter_with_all()
    ],
    *,
    table_parameters: TableParameters = TableParameters(),
) -> None

Show aggregated quality statistics for snapshots of an event or all events.

Displays ICCS and MCCC quality metrics (means, SEMs, RMSE) from the frozen quality records of each snapshot.

Source code in src/aimbat/_cli/snapshot.py
@_quality.command(name="list")
@simple_exception
def cli_snapshot_quality_list(
    event_id: Annotated[UUID | Literal["all"], event_parameter_with_all()],
    *,
    table_parameters: TableParameters = TableParameters(),
) -> None:
    """Show aggregated quality statistics for snapshots of an event or all events.

    Displays ICCS and MCCC quality metrics (means, SEMs, RMSE) from the frozen
    quality records of each snapshot.
    """
    from sqlmodel import Session

    from aimbat.core import dump_snapshot_quality_table, resolve_event
    from aimbat.db import engine
    from aimbat.models import AimbatEvent, RichColSpec, SeismogramQualityStats
    from aimbat.utils import uuid_shortener

    from .common import json_to_table

    raw = table_parameters.raw

    with Session(engine) as session:
        if event_parameter_is_all(event_id):
            title = "Quality statistics for all snapshots"
            exclude = None
            filter_event_id = None
        else:
            event = resolve_event(session, event_id)
            label = str(event.id) if raw else uuid_shortener(session, event)
            title = f"Quality statistics for snapshots of event: {label}"
            exclude = {"event_id"}
            filter_event_id = event.id

        col_specs = {
            "event_id": RichColSpec(
                formatter=lambda x: uuid_shortener(session, AimbatEvent, str_uuid=x),
            ),
            "snapshot_id": RichColSpec(
                formatter=lambda x: uuid_shortener(session, AimbatSnapshot, str_uuid=x),
            ),
        }

        data = dump_snapshot_quality_table(
            session,
            event_id=filter_event_id,
            exclude=exclude,
        )

    json_to_table(
        data=data,
        model=SeismogramQualityStats,
        title=title,
        raw=raw,
        col_specs=col_specs,
    )

cli_snapshot_rollback

cli_snapshot_rollback(
    snapshot_id: Annotated[
        UUID,
        id_parameter(
            AimbatSnapshot,
            help="UUID (or unique prefix) of snapshot to use for rollback.",
        ),
    ],
    *,
    _: DebugParameter = DebugParameter(),
) -> None

Rollback to snapshot.

Source code in src/aimbat/_cli/snapshot.py
@app.command(name="rollback")
@simple_exception
def cli_snapshot_rollback(
    snapshot_id: Annotated[
        UUID,
        id_parameter(
            AimbatSnapshot,
            help="UUID (or unique prefix) of snapshot to use for rollback.",
        ),
    ],
    *,
    _: DebugParameter = DebugParameter(),
) -> None:
    """Rollback to snapshot."""
    from sqlmodel import Session

    from aimbat.core import rollback_to_snapshot
    from aimbat.db import engine

    with Session(engine) as session:
        rollback_to_snapshot(session, snapshot_id)

station

View and manage stations.

Functions:

Name Description
cli_station_delete

Delete existing station (for all events).

cli_station_dump

Dump the contents of the AIMBAT station table to JSON.

cli_station_list

Print information on the stations used in an event.

cli_station_note_edit

Open the station note in $EDITOR and save changes on exit.

cli_station_note_read

Display the note attached to a station, rendered as Markdown.

cli_station_quality_dump

Dump station quality statistics to JSON.

cli_station_quality_list

Show aggregated quality statistics for a station or all stations.

cli_station_seismograms_plot

Plot input seismograms for events recorded at this station.

cli_station_delete

cli_station_delete(
    station_id: Annotated[
        UUID,
        id_parameter(
            AimbatStation,
            help="UUID (or unique prefix) of station to delete.",
        ),
    ],
    *,
    _: DebugParameter = DebugParameter(),
) -> None

Delete existing station (for all events).

Source code in src/aimbat/_cli/station.py
@app.command(name="delete")
@simple_exception
def cli_station_delete(
    station_id: Annotated[
        UUID,
        id_parameter(
            AimbatStation,
            help="UUID (or unique prefix) of station to delete.",
        ),
    ],
    *,
    _: DebugParameter = DebugParameter(),
) -> None:
    """Delete existing station (for all events)."""
    from sqlmodel import Session

    from aimbat.core import delete_station
    from aimbat.db import engine

    with Session(engine) as session:
        delete_station(session, station_id)

cli_station_dump

cli_station_dump(
    *,
    dump_parameters: JsonDumpParameters = JsonDumpParameters(),
) -> None

Dump the contents of the AIMBAT station table to JSON.

Output can be piped or redirected for use in external tools or scripts.

Source code in src/aimbat/_cli/station.py
@app.command(name="dump")
@simple_exception
def cli_station_dump(
    *, dump_parameters: JsonDumpParameters = JsonDumpParameters()
) -> None:
    """Dump the contents of the AIMBAT station table to JSON.

    Output can be piped or redirected for use in external tools or scripts.
    """

    from rich import print_json
    from sqlmodel import Session

    from aimbat.core import dump_station_table
    from aimbat.db import engine

    with Session(engine) as session:
        print_json(data=dump_station_table(session, by_alias=dump_parameters.by_alias))

cli_station_list

cli_station_list(
    event_id: Annotated[
        UUID | Literal["all"], event_parameter_with_all()
    ],
    table_parameters: TableParameters = TableParameters(),
) -> None

Print information on the stations used in an event.

Source code in src/aimbat/_cli/station.py
@app.command(name="list")
@simple_exception
def cli_station_list(
    event_id: Annotated[UUID | Literal["all"], event_parameter_with_all()],
    table_parameters: TableParameters = TableParameters(),
) -> None:
    """Print information on the stations used in an event."""
    from sqlmodel import Session

    from aimbat.core import dump_station_table, resolve_event
    from aimbat.db import engine
    from aimbat.logger import logger
    from aimbat.models import AimbatStationRead
    from aimbat.utils import uuid_shortener

    from .common import json_to_table

    if raw := table_parameters.raw:
        exclude = {"short_id"}
    else:
        exclude = {"id"}

    with Session(engine) as session:
        if event_parameter_is_all(event_id):
            logger.debug("Selecting all AIMBAT stations.")
            data = dump_station_table(session, from_read_model=True, exclude=exclude)
            title = "AIMBAT stations for all events"
        else:
            logger.debug("Selecting AIMBAT stations used by event.")
            event = resolve_event(session, event_id)
            data = dump_station_table(
                session,
                event_id=event.id,
                from_read_model=True,
                exclude={"seismogram_count", "event_count"} | exclude,
            )
            if raw:
                title = f"AIMBAT stations for event {event.time} (ID={event.id})"
            else:
                title = f"AIMBAT stations for event {event.time.strftime('%Y-%m-%d %H:%M:%S')} (ID={uuid_shortener(session, event)})"

        json_to_table(data, model=AimbatStationRead, title=title, raw=raw)

cli_station_note_edit

cli_station_note_edit(
    station_id: Annotated[
        UUID,
        id_parameter(
            AimbatStation,
            help="UUID (or unique prefix) of station.",
        ),
    ],
    *,
    _: DebugParameter = DebugParameter(),
) -> None

Open the station note in $EDITOR and save changes on exit.

Source code in src/aimbat/_cli/station.py
@_note.command(name="edit")
@simple_exception
def cli_station_note_edit(
    station_id: Annotated[
        UUID,
        id_parameter(AimbatStation, help="UUID (or unique prefix) of station."),
    ],
    *,
    _: DebugParameter = DebugParameter(),
) -> None:
    """Open the station note in `$EDITOR` and save changes on exit."""
    from sqlmodel import Session

    from aimbat.core import get_note_content, save_note
    from aimbat.db import engine

    with Session(engine) as session:
        original = get_note_content(session, "station", station_id)

    updated = open_in_editor(original)

    if updated != original:
        with Session(engine) as session:
            save_note(session, "station", station_id, updated)

cli_station_note_read

cli_station_note_read(
    station_id: Annotated[
        UUID,
        id_parameter(
            AimbatStation,
            help="UUID (or unique prefix) of station.",
        ),
    ],
    *,
    _: DebugParameter = DebugParameter(),
) -> None

Display the note attached to a station, rendered as Markdown.

Source code in src/aimbat/_cli/station.py
@_note.command(name="read")
@simple_exception
def cli_station_note_read(
    station_id: Annotated[
        UUID,
        id_parameter(AimbatStation, help="UUID (or unique prefix) of station."),
    ],
    *,
    _: DebugParameter = DebugParameter(),
) -> None:
    """Display the note attached to a station, rendered as Markdown."""
    from rich.console import Console
    from rich.markdown import Markdown
    from sqlmodel import Session

    from aimbat.core import get_note_content
    from aimbat.db import engine

    with Session(engine) as session:
        content = get_note_content(session, "station", station_id)

    Console().print(Markdown(content) if content else "(no note)")

cli_station_quality_dump

cli_station_quality_dump(
    *,
    dump_parameters: JsonDumpParameters = JsonDumpParameters(),
) -> None

Dump station quality statistics to JSON.

Output can be piped or redirected for use in external tools or scripts.

Source code in src/aimbat/_cli/station.py
@_quality.command(name="dump")
@simple_exception
def cli_station_quality_dump(
    *, dump_parameters: JsonDumpParameters = JsonDumpParameters()
) -> None:
    """Dump station quality statistics to JSON.

    Output can be piped or redirected for use in external tools or scripts.
    """
    from rich import print_json
    from sqlmodel import Session

    from aimbat.core import dump_station_quality_table
    from aimbat.db import engine

    with Session(engine) as session:
        data = dump_station_quality_table(session, by_alias=dump_parameters.by_alias)

    print_json(data=data)

cli_station_quality_list

cli_station_quality_list(
    station_id: Annotated[
        UUID | Literal["all"], station_parameter_with_all()
    ],
    *,
    table_parameters: TableParameters = TableParameters(),
) -> None

Show aggregated quality statistics for a station or all stations.

Displays ICCS and MCCC quality metrics (means, SEMs) aggregated across all seismograms of each station.

Source code in src/aimbat/_cli/station.py
@_quality.command(name="list")
@simple_exception
def cli_station_quality_list(
    station_id: Annotated[UUID | Literal["all"], station_parameter_with_all()],
    *,
    table_parameters: TableParameters = TableParameters(),
) -> None:
    """Show aggregated quality statistics for a station or all stations.

    Displays ICCS and MCCC quality metrics (means, SEMs) aggregated across
    all seismograms of each station.
    """
    from sqlmodel import Session

    from aimbat.core import dump_station_quality_table
    from aimbat.db import engine
    from aimbat.models import RichColSpec, SeismogramQualityStats
    from aimbat.utils import uuid_shortener

    from .common import json_to_table

    raw = table_parameters.raw
    is_all = station_parameter_is_all(station_id)

    with Session(engine) as session:
        if is_all:
            title = "Quality statistics for all stations"
            exclude = None
        else:
            label = (
                str(station_id)
                if raw
                else uuid_shortener(session, AimbatStation, str_uuid=str(station_id))
            )
            title = f"Quality statistics for station: {label}"
            exclude = {"station_id"}

        col_specs = {
            "station_id": RichColSpec(
                formatter=lambda x: uuid_shortener(session, AimbatStation, str_uuid=x),
            ),
        }

        data = dump_station_quality_table(
            session,
            station_id=None if station_parameter_is_all(station_id) else station_id,
            exclude=exclude,
        )

    json_to_table(
        data=data,
        model=SeismogramQualityStats,
        title=title,
        raw=raw,
        col_specs=col_specs,
    )

cli_station_seismograms_plot

cli_station_seismograms_plot(
    station_id: Annotated[
        UUID,
        id_parameter(
            AimbatStation,
            help="UUID (or unique prefix) of station to plot seismograms for.",
        ),
    ],
    *,
    _: DebugParameter = DebugParameter(),
) -> None

Plot input seismograms for events recorded at this station.

Source code in src/aimbat/_cli/station.py
@app.command(name="plotseis")
@simple_exception
def cli_station_seismograms_plot(
    station_id: Annotated[
        UUID,
        id_parameter(
            AimbatStation,
            help="UUID (or unique prefix) of station to plot seismograms for.",
        ),
    ],
    *,
    _: DebugParameter = DebugParameter(),
) -> None:
    """Plot input seismograms for events recorded at this station."""
    from sqlmodel import Session

    from aimbat.db import engine
    from aimbat.models import AimbatStation
    from aimbat.plot import plot_seismograms

    with Session(engine) as session:
        station = session.get(AimbatStation, station_id)
        if station is None:
            raise ValueError(f"Station with ID {station_id} not found.")
        plot_seismograms(session, station, return_fig=False)

utils

Utilities for AIMBAT.

Modules:

Name Description
app

Utilities for AIMBAT.

sampledata

Download or delete AIMBAT sample data.

app

Utilities for AIMBAT.

The utils subcommand contains useful tools that are not strictly part of an AIMBAT workflow.

sampledata

Download or delete AIMBAT sample data.

The sampledata subcommand manages an example dataset that can be used for testing or learning how to use AIMBAT.

The sample data source url can be viewed or changed via aimbat default <list/set> sampledata_src. Likewise the sample data destination folder be viewed or changed via aimbat default <list/set> sampledata_dir.

Functions:

Name Description
sampledata_cli_delete

Recursively delete sample data directory.

sampledata_cli_download

Download AIMBAT sample data.

sampledata_cli_delete

sampledata_cli_delete(
    *, _: DebugParameter = DebugParameter()
) -> None

Recursively delete sample data directory.

Source code in src/aimbat/_cli/utils/sampledata.py
@app.command(name="delete")
@simple_exception
def sampledata_cli_delete(*, _: DebugParameter = DebugParameter()) -> None:
    """Recursively delete sample data directory."""
    from aimbat.utils import delete_sampledata

    delete_sampledata()

sampledata_cli_download

sampledata_cli_download(
    *,
    force: Annotated[
        bool,
        Parameter(
            help="Delete the download directory and re-download"
        ),
    ] = False,
    _: DebugParameter = DebugParameter(),
) -> None

Download AIMBAT sample data.

Downloads an example dataset to the directory specified in the sampledata_dir AIMBAT default variable.

Source code in src/aimbat/_cli/utils/sampledata.py
@app.command(name="download")
@simple_exception
def sampledata_cli_download(
    *,
    force: Annotated[
        bool, Parameter(help="Delete the download directory and re-download")
    ] = False,
    _: DebugParameter = DebugParameter(),
) -> None:
    """Download AIMBAT sample data.

    Downloads an example dataset to the directory specified in the
    `sampledata_dir` AIMBAT default variable.
    """
    from aimbat.utils import download_sampledata

    download_sampledata(force)