Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
## [0.0.2] - 2026-XX-XX
## [0.0.3] - 2026-06-23
- Fixes in modifiy_timezone
- Disarm dependencies to ease compatibility to designer development
- Enhance documentation

## [0.0.2] - 2026-05-21
- Include helpers for metadata
- Include helper function for modify timezone
- Publish sphinx documentation on GitHub Pages
Expand Down
18 changes: 15 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ writing component code.
Once you are done writing your code, including unit tests, use `./run check` to see if your code quality is sufficient.

### Documentation
Fr documentation we use the tool sphinx. Please apply `./run build_docs` to create the current state of documentation. It will be stored in **docs**. You can open the documentation by opening `docs/index.html`, e.g. with your browser.
For documentation we use the tool sphinx. Please apply `./run build_docs` to create the current state of documentation. It will be stored in **docs**. You can open the documentation by opening `docs/index.html`, e.g. with your browser.

### Build, Release and Publish
The first step for publishing a new package version is creating and merging a pull request from develop to main.
Expand All @@ -96,9 +96,21 @@ To **publish** the build from the `dist` subdirectory to PyPI,

1) tag your main branch with the specified package version

2) use `uv publish --index testpypi --token <API-token>`. You need a (Test-)PyPI account with a token and you need maintainer/owner access to the [hdhelpers (Test-)PyPI project](https://pypi.org/project/hdhelpers/).
2) use `uv publish --index testpypi --token <API-token>`. You need a Test-PyPI account with a token and you need maintainer/owner access to the [hdhelpers Test-PyPI project](https://test.pypi.org/project/hdhelpers/).

3) After publishing please communicate to the hetida designer team so upgrade there dependencies.
3) verifiy that package can be installed by using:
```bash
uv run --with 'hdhelpers==<version>'
--refresh-package hdhelpers
--default-index https://test.pypi.org/simple/
--index https://test.pypi.org/simple/
--no-project
-- python -c "import hdhelpers; print(hdhelpers.__version__)"
```

4) use `uv publish dist/*` to upload the package on [hdhelpers PyPI project](https://pypi.org/project/hdhelpers/).

5) After publishing please communicate to the hetida designer team so upgrade there dependencies.
The hetida designer docker compose setup installs hdhelpers from [PyPI](https://pypi.org) as it does with any dependency listed in `runtime/requirements.in`.

### Notes
Expand Down
121 changes: 21 additions & 100 deletions docs/_sources/first_steps.rst.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ First steps
How to get metadata with hdhelpers?
===================================

Let's say we want to plot a timeseries with data points.
In hetida designer this series can be represented as json for *direct provisioning* :
Let's say we want to retrieve the metadata of a timeseries.
In hetida designer this series can be represented as json for *direct provisioning*

.. code-block:: json

Expand Down Expand Up @@ -34,7 +34,7 @@ In hetida designer this series can be represented as json for *direct provisioni
}
}

We can retrieve the name and unit for example with the following code
We can retrieve the name and unit of the series with the following code

.. code-block:: python

Expand All @@ -43,7 +43,7 @@ We can retrieve the name and unit for example with the following code
def main(*, series):
# entrypoint function for this component
# ***** DO NOT EDIT LINES ABOVE *****
# write your function code here.

name = get_series_name(series)
unit = get_series_unit(series)

Expand All @@ -54,36 +54,14 @@ We can retrieve the name and unit for example with the following code
How to use hdhelpers for plotting? (tbd)
========================================

Let's say we want to plot a timeseries with data points.
In hetida designer this series can be represented as json for *direct provisioning* :
Let's say we want to plot the same timeseries above using hdhelpers functionalities.
For example, we want to:
- plot the timeseries in a corresponding timezone,
- set the limits of the x-axis corresponding to the metadata,
- define the label of the y-axis corresponding to the metadata,
- and use standard colors for plotting.

.. code-block:: json

{
"__hd_wrapped_data_object__":"SERIES",
"__metadata__": {
"single_metric_dataset_metadata": {
"ref_interval_end_timestamp":"2020-01-01T08:20:00.000Z",
"ref_interval_start_timestamp": "2020-01-01T08:10:00.000Z"
},
"single_metric_metadata": {
"structured_metadata": {
"metric": {
"short_display_name": "Water Level",
"unit": "cm"
}
}
}
},
"__data__": {
"2020-01-01T08:10:00+00:00": 1,
"2020-01-01T08:15:00+00:00": 2,
"2020-01-01T08:16:00+00:00": 3,
"2020-01-01T08:17:00+00:00": 4,
}
}

Our component code might look like this to plot this series:
Our component code might look like this to plot the timeseries accordingly:

.. code-block:: python

Expand All @@ -94,7 +72,7 @@ Our component code might look like this to plot this series:
def main(*, series):
# entrypoint function for this component
# ***** DO NOT EDIT LINES ABOVE *****
# write your function code here.

series = modify_timezone(series)

colors = get_colors_from_plot_target_settings()
Expand All @@ -108,72 +86,15 @@ Our component code might look like this to plot this series:

return {"plot": plotly_fig_to_json_dict(fig=fig)}

First, we use *modify_timezone* to set the timezone. Since our goal is just to make sure that the timestamps are
timezone aware, not to convert it to a specific timezone, we do not pass a value for the `timezone` parameter. That way,
if there is a `plot_target_timezone` set in the hetida designer's `plot_target_settings` context variable, that timezone
will be used. Otherwise, the timestamps keep their current timezone or are converted to UTC if they are timezone naive.

With the timezone-corrected data in place, we turn it into a plotly Scatter Figure object called `fig`, that we can then
style to our liking. We want to customize said scatter plot by coloring the markers. To find a fitting color, we use
`get_colors_from_plot_target_settings`, which returns the `plot_target_style` property of the `plot_target_settings`
context variable. It contains a set of colors with specific purposes, such as `background_color`, and the
`status_colors` object, which in turn contains the four status colors: `success_color`, `error_color`, `warn_color`, and
`info_color`. The status colors have no hardwired use in a plot, but are intended to convey a message. In our example,
we want to communicate that the order of magnitude of our data is potentially dangerous, so we use the `warn_color` for
`fig`'s `marker["color"]` property, which determines the plot's marker and line color.

Now, we use `get_and_pad_start_and_end_timestamp` for precise control over the x-axis range. We do not set `start` and
`end` explicitly because we want to parse them from the series metadata, which reflects the chosen interval for which
plotting data was requested. This way, we can see that there is missing data from 8:18 to 8:20, where normally Plotly
would not have included that time range in the plot. We do not pass a `timezone` for the same reasons as with
`modify_timezone`. We also set a `start_padding`, so the markers of the first data point is not cut in half by the edge
of the plot. With start and end parsed, we can update `fig`'s x-axis range.

Next, we use `get_y_axis_label` so our y-axis can be labeled with the series metadata. With the above input series,
title and unit will be parsed from the series metadata, but in case the component is ever run without series metadata,
we provide a `default_title`, but we leave the `default_unit` at its empty default value. Then, we update `fig` with our
title.

Lastly, we use `plotly_fig_to_json_dict` to apply standardized stylings and serialize the plotly figure into a json
dict. All the standardized styling options are active by default, as detailed in [Styling Flags](#flags), so we do not
have to set any for this example.

As a result we get the following plot:

Further Explanation
===================

* `use_platform_defaults=True` sets the following flags to `True`, which are by default `False`:
* `hide_legend` sets the plotly layout parameter `showlegend=False` to hide the plot's legend
* `hide_x_title` sets the plotly xaxes parameter `title_text=''` to hide the x-axis title
* `remove_plotly_bar` sets the plotly figure's `displayModeBar` setting to `False` to remove the plotly bar from the plot
* `update_x_axes_tickformat` sets the plotly xaxes parameter `tickformat` to the `datetime_tick_format` property the hetida platform writes into the hetida designer's `plot_target_settings` context variable (unless the property is `None`)
* `use_default_standoff` sets the plotly yaxes parameter `title_standoff=5`
* `use_muplot_axes_color` sets the plotly xaxes and yaxes parameter `color` to the `axes_label_color` property the hetida platform writes into the hetida designer's `plot_target_settings` context variable (unless the property is `None`)
* `use_muplot_grid` makes the plotly grid visible and colors it in according to the `grid_color` property the hetida platform writes into the hetida designer's `plot_target_settings` context variable (unless the property is `None`)
* `use_muplot_line_and_markers` sets the plotly traces to the following style, which matches the hetida platform's µplots:
Explanation
-----------

.. code-block:: json
- *modify_timezone*: We use `modify_timezone` function to set the timezone. Since our goal is just to make sure that the timestamps are timezone aware, not to convert it to a specific timezone, we do not pass a value for the `timezone` parameter. That way, if there is a `plot_target_timezone` set in the hetida designer's `plot_target_settings` context variable, that timezone will be used. Otherwise, the timestamps keep their current timezone or are converted to UTC if they are timezone naive.

{
"marker": {"size": 3},
"line": {"width": 1},
"mode": "lines+markers",
"marker_symbol": "circle",
}
- *get_colors_from_plot_target_settings*: To use a (global) standard color, we use `get_colors_from_plot_target_settings`, which returns the `plot_target_style` property of the `plot_target_settings` context variable. It contains a set of colors with specific purposes, such as `background_color`, and the `status_colors` object, which in turn contains the four status colors: `success_color`, `error_color`, `warn_color`, and `info_color`. The status colors have no hardwired use in a plot, but are intended to convey a message. In our example, we want to communicate that the order of magnitude of our data is potentially dangerous, so we use the `warn_color` for `fig`'s `marker["color"]` property, which determines the plot's marker and line color.

- *get_and_pad_start_and_end_timestamp*: We use `get_and_pad_start_and_end_timestamp` for precise control over the x-axis range. We do not set `start` and `end` explicitly because we want to parse them from the metadata, which reflects the chosen interval for which the data was requested. This way, we can see that there is missing data from 8:18 to 8:20. In the default behaviour of plotly this time range would not have been included possibly hiding missing data. Note: (1) We do not pass a `timezone` for the same reasons as with `modify_timezone`. (2) We also set a `start_padding`, so the markers of the first data point is not cut in half by the edge of the plot.

- *get_y_axis_label*: We use `get_y_axis_label` so our y-axis can be labeled by using information from the metadata. With the above input series, title and unit will be parsed from the metadata. In case the metadata does not contain the mentioned information, we provide a `default_title`, and `default_unit` to configure the axis label in such cases.

* `use_platform_background` sets the plotly layout parameter `paper_bgcolor` to the `background_color` property the
hetida platform writes into the hetida designer's `plot_target_settings` context variable (unless the property is
`None`) and it sets `plot_bgcolor=rgba(0,0,0,0)` so the "paper background" is visible through the "plot background"
* `plotly_fig_to_json_dict` has four more boolean parameters:
* `add_config_settings` sets the plotly figure's locale to
the `plot_target_locale` property the hetida platform writes into the hetida designer's `plot_target_settings` context
variable (unless the property is `None`)
* `remove_plotly_icon` sets the plotly figure's `displaylogo` setting to
`False` to remove the plotly logo from the plot
* `use_minimum_margin` sets the plotly layout parameter
`margin={"autoexpand": True, "l": 0, "r": 0, "b": 0, "t": 0, "pad": 0}` to minimize the plot's margins
* `use_platform_colorway` sets the plotly layout parameter `colorway` to the `line_colors` property the hetida platform
writes into the hetida designer's `plot_target_settings` context variable (unless the property is `None`). Note that in
Plotly, explicitly set line colors have higher priority than those in the colorway, so setting this parameter to `False`
is rarely necessary. * `use_simple_white_template` sets the plotly layout parameter `template=simple_white`
- *plotly_fig_to_json_dict*: We use `plotly_fig_to_json_dict` to apply standardized stylings and serialize the plotly figure into a json dict. All the standardized styling options are active by default, as detailed in [Styling Flags](#flags), so we do not have to set any for this example.
8 changes: 4 additions & 4 deletions docs/_sources/index.rst.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ hdhelpers is a package designed for and included in the standard installation of

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

* accessing series metadata that complies with the hetida platform metadata scheme
* 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)
* accessing series metadata that complies with the hetida platform metadata scheme,
* 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).

.. _hetida designer: https://github.com/hetida/hetida-designer
.. _hetida platform: https://hetida.io/
Expand Down
Loading