Source code for piel.analysis.metrics.units

from piel.types import Unit, ScalarMetric, ScalarMetricCollection

from pydantic import ValidationError


[docs] def convert_scalar_metric_unit(metric: ScalarMetric, target_unit: Unit) -> ScalarMetric: """ Converts the units of a single ScalarMetrics instance to the target unit. Args: metric (ScalarMetric): The original scalar metric. target_unit (Unit): The target unit to convert to. Returns: ScalarMetric: A new ScalarMetrics instance with converted values and updated unit. Raises: ValueError: If the original unit and target unit have different 'datum'. """ original_unit = metric.unit if original_unit.datum != target_unit.datum: raise ValueError( f"Cannot convert from unit '{original_unit.name}' (datum: {original_unit.datum}) " f"to unit '{target_unit.name}' (datum: {target_unit.datum}). Units are incompatible." ) # Calculate conversion factor conversion_factor = original_unit.base / target_unit.base # Define a helper function to convert individual numerical fields def convert_field(value): if value is None: return None return value * conversion_factor # Create a new ScalarMetric instance with converted values try: converted_metric = metric.model_copy( update={ "value": convert_field(metric.value), "mean": convert_field(metric.mean), "min": convert_field(metric.min), "max": convert_field(metric.max), "standard_deviation": convert_field(metric.standard_deviation), "unit": target_unit, } ) except ValidationError as e: raise ValueError(f"Error during conversion: {e}") return converted_metric
[docs] def convert_metric_collection_units_per_metric( collection: ScalarMetricCollection, target_units: dict[str, Unit] ) -> ScalarMetricCollection: """ Converts the units of metrics in a ScalarMetricCollection to the target units. Args: collection (ScalarMetricCollection): The original metric collection. target_units (dict[str, Unit]): - If a dictionary is provided, keys should be metrics names and values are the target Units. Returns: ScalarMetricCollection: A new ScalarMetricCollection with converted metrics. Raises: ValueError: If target_units is a dict and a metric name is missing, or if any unit conversion is invalid. """ converted_metrics = [] if isinstance(target_units, dict): # Convert using a mapping of metric names to target units for metric in collection.metrics: if metric.name not in target_units: raise ValueError( f"Target unit for metric '{metric.name}' not provided in target_units dictionary." ) target_unit = target_units[metric.name] converted_metric = convert_scalar_metric_unit(metric, target_unit) converted_metrics.append(converted_metric) # Create a new ScalarMetricCollection with the converted metrics try: converted_collection = collection.model_copy( update={"metrics": converted_metrics} ) except ValidationError as e: raise ValueError(f"Error during collection conversion: {e}") return converted_collection
[docs] def convert_metric_collection_per_unit( collection: ScalarMetricCollection, target_units: dict[str, Unit] ) -> ScalarMetricCollection: """ Converts the units of metrics in a ScalarMetricCollection based on unit names. Args: collection (ScalarMetricCollection): The original metric collection. target_units (dict[str, Unit] ): Returns: ScalarMetricCollection: A new ScalarMetricCollection with converted metrics. Raises: ValueError: If target_units is a dict and a metric's unit name is missing, or if any unit conversion is invalid. """ converted_metrics = [] if isinstance(target_units, dict): # Convert using a mapping of unit names to target units for metric in collection.metrics: current_unit_name = metric.unit.name if current_unit_name not in target_units: # If the metric's unit is not in the mapping, keep it unchanged converted_metrics.append(metric) continue target_unit = target_units[current_unit_name] try: converted_metric = convert_scalar_metric_unit(metric, target_unit) converted_metrics.append(converted_metric) except ValueError as ve: raise ValueError( f"Error converting metric '{metric.name}': {ve}" ) from ve # Create a new ScalarMetricCollection with the converted metrics try: converted_collection = collection.model_copy( update={"metrics": converted_metrics} ) except ValidationError as e: raise ValueError(f"Error during collection conversion: {e}") from e return converted_collection