Skip to content

KPI & Attributes

KPI dataclass

Single computed KPI with value and rich metadata.

Represents a scalar metric (e.g., "Mean market price for BZ DE-LU in scenario base") with all context needed for filtering, visualization, and unit conversion.

Attributes:

Name Type Description
value float | int

The computed scalar value

attributes KPIAttributes

Rich metadata container

dataset Dataset

Reference to source dataset for lazy model access

Source code in submodules/mesqual/mesqual/kpis/kpi.py
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
@dataclass
class KPI:
    """
    Single computed KPI with value and rich metadata.

    Represents a scalar metric (e.g., "Mean market price for BZ DE-LU in scenario base")
    with all context needed for filtering, visualization, and unit conversion.

    Attributes:
        value: The computed scalar value
        attributes: Rich metadata container
        dataset: Reference to source dataset for lazy model access
    """

    value: float | int
    attributes: KPIAttributes
    dataset: Dataset

    _object_info: pd.Series | None = None
    _quantity: Units.Quantity | None = None

    @property
    def quantity(self) -> Units.Quantity:
        """
        Return value as pint Quantity with unit.

        Returns:
            Quantity with value and unit
        """
        if self._quantity is None:
            unit = self.attributes.unit or self.dataset.flag_index.get_unit(self.attributes.flag)
            self._quantity = self.value * unit
        return self._quantity

    @property
    def name(self) -> str:
        """
        Generate human-readable unique name.

        Returns:
            KPI name (custom or auto-generated)
        """
        if self.attributes.custom_name:
            return self.attributes.custom_name

        return self._generate_automatic_name()

    def _generate_automatic_name(self) -> str:
        """
        Auto-generate name from attributes.

        Format: [prefix] flag aggregation object [comparison/operation] [suffix]

        Returns:
            Generated name string
        """
        parts = []

        if self.attributes.name_prefix:
            parts.append(self.attributes.name_prefix)

        # Core components
        flag_short = str(self.attributes.flag)
        parts.append(flag_short)

        if self.attributes.aggregation:
            parts.append(str(self.attributes.aggregation))

        if self.attributes.object_name:
            parts.append(str(self.attributes.object_name))

        if self.attributes.value_comparison:
            parts.append(str(self.attributes.value_comparison))

        if self.attributes.arithmetic_operation:
            parts.append(str(self.attributes.arithmetic_operation))

        if self.attributes.name_suffix:
            parts.append(self.attributes.name_suffix)

        return ' '.join(parts)

    def get_object_info_from_model(self) -> pd.Series:
        """
        Lazy fetch of object metadata from Model flag.

        Returns:
            Series with object properties from model DataFrame
        """
        if self._object_info is None:
            if self.attributes.model_flag and self.attributes.object_name:
                if isinstance(self.dataset, DatasetComparison):
                    sets = [self.dataset.variation_dataset, self.dataset.reference_dataset]
                else:
                    sets = [self.dataset]
                for ds in sets:
                    if ds.flag_is_accepted(self.attributes.model_flag):
                        model_df = ds.fetch(self.attributes.model_flag)
                        if self.attributes.object_name in model_df.index:
                            self._object_info = model_df.loc[self.attributes.object_name]
                            break
                if self._object_info is None:
                    self._object_info = pd.Series()
        return self._object_info

    def get_kpi_name_with_dataset_name(self) -> str:
        """
        Get KPI name with dataset name for visualization tooltips.

        Returns:
            Name including dataset (e.g., "market_price Mean [base_scenario]")
        """
        base_name = self.name
        if self.attributes.dataset_name:
            return f"{base_name} [{self.attributes.dataset_name}]"
        return base_name

    def to_dict(self, primitive_values: bool = True) -> dict:
        """
        Export KPI as flat dictionary for tables.

        Args:
            primitive_values: If True, convert objects to strings for serialization

        Returns:
            Dictionary with all KPI data
        """
        return {
            'name': self.name,
            'value': self.value,
            'quantity': str(self.quantity) if primitive_values else self.quantity,
            **self.attributes.as_dict(primitive_values=primitive_values),
        }

    def __repr__(self) -> str:
        """String representation of KPI."""
        return f"KPI(name='{self.name}', value={self.value}, unit={self.quantity.units})"

quantity property

quantity: Quantity

Return value as pint Quantity with unit.

Returns:

Type Description
Quantity

Quantity with value and unit

name property

name: str

Generate human-readable unique name.

Returns:

Type Description
str

KPI name (custom or auto-generated)

get_object_info_from_model

get_object_info_from_model() -> Series

Lazy fetch of object metadata from Model flag.

Returns:

Type Description
Series

Series with object properties from model DataFrame

Source code in submodules/mesqual/mesqual/kpis/kpi.py
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
def get_object_info_from_model(self) -> pd.Series:
    """
    Lazy fetch of object metadata from Model flag.

    Returns:
        Series with object properties from model DataFrame
    """
    if self._object_info is None:
        if self.attributes.model_flag and self.attributes.object_name:
            if isinstance(self.dataset, DatasetComparison):
                sets = [self.dataset.variation_dataset, self.dataset.reference_dataset]
            else:
                sets = [self.dataset]
            for ds in sets:
                if ds.flag_is_accepted(self.attributes.model_flag):
                    model_df = ds.fetch(self.attributes.model_flag)
                    if self.attributes.object_name in model_df.index:
                        self._object_info = model_df.loc[self.attributes.object_name]
                        break
            if self._object_info is None:
                self._object_info = pd.Series()
    return self._object_info

get_kpi_name_with_dataset_name

get_kpi_name_with_dataset_name() -> str

Get KPI name with dataset name for visualization tooltips.

Returns:

Type Description
str

Name including dataset (e.g., "market_price Mean [base_scenario]")

Source code in submodules/mesqual/mesqual/kpis/kpi.py
121
122
123
124
125
126
127
128
129
130
131
def get_kpi_name_with_dataset_name(self) -> str:
    """
    Get KPI name with dataset name for visualization tooltips.

    Returns:
        Name including dataset (e.g., "market_price Mean [base_scenario]")
    """
    base_name = self.name
    if self.attributes.dataset_name:
        return f"{base_name} [{self.attributes.dataset_name}]"
    return base_name

to_dict

to_dict(primitive_values: bool = True) -> dict

Export KPI as flat dictionary for tables.

Parameters:

Name Type Description Default
primitive_values bool

If True, convert objects to strings for serialization

True

Returns:

Type Description
dict

Dictionary with all KPI data

Source code in submodules/mesqual/mesqual/kpis/kpi.py
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
def to_dict(self, primitive_values: bool = True) -> dict:
    """
    Export KPI as flat dictionary for tables.

    Args:
        primitive_values: If True, convert objects to strings for serialization

    Returns:
        Dictionary with all KPI data
    """
    return {
        'name': self.name,
        'value': self.value,
        'quantity': str(self.quantity) if primitive_values else self.quantity,
        **self.attributes.as_dict(primitive_values=primitive_values),
    }

__repr__

__repr__() -> str

String representation of KPI.

Source code in submodules/mesqual/mesqual/kpis/kpi.py
150
151
152
def __repr__(self) -> str:
    """String representation of KPI."""
    return f"KPI(name='{self.name}', value={self.value}, unit={self.quantity.units})"

KPIAttributes dataclass

Rich metadata container for KPI instances.

Stores all context needed for filtering, grouping, visualization, and unit conversion of KPI values.

Attributes:

Name Type Description
flag FlagTypeProtocol

Variable flag (e.g., 'BZ.Results.market_price')

model_flag FlagTypeProtocol | None

Associated model flag (e.g., 'BZ.Model')

object_name Hashable | None

Specific object identifier (e.g., 'DE-LU')

aggregation Aggregation | None

Aggregation applied (e.g., Aggregations.Mean)

dataset_name str

Name of the dataset

dataset_type Type[Dataset]

Type of dataset ('scenario', 'comparison', etc.)

value_comparison ValueComparison | None

Comparison operation for comparison KPIs

arithmetic_operation ArithmeticValueOperation | None

Arithmetic operation for derived KPIs

reference_dataset_name str | None

Reference dataset for comparisons

variation_dataset_name str | None

Variation dataset for comparisons

name_prefix str

Custom prefix for KPI name

name_suffix str

Custom suffix for KPI name

custom_name str | None

Complete custom name override

unit Unit | None

Physical unit of the KPI value

target_unit Unit | None

Target unit for conversion

dataset_attributes dict[str, Any]

Additional attributes from dataset (e.g., scenario attributes)

extra_attributes dict[str, Any]

Extra attributes set by user (e.g. for filtering / grouping purposes)

Source code in submodules/mesqual/mesqual/kpis/attributes.py
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
@dataclass
class KPIAttributes:
    """
    Rich metadata container for KPI instances.

    Stores all context needed for filtering, grouping, visualization,
    and unit conversion of KPI values.

    Attributes:
        flag: Variable flag (e.g., 'BZ.Results.market_price')
        model_flag: Associated model flag (e.g., 'BZ.Model')
        object_name: Specific object identifier (e.g., 'DE-LU')
        aggregation: Aggregation applied (e.g., Aggregations.Mean)
        dataset_name: Name of the dataset
        dataset_type: Type of dataset ('scenario', 'comparison', etc.)
        value_comparison: Comparison operation for comparison KPIs
        arithmetic_operation: Arithmetic operation for derived KPIs
        reference_dataset_name: Reference dataset for comparisons
        variation_dataset_name: Variation dataset for comparisons
        name_prefix: Custom prefix for KPI name
        name_suffix: Custom suffix for KPI name
        custom_name: Complete custom name override
        unit: Physical unit of the KPI value
        target_unit: Target unit for conversion
        dataset_attributes: Additional attributes from dataset (e.g., scenario attributes)
        extra_attributes: Extra attributes set by user (e.g. for filtering / grouping purposes)
    """

    # Core identifiers
    flag: FlagTypeProtocol
    model_flag: FlagTypeProtocol | None = None
    object_name: Hashable | None = None
    aggregation: Aggregation | None = None

    # Dataset context
    dataset_name: str = ''
    dataset_type: Type[Dataset] = None

    # Comparison-specific
    value_comparison: ValueComparison | None = None
    arithmetic_operation: ArithmeticValueOperation | None = None
    reference_dataset_name: str | None = None
    variation_dataset_name: str | None = None

    # Naming
    name_prefix: str = ''
    name_suffix: str = ''
    custom_name: str | None = None

    # Unit handling
    unit: Units.Unit | None = None

    # Additional attributes
    dataset_attributes: dict[str, Any] = field(default_factory=dict)
    extra_attributes: dict[str, Any] = field(default_factory=dict)

    def as_dict(self, primitive_values: bool = True) -> dict[str, Any]:
        """
        Export attributes as dictionary for filtering.

        Args:
            primitive_values: If True, convert objects to strings for serialization

        Returns:
            Dictionary representation of attributes
        """
        d = {
            'flag': self.flag,
            'model_flag': self.model_flag,
            'object_name': self.object_name,
            'aggregation': self.aggregation,
            'dataset_name': self.dataset_name,
            'dataset_type': self.dataset_type,
            'value_comparison': self.value_comparison,
            'arithmetic_operation': self.arithmetic_operation,
            'reference_dataset_name': self.reference_dataset_name,
            'variation_dataset_name': self.variation_dataset_name,
            'name_prefix': self.name_prefix,
            'name_suffix': self.name_suffix,
            'custom_name': self.custom_name,
            'unit': self.unit,
            **self.dataset_attributes,
            **self.extra_attributes
        }
        if primitive_values:
            d = {k: _to_primitive(v) for k, v in d.items()}
        return d

    def get(self, key: str, default: Any = None) -> Any:
        """
        Dict-like get interface for compatibility.

        Args:
            key: Attribute key to retrieve
            default: Default value if key not found

        Returns:
            Attribute value or default
        """
        return self.as_dict().get(key, default)

as_dict

as_dict(primitive_values: bool = True) -> dict[str, Any]

Export attributes as dictionary for filtering.

Parameters:

Name Type Description Default
primitive_values bool

If True, convert objects to strings for serialization

True

Returns:

Type Description
dict[str, Any]

Dictionary representation of attributes

Source code in submodules/mesqual/mesqual/kpis/attributes.py
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
def as_dict(self, primitive_values: bool = True) -> dict[str, Any]:
    """
    Export attributes as dictionary for filtering.

    Args:
        primitive_values: If True, convert objects to strings for serialization

    Returns:
        Dictionary representation of attributes
    """
    d = {
        'flag': self.flag,
        'model_flag': self.model_flag,
        'object_name': self.object_name,
        'aggregation': self.aggregation,
        'dataset_name': self.dataset_name,
        'dataset_type': self.dataset_type,
        'value_comparison': self.value_comparison,
        'arithmetic_operation': self.arithmetic_operation,
        'reference_dataset_name': self.reference_dataset_name,
        'variation_dataset_name': self.variation_dataset_name,
        'name_prefix': self.name_prefix,
        'name_suffix': self.name_suffix,
        'custom_name': self.custom_name,
        'unit': self.unit,
        **self.dataset_attributes,
        **self.extra_attributes
    }
    if primitive_values:
        d = {k: _to_primitive(v) for k, v in d.items()}
    return d

get

get(key: str, default: Any = None) -> Any

Dict-like get interface for compatibility.

Parameters:

Name Type Description Default
key str

Attribute key to retrieve

required
default Any

Default value if key not found

None

Returns:

Type Description
Any

Attribute value or default

Source code in submodules/mesqual/mesqual/kpis/attributes.py
118
119
120
121
122
123
124
125
126
127
128
129
def get(self, key: str, default: Any = None) -> Any:
    """
    Dict-like get interface for compatibility.

    Args:
        key: Attribute key to retrieve
        default: Default value if key not found

    Returns:
        Attribute value or default
    """
    return self.as_dict().get(key, default)