| """Utility functions for layer resolution, validation, and parameter logging.""" |
|
|
| from __future__ import annotations |
|
|
| import logging |
| from typing import Optional |
|
|
| import numpy as np |
| from anndata import AnnData |
| from scipy.sparse import issparse |
|
|
| from . import _constants as C |
|
|
| logger = logging.getLogger("scptr") |
|
|
|
|
| def get_layer(adata: AnnData, layer: str) -> np.ndarray: |
| """Return a dense numpy array for the given layer.""" |
| mat = adata.layers[layer] |
| if issparse(mat): |
| return np.asarray(mat.todense()) |
| return np.asarray(mat) |
|
|
|
|
| def require_layers(adata: AnnData, *layers: str) -> None: |
| """Raise KeyError if any of the specified layers are missing.""" |
| missing = [l for l in layers if l not in adata.layers] |
| if missing: |
| raise KeyError(f"Missing required layers: {missing}") |
|
|
|
|
| def require_obs(adata: AnnData, *keys: str) -> None: |
| """Raise KeyError if any of the specified obs columns are missing.""" |
| missing = [k for k in keys if k not in adata.obs.columns] |
| if missing: |
| raise KeyError(f"Missing required obs columns: {missing}") |
|
|
|
|
| def require_var(adata: AnnData, *keys: str) -> None: |
| """Raise KeyError if any of the specified var columns are missing.""" |
| missing = [k for k in keys if k not in adata.var.columns] |
| if missing: |
| raise KeyError(f"Missing required var columns: {missing}") |
|
|
|
|
| def log_params(adata: AnnData, step: str, params: dict) -> None: |
| """Record run parameters in adata.uns['scptr'].""" |
| if C.UNS_KEY not in adata.uns: |
| adata.uns[C.UNS_KEY] = {} |
| adata.uns[C.UNS_KEY][step] = params |
|
|
|
|
| def to_dense_float32(mat) -> np.ndarray: |
| """Convert a matrix (sparse or dense) to dense float32.""" |
| if issparse(mat): |
| mat = np.asarray(mat.todense()) |
| return np.asarray(mat, dtype=np.float32) |
|
|