hdhelpers

Introduction

hdhelpers is a package designed for and included in the standard installation of the hetida designer.

It contains functions that streamline plotting components, especially those that are used in the hetida platform, by

  • accessing metadata of series, singletsframes and multitsframes that complies with the hetida designer metadata conventions,

  • aditional helper functions like adjusting the timezone of timestamps, series, and dataframes,

  • accessing metadata that the hetida platform writes into the hetida designer’s plot_target_settings context variable (tbd),

  • providing toggleable standardized styling options and json serialization for plotly plots (tbd).

Further Information

Functions

metadata

The examples below use Shared data setup. See Metadata examples for the return shapes and shared examples of the related getters. See Metadata lookup basics for metric selection and missing-field behavior.

Access to the metadata of SERIES, SINGLETSFRAMEs and MULTITSFRAMEs

The metadata follows the hetida designer metadata conventions, see hdhelpers.metadata.conventions for its models. read_metadata gives the metadata of an object as model, whose methods resolve the fallbacks of the conventions. The get_* functions are thin wrappers over these methods.

exception hdhelpers.metadata.MetadataConventionError(issues: list[MetadataConventionIssue])[source]

Bases: ValueError

Raised when required metadata is missing, invalid or of the wrong type.

issues

Individual problems with severity, location and message.

Type:

list[MetadataConventionIssue]

class hdhelpers.metadata.Recording(recording_mode: str | None = None, data_frequency: str | None = None, data_frequency_offset: str | None = None, data_frequency_timezone: str | None = None, recording_aggregation_method: str | None = None)[source]

Bases: object

Immutable recording settings for a metric: mode, frequency and interval alignment.

Metadata lookups use dataset frequency settings when the metric provides none. Recording modes describe when values are recorded:

  • periodic: one value per interval, timestamped at its start. Missing values are gaps.

  • on_change: record changes exceeding the value dimension’s deadband. A value holds until the next one, provided the heartbeat interval is not exceeded.

  • irregular: values at arbitrary points in time.

recording_mode

One of the modes above; None if unknown.

Type:

str | None

data_frequency

Pandas offset alias or timedelta string, e.g. “15min” or “1MS”. For on_change, the maximum time between recordings (heartbeat), even without a change. None if unknown.

Type:

str | None

data_frequency_offset

Shift of the frequency intervals as a timedelta string, e.g. “5min”. None means zero when a frequency is set.

Type:

str | None

data_frequency_timezone

Time zone for aligning frequency intervals, e.g. “Europe/Berlin”. None means UTC when a frequency is set.

Type:

str | None

recording_aggregation_method

For periodic values, how each interval is aggregated, e.g. “MEAN” or “MAX”. None for samples taken at the timestamp.

Type:

str | None

data_frequency_offset and data_frequency_timezone belong to data_frequency: They are None if no data_frequency applies.

hdhelpers.metadata.attach_metadata(obj: Series | DataFrame, data_type: Literal['SERIES', 'SINGLETSFRAME', 'MULTITSFRAME'] | None = None) → SeriesMetadata | SingleTSFrameMetadata | MultiTSFrameMetadata | None[source]

Parse metadata in attrs and attach the resulting immutable model.

Replace convention fields with attrs[“hd_metadata”]; preserve other attrs. An already attached model is returned unchanged.

Parameters:
  • obj – Series or DataFrame to update in place.

  • data_type – Convention for raw attrs, or None to infer it; see Automatic metadata type selection. Used only when no model is attached.

Returns:

SeriesMetadata | SingleTSFrameMetadata | MultiTSFrameMetadata | None – Attached model, or None for absent/invalid metadata. Failure leaves attrs unchanged.

Code example:

Using Shared data setup, attach a model while preserving unrelated attrs:

>>> data = series.copy()
>>> data.attrs["source"] = "example"
>>> meta = md.attach_metadata(data)
>>> meta.unit()
'm'
>>> sorted(data.attrs)
['hd_metadata', 'source']
>>> md.read_metadata(data) is meta
True
>>> md.attach_metadata(data) is meta
True
>>> md.attach_metadata(pd.Series([1.0])) is None
True
hdhelpers.metadata.attrs_to_json(attrs: Mapping[Any, Any]) → dict[Any, Any][source]

Replace attached metadata with its JSON fields in a new attrs dictionary.

Keep unrelated attrs as-is. Omit optional metadata fields set to None or their defaults.

Parameters:

attrs – Pandas attrs mapping; left unchanged.

Returns:

dict[Any, Any] – Dictionary for json.dumps or export. Unrelated attrs must also be JSON-compatible.

Code example:

Using Shared data setup, convert attached models to JSON-compatible dictionaries. This function returns a dictionary; json.dumps produces the JSON string:

>>> import json
>>> data = series.copy()
>>> _ = md.attach_metadata(data)
>>> attrs = md.attrs_to_json(data.attrs)
>>> isinstance(attrs, dict), "hd_metadata" in attrs
(True, False)
>>> encoded = json.dumps(attrs)
>>> json.loads(encoded)["metrics"][0]["value_dimensions"][0]["unit"]
'm'
>>> export = data.copy()
>>> export.attrs = md.attrs_to_json(export.attrs)
>>> "hd_metadata" in data.attrs, "hd_metadata" in export.attrs
(True, False)

The export copy can now be written with export.to_frame().to_parquet("series.parquet") if a pandas Parquet engine is installed. The original keeps its attached model.

hdhelpers.metadata.check_metadata_conventions(obj: Series | DataFrame | Mapping[str, Any], data_type: Literal['SERIES', 'SINGLETSFRAME', 'MULTITSFRAME'] | None = None) → list[MetadataConventionIssue][source]

Report metadata errors and warnings, optionally checking against pandas data.

For pandas inputs, also check metric IDs, value columns and time bounds. An empty list means no issues; warnings alone do not make metadata invalid.

Parameters:
  • obj – Series/DataFrame to check, or a mapping containing metadata.

  • data_type – Convention to check; required for mappings. None infers it from pandas input; see Automatic metadata type selection.

Returns:

list[MetadataConventionIssue] – Issues with severity, location and message. Invalid metadata is reported as issues.

Raises:

ValueError – A metadata mapping is provided without data_type.

Code example:

Using Shared data setup, validate the data and its metadata together, or pass plain metadata with an explicit data type. Issues describe the severity, location and cause:

>>> md.check_metadata_conventions(series)
[]
>>> md.check_metadata_conventions(series.attrs, "SERIES")
[]
>>> invalid = series.copy()
>>> invalid.attrs["metrics"][0]["default_timezone"] = "Mars/Base"
>>> issues = md.check_metadata_conventions(invalid)
>>> [(issue.severity.value, issue.location) for issue in issues]
[('error', 'metrics[0].default_timezone')]
>>> print(issues[0].message)
"Mars/Base" is neither an IANA time zone name like "Europe/Berlin" nor a UTC offset...
hdhelpers.metadata.copy_without_metadata(data: T) → T[source]

Copy a Series or DataFrame with all attrs removed.

Data is shared until either object is modified (pandas copy on write).

Parameters:

data (pd.Series | pd.DataFrame) – Source object; left unchanged.

Returns:

pd.Series | pd.DataFrame – Copy with empty attrs.

Code example:

>>> multitsframe.attrs = {"dataset_metadata": {"metric_key": "id"}, "metrics": []}
>>> data = md.copy_without_metadata(multitsframe)
>>> data.attrs
{}
>>> multitsframe.attrs
{'dataset_metadata': {'metric_key': 'id'}, 'metrics': []}
hdhelpers.metadata.get_default_aggregation_methods(multitsframe: DataFrame) → defaultdict[str, str][source]

Read the default aggregation method for each metric.

Use explicit default_aggregation_method (AVG becomes MEAN). Otherwise, metadata value_data_type selects LAST for boolean/string and MEAN for other types.

Parameters:

multitsframe – DataFrame with per-metric metadata in attrs.

Returns:

defaultdict[str, str] – Method names by metric ID; missing IDs default to MEAN.

Code example:

>>> from hdhelpers.metadata.conventions import MULTITSFRAME_METADATA_EXAMPLE
>>> multitsframe.attrs = MULTITSFRAME_METADATA_EXAMPLE
>>> methods = md.get_default_aggregation_methods(multitsframe)
>>> methods["plant_a.temperature"], methods["plant_a.pressure"]
('MAX', 'MEAN')

See Default aggregation methods for shared examples and return shapes.

hdhelpers.metadata.get_default_timezones(multitsframe: DataFrame) → defaultdict[str, str | None][source]

Read the time zone recommended for calculations on each metric.

Use the metric’s default_timezone, then the dataset’s default_timezone.

Parameters:

multitsframe – DataFrame with per-metric metadata in attrs.

Returns:

defaultdict[str, str | None] – Zone names or UTC offsets by metric ID, or None for unresolved zones. Missing IDs use the dataset default.

Code example:

>>> from hdhelpers.metadata.conventions import MULTITSFRAME_METADATA_EXAMPLE
>>> multitsframe.attrs = MULTITSFRAME_METADATA_EXAMPLE
>>> md.get_default_timezones(multitsframe)["plant_a.pressure"]
'Europe/Berlin'

See Default time zones for shared examples and return shapes.

hdhelpers.metadata.get_display_names(multitsframe: DataFrame, *, include_inherited: bool = False) → defaultdict[str, defaultdict[str, str | None]][source]

Read display labels for each metric and value column.

Use display_name, then name.

Parameters:
  • multitsframe – DataFrame with per-metric metadata in attrs.

  • include_inherited – Use inherited fields last, only for the “value” column.

Returns:

defaultdict[str, defaultdict[str, str | None]] – Labels as result[metric_id][column]; unavailable labels are None.

See Names and display-name fallbacks for shared examples and return shapes.

hdhelpers.metadata.get_measurements(multitsframe: DataFrame, *, include_inherited: bool = False) → defaultdict[str, defaultdict[str, str | None]][source]

Read physical quantities for each metric and value column.

For example, “temperature” is a measurement and “°C” is its unit.

Parameters:
  • multitsframe – DataFrame with per-metric metadata in attrs.

  • include_inherited – Use inherited fields last, only for the “value” column.

Returns:

defaultdict[str, defaultdict[str, str | None]] – Quantities as result[metric_id][column]; unavailable quantities are None.

See Units, measurements and return shapes for shared examples and return shapes.

hdhelpers.metadata.get_metric_info(multitsframe: DataFrame, metric_info: str, *, include_inherited: bool = True) → defaultdict[str, Any][source]

Read a metadata field for each metric.

Search the metric, its “value” column, shared “value” metadata, then inherited fields (if enabled).

Parameters:
  • multitsframe – DataFrame with per-metric metadata in attrs.

  • metric_info – Field name or dotted path, e.g. “sensor.model”.

  • include_inherited – Use inherited fields as a last fallback.

Returns:

defaultdict[str, Any] – Field values by metric ID; unresolved fields are None.

Code example:

>>> from hdhelpers.metadata.conventions import MULTITSFRAME_METADATA_EXAMPLE
>>> multitsframe.attrs = MULTITSFRAME_METADATA_EXAMPLE
>>> md.get_metric_info(multitsframe, "recording_mode")["plant_a.temperature"]
'on_change'

See Metric fields and value-dimension fields for shared examples and return shapes.

hdhelpers.metadata.get_names(multitsframe: DataFrame, *, include_inherited: bool = False) → defaultdict[str, defaultdict[str, str | None]][source]

Read metadata names for each metric and value column.

For the “value” column, try the metric’s name after the column’s own name.

Parameters:
  • multitsframe – DataFrame with per-metric metadata in attrs.

  • include_inherited – Use inherited fields last, only for the “value” column.

Returns:

defaultdict[str, defaultdict[str, str | None]] – Names as result[metric_id][column]; unavailable names are None.

Code example:

>>> from hdhelpers.metadata.conventions import MULTITSFRAME_METADATA_EXAMPLE
>>> multitsframe.attrs = MULTITSFRAME_METADATA_EXAMPLE
>>> md.get_names(multitsframe)["plant_a.pressure"]["value"]
'Plant A pressure'

See Names and display-name fallbacks for shared examples and return shapes.

hdhelpers.metadata.get_queried_interval(data: Series | DataFrame) → tuple[datetime | None, datetime | None][source]

Read the requested UTC time interval from dataset metadata.

Parameters:

data – Series or DataFrame with dataset metadata in attrs.

Returns:

tuple[datetime.datetime | None, datetime.datetime | None] – (start, end) as timezone-aware datetimes, or (None, None) if unavailable.

Code example:

>>> from hdhelpers.metadata.conventions import SERIES_METADATA_EXAMPLE
>>> series.attrs = SERIES_METADATA_EXAMPLE
>>> start, end = md.get_queried_interval(series)
>>> start.isoformat()
'2026-01-01T00:00:00+00:00'

See Units, measurements and return shapes for shared examples and return shapes.

hdhelpers.metadata.get_recordings(multitsframe: DataFrame) → defaultdict[str, Recording][source]

Read recording settings for each metric.

Use the metric’s frequency, offset and time zone together. If its frequency is missing, use the dataset’s three fields instead.

Parameters:

multitsframe – DataFrame with per-metric metadata in attrs.

Returns:

defaultdict[str, Recording] – Settings by metric ID; missing IDs use dataset frequency settings.

Code example:

>>> from hdhelpers.metadata.conventions import MULTITSFRAME_METADATA_EXAMPLE
>>> multitsframe.attrs = MULTITSFRAME_METADATA_EXAMPLE
>>> md.get_recordings(multitsframe)["plant_a.temperature"].recording_mode
'on_change'

See Recording information for shared examples and return shapes.

hdhelpers.metadata.get_series_default_aggregation_method(series: Series) → str[source]

Read the default aggregation method for this Series.

Use explicit default_aggregation_method (AVG becomes MEAN). Otherwise, metadata value_data_type selects LAST for boolean/string and MEAN for other types.

Parameters:

series – Series with metadata in attrs.

Returns:

str – Method name; MEAN if metadata is unavailable.

See Default aggregation methods for shared examples and return shapes.

hdhelpers.metadata.get_series_default_timezone(series: Series) → str | None[source]

Read the time zone recommended for calculations on this Series.

Use the metric’s default_timezone, then the dataset’s default_timezone.

Parameters:

series – Series with metadata in attrs.

Returns:

str | None – Zone name or UTC offset, or None when neither source provides one.

See Default time zones for shared examples and return shapes.

hdhelpers.metadata.get_series_display_name(series: Series, *, include_inherited: bool = False) → str | None[source]

Read the display label for this Series.

Use display_name, then name.

Parameters:
  • series – Series with metadata in attrs.

  • include_inherited – Use inherited fields as a last fallback.

Returns:

str | None – Resolved label, or None when unavailable.

See Names and display-name fallbacks for shared examples and return shapes.

hdhelpers.metadata.get_series_info(series: Series, value_dim_info: str, *, include_inherited: bool = True) → Any[source]

Read a metadata field for this Series.

Search the “value” column, the metric, shared “value” metadata, then inherited fields (if enabled).

Parameters:
  • series – Series with metadata in attrs.

  • value_dim_info – Field name or dotted path, e.g. “sensor.model”.

  • include_inherited – Use inherited fields as a last fallback.

Returns:

Any – Field value, or None when unavailable.

Code example:

>>> from hdhelpers.metadata.conventions import SERIES_METADATA_EXAMPLE
>>> series.attrs = SERIES_METADATA_EXAMPLE
>>> md.get_series_info(series, "decimals")
2

See Metric fields and value-dimension fields for shared examples and return shapes.

hdhelpers.metadata.get_series_measurement(series: Series, *, include_inherited: bool = False) → str | None[source]

Read this Series’ physical quantity from metadata.

For example, “temperature” describes the quantity and “°C” describes its unit.

Parameters:
  • series – Series with metadata in attrs.

  • include_inherited – Use inherited fields as a last fallback.

Returns:

str | None – Quantity name, or None when unavailable.

See Units, measurements and return shapes for shared examples and return shapes.

hdhelpers.metadata.get_series_name(series: Series, *, include_inherited: bool = False) → str | None[source]

Read this Series’ name from metadata.

Try the “value” column’s name, then the metric’s name.

Parameters:
  • series – Series with metadata in attrs.

  • include_inherited – Use inherited fields as a last fallback.

Returns:

str | None – Resolved name, or None when unavailable.

Code example:

>>> from hdhelpers.metadata.conventions import SERIES_METADATA_EXAMPLE
>>> series.attrs = SERIES_METADATA_EXAMPLE
>>> md.get_series_name(series)
'Water level north'

See Names and display-name fallbacks for shared examples and return shapes.

hdhelpers.metadata.get_series_recording(series: Series) → Recording[source]

Read recording settings for this Series.

Use the metric’s frequency, offset and time zone together. If its frequency is missing, use the dataset’s three fields instead.

Parameters:

series – Series with metadata in attrs.

Returns:

Recording – Recording object; absent metadata yields its default field values.

See Recording information for shared examples and return shapes.

hdhelpers.metadata.get_series_short_display_name(series: Series, *, include_inherited: bool = False) → str | None[source]

Read the short display label for this Series.

Use short_display_name, then display_name, then name.

Parameters:
  • series – Series with metadata in attrs.

  • include_inherited – Use inherited fields as a last fallback.

Returns:

str | None – Resolved label, or None when unavailable.

See Names and display-name fallbacks for shared examples and return shapes.

hdhelpers.metadata.get_series_unit(series: Series, *, include_inherited: bool = False) → str | None[source]

Read this Series’ unit from metadata.

Parameters:
  • series – Series with metadata in attrs.

  • include_inherited – Use inherited fields as a last fallback.

Returns:

str | None – Unit string; “” means dimensionless and None means unavailable.

Code example:

>>> from hdhelpers.metadata.conventions import SERIES_METADATA_EXAMPLE
>>> series.attrs = SERIES_METADATA_EXAMPLE
>>> md.get_series_unit(series)
'm'

See Units, measurements and return shapes for shared examples and return shapes.

hdhelpers.metadata.get_short_display_names(multitsframe: DataFrame, *, include_inherited: bool = False) → defaultdict[str, defaultdict[str, str | None]][source]

Read short display labels for each metric and value column.

Use short_display_name, then display_name, then name.

Parameters:
  • multitsframe – DataFrame with per-metric metadata in attrs.

  • include_inherited – Use inherited fields last, only for the “value” column.

Returns:

defaultdict[str, defaultdict[str, str | None]] – Labels as result[metric_id][column]; unavailable labels are None.

See Names and display-name fallbacks for shared examples and return shapes.

hdhelpers.metadata.get_singlets_default_aggregation_method(singletsframe: DataFrame) → str[source]

Read the default aggregation method for a single-metric frame.

Use explicit default_aggregation_method (AVG becomes MEAN). Otherwise, metadata value_data_type selects LAST for boolean/string and MEAN for other types.

Parameters:

singletsframe – DataFrame with one metric’s metadata in attrs.

Returns:

str – Method name; MEAN if metadata is unavailable.

See Default aggregation methods for shared examples and return shapes.

hdhelpers.metadata.get_singlets_default_timezone(singletsframe: DataFrame) → str | None[source]

Read the time zone recommended for calculations on a single-metric frame.

Use the metric’s default_timezone, then the dataset’s default_timezone.

Parameters:

singletsframe – DataFrame with one metric’s metadata in attrs.

Returns:

str | None – Zone name or UTC offset, or None when neither source provides one.

See Default time zones for shared examples and return shapes.

hdhelpers.metadata.get_singlets_display_names(singletsframe: DataFrame, *, include_inherited: bool = False) → defaultdict[str, str | None][source]

Read display labels for each value column of a single-metric frame.

Use display_name, then name.

Parameters:
  • singletsframe – DataFrame with one metric’s metadata in attrs.

  • include_inherited – Use inherited fields last, only for the “value” column.

Returns:

defaultdict[str, str | None] – Labels as result[column]; unavailable labels are None.

See Names and display-name fallbacks for shared examples and return shapes.

hdhelpers.metadata.get_singlets_info(singletsframe: DataFrame, value_dim_info: str, *, include_inherited: bool = True) → defaultdict[str, Any][source]

Read a metadata field for each value column of a single-metric frame.

For “value”, search column, metric, shared and inherited metadata (if enabled), in that order. Other columns use their own and shared metadata.

Parameters:
  • singletsframe – DataFrame with one metric’s metadata in attrs.

  • value_dim_info – Field name or dotted path, e.g. “sensor.model”.

  • include_inherited – Use inherited fields last, only for the “value” column.

Returns:

defaultdict[str, Any] – Field values as result[column]; unresolved fields are None.

Code example:

>>> from hdhelpers.metadata.conventions import SINGLETSFRAME_METADATA_EXAMPLE
>>> dataframe.attrs = SINGLETSFRAME_METADATA_EXAMPLE
>>> md.get_singlets_info(dataframe, "name")["state"]
'measurement state'

See Metric fields and value-dimension fields for shared examples and return shapes.

hdhelpers.metadata.get_singlets_measurements(singletsframe: DataFrame, *, include_inherited: bool = False) → defaultdict[str, str | None][source]

Read physical quantities for each value column of a single-metric frame.

For example, “temperature” is a measurement and “°C” is its unit.

Parameters:
  • singletsframe – DataFrame with one metric’s metadata in attrs.

  • include_inherited – Use inherited fields last, only for the “value” column.

Returns:

defaultdict[str, str | None] – Quantities as result[column]; unavailable quantities are None.

See Units, measurements and return shapes for shared examples and return shapes.

hdhelpers.metadata.get_singlets_metric_info(singletsframe: DataFrame, metric_info: str, *, include_inherited: bool = True) → Any[source]

Read one metadata field for the frame’s single metric.

Search the metric, its “value” column, shared “value” metadata, then inherited fields (if enabled).

Parameters:
  • singletsframe – DataFrame with one metric’s metadata in attrs.

  • metric_info – Field name or dotted path, e.g. “sensor.model”.

  • include_inherited – Use inherited fields as a last fallback.

Returns:

Any – One field value, or None when unavailable.

Code example:

Using Shared data setup, compare a field of the metric with fields of its value dimensions. See Metric fields and value-dimension fields for the related getters:

>>> md.get_singlets_metric_info(dataframe, "name")
'ABC temperature'
>>> md.get_singlets_info(dataframe, "name")["state"]
'measurement state'
hdhelpers.metadata.get_singlets_names(singletsframe: DataFrame, *, include_inherited: bool = False) → defaultdict[str, str | None][source]

Read metadata names for each value column of a single-metric frame.

For “value”, try the metric’s name after the column’s own name.

Parameters:
  • singletsframe – DataFrame with one metric’s metadata in attrs.

  • include_inherited – Use inherited fields last, only for the “value” column.

Returns:

defaultdict[str, str | None] – Names as result[column]; unavailable names are None.

See Names and display-name fallbacks for shared examples and return shapes.

hdhelpers.metadata.get_singlets_recording(singletsframe: DataFrame) → Recording[source]

Read recording settings for a single-metric frame.

Use the metric’s frequency, offset and time zone together. If its frequency is missing, use the dataset’s three fields instead.

Parameters:

singletsframe – DataFrame with one metric’s metadata in attrs.

Returns:

Recording – Recording object; absent metadata yields its default field values.

See Recording information for shared examples and return shapes.

hdhelpers.metadata.get_singlets_short_display_names(singletsframe: DataFrame, *, include_inherited: bool = False) → defaultdict[str, str | None][source]

Read short display labels for each value column of a single-metric frame.

Use short_display_name, then display_name, then name.

Parameters:
  • singletsframe – DataFrame with one metric’s metadata in attrs.

  • include_inherited – Use inherited fields last, only for the “value” column.

Returns:

defaultdict[str, str | None] – Labels as result[column]; unavailable labels are None.

See Names and display-name fallbacks for shared examples and return shapes.

hdhelpers.metadata.get_singlets_units(singletsframe: DataFrame, *, include_inherited: bool = False) → defaultdict[str, str | None][source]

Read units for each value column of a single-metric frame.

Parameters:
  • singletsframe – DataFrame with one metric’s metadata in attrs.

  • include_inherited – Use inherited fields last, only for the “value” column.

Returns:

defaultdict[str, str | None] – Units as result[column]; “” means dimensionless and None means unavailable.

Code example:

>>> from hdhelpers.metadata.conventions import SINGLETSFRAME_METADATA_EXAMPLE
>>> dataframe.attrs = SINGLETSFRAME_METADATA_EXAMPLE
>>> md.get_singlets_units(dataframe)["value"]
'°C'

See Units, measurements and return shapes for shared examples and return shapes.

hdhelpers.metadata.get_units(multitsframe: DataFrame, *, include_inherited: bool = False) → defaultdict[str, defaultdict[str, str | None]][source]

Read units for each metric and value column.

Parameters:
  • multitsframe – DataFrame with per-metric metadata in attrs.

  • include_inherited – Use inherited fields last, only for the “value” column.

Returns:

defaultdict[str, defaultdict[str, str | None]] – Units as result[metric_id][column]; unavailable units are None.

Code example:

>>> from hdhelpers.metadata.conventions import MULTITSFRAME_METADATA_EXAMPLE
>>> multitsframe.attrs = MULTITSFRAME_METADATA_EXAMPLE
>>> units = md.get_units(multitsframe)
>>> units["plant_a.temperature"]["value"]
'°C'
>>> units["unknown metric"]["value"] is None
True

See Units, measurements and return shapes for shared examples and return shapes.

hdhelpers.metadata.read_metadata(obj: Series | DataFrame, data_type: Literal['SERIES'], *, required: Literal[True]) → SeriesMetadata[source]
hdhelpers.metadata.read_metadata(obj: Series | DataFrame, data_type: Literal['SERIES'], *, required: bool = False) → SeriesMetadata | None
hdhelpers.metadata.read_metadata(obj: Series | DataFrame, data_type: Literal['SINGLETSFRAME'], *, required: Literal[True]) → SingleTSFrameMetadata
hdhelpers.metadata.read_metadata(obj: Series | DataFrame, data_type: Literal['SINGLETSFRAME'], *, required: bool = False) → SingleTSFrameMetadata | None
hdhelpers.metadata.read_metadata(obj: Series | DataFrame, data_type: Literal['MULTITSFRAME'], *, required: Literal[True]) → MultiTSFrameMetadata
hdhelpers.metadata.read_metadata(obj: Series | DataFrame, data_type: Literal['MULTITSFRAME'], *, required: bool = False) → MultiTSFrameMetadata | None
hdhelpers.metadata.read_metadata(obj: Series | DataFrame, data_type: None = None, *, required: Literal[True]) → SeriesMetadata | SingleTSFrameMetadata | MultiTSFrameMetadata
hdhelpers.metadata.read_metadata(obj: Series | DataFrame, data_type: None = None, *, required: bool = False) → SeriesMetadata | SingleTSFrameMetadata | MultiTSFrameMetadata | None

Read metadata as a model without changing the input.

Reuse an attached model; otherwise parse convention fields in attrs.

Parameters:
  • obj – Series or DataFrame to read.

  • data_type – Expected convention. None keeps an attached model’s type or infers it for raw attrs; see Automatic metadata type selection.

  • required – If True, raise on missing, invalid or wrong-type metadata instead of returning None.

Returns:

SeriesMetadata | SingleTSFrameMetadata | MultiTSFrameMetadata | None – Attached or newly parsed model; None for missing, invalid or wrong-type metadata.

Raises:

MetadataConventionError – Metadata cannot be returned and required=True.

Code example:

Using Shared data setup, read a model without changing the original attrs:

>>> meta = md.read_metadata(series, required=True)
>>> meta.unit()
'm'
>>> "hd_metadata" in series.attrs
False
>>> missing = pd.Series([1.0])
>>> md.read_metadata(missing) is None
True
>>> try:
...     md.read_metadata(missing, required=True)
... except md.MetadataConventionError as error:
...     print(error.issues[0].message)
No metadata in attrs.
hdhelpers.metadata.set_metadata(obj: Series | DataFrame, meta: SeriesMetadata | SingleTSFrameMetadata | MultiTSFrameMetadata) → None[source]

Attach the supplied metadata model to a result object.

Store it under attrs[“hd_metadata”], replacing convention fields and preserving unrelated attrs.

Parameters:
  • obj – Result Series or DataFrame created by your component; updated in place.

  • meta – Validated metadata model; shared without copying or revalidation.

Returns:

None – Updates obj in place.

Code example:

Convert the metre values from Shared data setup to centimetres and set matching metadata on the result. The original metadata stays unchanged:

>>> meta = md.read_metadata(series, required=True)
>>> result = series * 100
>>> changed = meta.with_value_dimension(None, "value", unit="cm")
>>> md.set_metadata(result, changed)
>>> md.get_series_unit(result), md.get_series_unit(series)
('cm', 'm')
>>> md.read_metadata(result) is changed
True

helpers

Collection of useful functions to ease some operations in hetida designer code.

hdhelpers.helpers.get_locale(explicit_locale: str | None = None) → str | None[source]

Read the explicit locale or plot target locale, normalizing underscores to hyphens.

Parameters:

explicit_locale – Override locale, e.g. “de_DE”. None or “” uses the plot target setting.

Returns:

str | None – Locale such as “de-DE”, or None if no locale is configured.

Code example:

>>> get_locale("de_DE")         # returns "de-DE"
'de-DE'

>>> print(get_locale())         # returns locale from plot target settings of execution or None
None
hdhelpers.helpers.modify_timezone(object_to_convert: T, to_timezone: str | None = None, column_names: list[str] | None = None, convert_index: bool = True) → T[source]

Convert aware timestamps or localize naive timestamps to the selected time zone.

Parameters:
  • object_to_convert (pd.Timestamp | datetime.datetime | pd.Series | pd.DataFrame) – Timestamp, datetime, Series or DataFrame to convert.

  • to_timezone – Target zone, e.g. “Europe/Berlin”. None uses the plot target setting; if unset, naive values use UTC and aware values keep their zone.

  • column_names – Columns to convert. None/[] selects the Series index or DataFrame “timestamp” column. For Series values, pass [series.name]. Ignored for scalars.

  • convert_index – Also convert the pandas index. With column_names=None/[], a Series index is always converted. Ignored for scalars.

Returns:

pd.Timestamp | pd.Series | pd.DataFrame – Timestamp for scalar inputs; converted copy for nonempty pandas inputs. Empty pandas inputs are returned unchanged.

Raises:
  • TypeError – Unsupported input or incompatible timestamp/index values.

  • ValueError – Unknown time zone or invalid datetime values.

  • KeyError – A requested column is absent.

Code example:

>>> from hdhelpers.helpers import modify_timezone
>>> modified_timezone = modify_timezone(pd.to_datetime("2025-01-01T01:00:00+05:00"), to_timezone="Europe/Berlin")
>>> int(modified_timezone.utcoffset().total_seconds())
3600

plotting

Collection of useful functions to ease plotting.

hdhelpers.plotting.resolve_color(color_str: str) → str[source]

Resolve a Fuseki palette name to a color string.

Parameters:

color_str – Palette name, e.g. “ki.energy”, or any other string.

Returns:

str – Resolved color; other strings are returned unchanged.

Code example:

>>> resolve_color("red")
'red'
>>> resolve_color("ki.energy")
'#eb6962'
hdhelpers.plotting.set_agnostic_theme(fig: Figure) → None[source]

Apply a Plotly theme suitable for light and dark backgrounds.

Parameters:

fig – Figure to style.

Returns:

None – The supplied figure is updated in place.

Code example:

>>> import plotly.graph_objects as go
>>> fig = go.Figure(data=go.Scatter(x=[1, 2, 3], y=[1, 4, 9]))
>>> set_agnostic_theme(fig)
hdhelpers.plotting.set_dt_ticks(fig: Figure) → None[source]

Set zoom-dependent, locale-independent date/time labels on all x axes.

Update tickformatstops; timestamps and time zones are unchanged.

Parameters:

fig – Figure to format.

Returns:

None – The supplied figure is updated in place.

Code example:

>>> import plotly.graph_objects as go
>>> fig = go.Figure(data=go.Scatter(x=["2024-01-01", "2024-01-02"], y=[1, 4]))
>>> set_dt_ticks(fig)

exceptions

For metadata validation errors, see hdhelpers.metadata.MetadataConventionError in the metadata API. Its issues attribute contains the individual validation issues.

exception hdhelpers.exceptions.HelperException(*args: Any, error_code: int | str = '', extra_information: dict | None = None, **kwargs: Any)[source]

Bases: Exception

Exception for reporting errors to hetida designer.

error_code

Error identifier; an empty string if unspecified.

Type:

int | str

extra_information

Optional details for the error handler.

Type:

dict | None

exception hdhelpers.exceptions.InsufficientPlottingData(*args: Any, error_code: int | str = '', extra_information: dict | None = None, **kwargs: Any)[source]

Bases: HelperException

Raised when a plot component has insufficient data to produce a meaningful plot.

Frontends can handle this by displaying a message instead of an empty plot.