Source code for vmpt.catalog_ops

"""Pure helpers for the catalog editor — computing weight from priority
and vice versa. Lives outside `main.py` so unit tests don't need to
import Bokeh.
"""

from __future__ import annotations

import numpy as np


[docs] def compute_weights_from_priorities(priorities) -> list[str] | None: """Iterative weight formula. For sources at each priority class (smaller p = higher priority), find the smallest INTEGER w(p) such that simultaneously w(p) > w(p+1) N(p) * w(p) > N(p+1) * w(p+1) iterating from the LOWEST priority class (largest p) upward. Returns a per-row list of stringified ints (NaN priority → "") or None if no finite priorities exist. """ pris: list[float] = [] for v in priorities: try: f = float(str(v).strip()) except (ValueError, TypeError): f = float("nan") pris.append(f) finite_pris = [p for p in pris if np.isfinite(p)] if not finite_pris: return None # Unique priority values, descending (lowest priority class first). classes = sorted(set(finite_pris), reverse=True) counts = {c: sum(1 for p in pris if p == c) for c in classes} weights: dict = {classes[0]: 1} w_prev = 1 n_prev = counts[classes[0]] for q in range(1, len(classes)): c = classes[q] n_q = counts[c] # smallest int w satisfying both inequalities: # w > w_prev AND n_q * w > n_prev * w_prev candidate = max(w_prev + 1, n_prev * w_prev // n_q + 1) weights[c] = candidate w_prev = candidate n_prev = n_q out: list[str] = [] for p in pris: if not np.isfinite(p): out.append("") else: out.append(str(int(weights[p]))) return out
[docs] def compute_priorities_from_weights(weights) -> list[str] | None: """Group rows by unique weight value, descending. Largest weight → priority 1; next → 2; … Rows with non-finite weight get "" (NaN priority).""" ws: list[float] = [] for v in weights: try: f = float(str(v).strip()) except (ValueError, TypeError): f = float("nan") ws.append(f) finite_ws = [w for w in ws if np.isfinite(w)] if not finite_ws: return None classes = sorted(set(finite_ws), reverse=True) # largest weight first p_of: dict = {c: i + 1 for i, c in enumerate(classes)} out: list[str] = [] for w in ws: if not np.isfinite(w): out.append("") else: out.append(str(int(p_of[w]))) return out