acia.analysis.units#

Unit representations for property-extractor tables.

The property extractors produce plain numeric values together with a mapping of column -> physical unit. This module bridges between three representations of that data:

  • plain floats – numeric columns, the unit map carried in df.attrs["units"]. Fast and unsurprising, but not unit-safe: arithmetic ignores the units entirely.

  • header form – plain float values with the unit kept as an extra column index level (pint-pandas’ “dequantified” form). Good for CSV export and readable tables, but still not unit-safe.

  • pint dtype – columns of dtype pint[<unit>] (pint-pandas extension arrays). This is the only unit-safe representation: arithmetic propagates units and raises on dimensional mismatch, .pint.to(...) converts, and .pint.magnitude drops back to plain floats.

The header form and the attrs map are inert carriers; call attach_units() (or df.pint.quantify()) to turn them back into the pint dtype before doing unit-correct computation.

acia.analysis.units.UNIT_ATTR = 'units'#

key under which the column -> unit-string mapping is stored in df.attrs

acia.analysis.units.attach_units(df, units=None, include_dimensionless=False)[source]#

Convert numeric columns into unit-safe pint[...] columns.

Parameters:
  • df (DataFrame) – a DataFrame of plain numeric columns (e.g. the output of acia.analysis.ExtractorExecutor.execute()).

  • units (dict | None) – column -> unit-string mapping. Defaults to df.attrs["units"].

  • include_dimensionless (bool) – if False (default), columns whose unit is dimensionless (e.g. id, frame, circularity) are left as plain numbers so they stay index/merge friendly.

Returns:

A new DataFrame; dimensioned columns have dtype pint[<unit>]. The index and any unmapped columns are preserved unchanged.

Return type:

DataFrame

acia.analysis.units.strip_units(df)[source]#

Inverse of attach_units(): turn pint columns back into floats.

Returns:

(plain_df, units) where plain_df has plain numeric columns (with the unit mapping stored in plain_df.attrs["units"]) and units maps each column to its unit string.

Parameters:

df (DataFrame)

Return type:

tuple[DataFrame, dict[str, str]]

acia.analysis.units.units_in_header(df, units=None)[source]#

Return the “header” form: plain floats with the unit as a column level.

Equivalent to attach_units(df, units).pint.dequantify(). The result is export-friendly (e.g. to_csv) but not unit-safe; use from_header() to recover the pint dtype for computation.

Parameters:
  • df (DataFrame)

  • units (dict | None)

Return type:

DataFrame

acia.analysis.units.from_header(df)[source]#

Inverse of units_in_header(): header form -> unit-safe pint dtype.

Parameters:

df (DataFrame)

Return type:

DataFrame

acia.analysis.units.write_units_csv(df, path, **to_csv_kwargs)[source]#

Write df to CSV with its units (the unit-carrying header form).

A one-liner around units_in_header() + to_csv so tables are never stored without their units. Round-trips with read_units_csv(). Extra keyword arguments are forwarded to pandas.DataFrame.to_csv().

Parameters:
  • df (DataFrame) – a table of plain-float columns (with df.attrs["units"]) or pint[...] columns.

  • path – destination CSV path.

Returns:

str(path) for convenience.

Return type:

str

acia.analysis.units.read_units_csv(path, **read_csv_kwargs)[source]#

Read a CSV written by write_units_csv() back into pint[...] columns.

The returned DataFrame is unit-aware: arithmetic propagates units and derived columns get their units automatically (e.g. df["area"] / df["time"] yields a pint[micrometer ** 2 / minute] column). Columns without a unit (e.g. an id or a label) come back as plain columns. header / index_col default to the two-row unit header and first-column index; any other keyword arguments are forwarded to pandas.read_csv().

Parameters:

path – a CSV produced by write_units_csv().

Returns:

A DataFrame with unit-safe pint columns (see from_header()).

Return type:

DataFrame