
.. DO NOT EDIT.
.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY.
.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE:
.. "gallery/02_writing_files/p02_writing_datasets_with_attributes.py"
.. LINE NUMBERS ARE GIVEN BELOW.

.. only:: html

    .. note::
        :class: sphx-glr-download-link-note

        :ref:`Go to the end <sphx_glr_download_gallery_02_writing_files_p02_writing_datasets_with_attributes.py>`
        to download the full example code.

.. rst-class:: sphx-glr-example-title

.. _sphx_glr_gallery_02_writing_files_p02_writing_datasets_with_attributes.py:


Writing Datasets with Attributes
=================================

Attach metadata attributes to HDF5 and HDF4 datasets, and understand datatype
restrictions specific to each format.

This example demonstrates how to attach key-value metadata attributes to PSI-style
HDF datasets using the ``**kwargs`` interface of :func:`~psi_io.psi_io.write_hdf_data`.
It also illustrates the datatype restrictions imposed by the HDF4 format and how to
handle attribute write failures gracefully using the ``strict`` parameter.

.. GENERATED FROM PYTHON SOURCE LINES 13-19

.. code-block:: Python


    import tempfile
    from pathlib import Path
    import numpy as np
    from psi_io import write_hdf_data, read_hdf_meta








.. GENERATED FROM PYTHON SOURCE LINES 20-22

Construct a simple 2D dataset with coordinate scales, representing a binary
coronal hole map in (θ, φ):

.. GENERATED FROM PYTHON SOURCE LINES 22-28

.. code-block:: Python


    nt, np_ = 180, 360
    t = np.linspace(0.0, np.pi, nt, dtype=np.float32)
    p = np.linspace(0.0, 2*np.pi, np_, dtype=np.float32)
    chmap = np.zeros((np_, nt), dtype=np.float32)








.. GENERATED FROM PYTHON SOURCE LINES 29-34

**Writing attributes to an HDF5 file**

Attributes are passed as keyword arguments to :func:`~psi_io.psi_io.write_hdf_data`.
For HDF5 files, attribute values are stored via :mod:`h5py`, which accepts most
Python and NumPy types without restriction:

.. GENERATED FROM PYTHON SOURCE LINES 34-49

.. code-block:: Python


    with tempfile.TemporaryDirectory() as tmpdir:
        out_h5 = Path(tmpdir) / "chmap.h5"
        write_hdf_data(out_h5, chmap, t, p,
                       description="Coronal Hole Map",
                       source="synthetic",
                       resolution=np.float32(1.0),
                       cr_number=np.int32(2190))

        meta = read_hdf_meta(out_h5)
        print(f"Dataset : {meta[0].name!r},  shape={meta[0].shape}")
        print("Attributes:")
        for key, val in meta[0].attr.items():
            print(f"  {key!r:<16}: {val!r}")





.. rst-class:: sphx-glr-script-out

 .. code-block:: none

    Dataset : 'Data',  shape=(360, 180)
    Attributes:
      'DIMENSION_LABELS': array(['dim1', 'dim2'], dtype=object)
      'DIMENSION_LIST': array([array([<HDF5 object reference>], dtype=object),
           array([<HDF5 object reference>], dtype=object)], dtype=object)
      'cr_number'     : np.int32(2190)
      'description'   : 'Coronal Hole Map'
      'resolution'    : np.float32(1.0)
      'source'        : 'synthetic'




.. GENERATED FROM PYTHON SOURCE LINES 50-54

.. note::
   Prefer explicit NumPy scalar types (*e.g.* ``np.float32``, ``np.int32``) over
   bare Python ``float`` or ``int`` when precision on disk matters. Python ``float``
   is stored as ``float64``; Python ``int`` is stored as ``int64``.

.. GENERATED FROM PYTHON SOURCE LINES 56-76

**HDF4 datatype restrictions – primary data and scales**

HDF4 supports only a restricted set of numeric types, mapped through the
``SDC`` type system. The supported types are:

+----------+------------------------------------------+
| Kind     | Supported itemsizes                      |
+==========+==========================================+
| integer  | ``int8``, ``int16``, ``int32``           |
+----------+------------------------------------------+
| unsigned | ``uint8``, ``uint16``, ``uint32``        |
+----------+------------------------------------------+
| float    | ``float32``, ``float64``                 |
+----------+------------------------------------------+
| string   | Unicode and byte strings                 |
+----------+------------------------------------------+

The types ``float16``, ``int64``, and ``uint64`` have no SDC equivalent.
Attempting to write a ``float16`` primary dataset to an HDF4 file raises a
:exc:`KeyError` immediately, before any scales or attributes are written:

.. GENERATED FROM PYTHON SOURCE LINES 76-84

.. code-block:: Python


    with tempfile.TemporaryDirectory() as tmpdir:
        out_hdf = Path(tmpdir) / "bad_data_dtype.hdf"
        try:
            write_hdf_data(out_hdf, chmap.astype(np.float16), t, p)
        except KeyError as e:
            print(f"KeyError raised for float16 data: {e}")





.. rst-class:: sphx-glr-script-out

 .. code-block:: none

    KeyError raised for float16 data: "Unsupported itemsize '2' for dtype kind 'f' in HDF4. Supported itemsizes are: {8, 4}"




.. GENERATED FROM PYTHON SOURCE LINES 85-87

The same restriction applies to scale arrays. Attempting to pass an ``int64``
scale to an HDF4 file also raises a :exc:`KeyError`:

.. GENERATED FROM PYTHON SOURCE LINES 87-95

.. code-block:: Python


    with tempfile.TemporaryDirectory() as tmpdir:
        out_hdf = Path(tmpdir) / "bad_scale_dtype.hdf"
        try:
            write_hdf_data(out_hdf, chmap, t.astype(np.float16), p)
        except KeyError as e:
            print(f"KeyError raised for float16 scale: {e}")





.. rst-class:: sphx-glr-script-out

 .. code-block:: none

    KeyError raised for float16 scale: "Unsupported itemsize '2' for dtype kind 'f' in HDF4. Supported itemsizes are: {8, 4}"




.. GENERATED FROM PYTHON SOURCE LINES 96-102

**HDF4 datatype restrictions – attributes**

The same SDC type constraints apply to attribute values. Passing an ``int64``
or ``float16`` attribute value to an HDF4 file raises a :exc:`KeyError`.
Unlike data and scale failures – which always propagate immediately – attribute
failures are gated by the ``strict`` parameter:

.. GENERATED FROM PYTHON SOURCE LINES 102-111

.. code-block:: Python


    with tempfile.TemporaryDirectory() as tmpdir:
        out_hdf = Path(tmpdir) / "bad_attr_strict.hdf"
        try:
            write_hdf_data(out_hdf, chmap, t, p,
                           cr_number=np.int64(2190))    # int64: no SDC equivalent
        except KeyError as e:
            print(f"KeyError raised for int64 attribute (strict=True): {e}")





.. rst-class:: sphx-glr-script-out

 .. code-block:: none

    KeyError raised for int64 attribute (strict=True): "Failed to set attribute 'cr_number' on dataset 'Data-Set-2'"




.. GENERATED FROM PYTHON SOURCE LINES 112-116

When ``strict=False`` is set, attribute write failures are downgraded to printed
warnings. Compatible attributes are still written; only the offending attribute
is skipped. This is useful when converting files from formats that use wider
integer or float types than HDF4 supports:

.. GENERATED FROM PYTHON SOURCE LINES 116-130

.. code-block:: Python


    with tempfile.TemporaryDirectory() as tmpdir:
        out_hdf = Path(tmpdir) / "partial_attrs.hdf"
        write_hdf_data(out_hdf, chmap, t, p,
                       description="Binary coronal hole map",  # str    : valid
                       cr_number=np.int64(2190),               # int64  : skipped with warning
                       resolution=np.float32(1.0),             # float32: valid
                       strict=False)

        meta = read_hdf_meta(out_hdf)
        print("Attributes written (incompatible attributes were skipped):")
        for key, val in meta[0].attr.items():
            print(f"  {key!r:<16}: {val!r}")





.. rst-class:: sphx-glr-script-out

 .. code-block:: none

    Warning: Failed to set attribute 'cr_number' on dataset 'Data-Set-2'; skipping.
    Attributes written (incompatible attributes were skipped):
      'description'   : 'Binary coronal hole map'
      'resolution'    : 1.0




.. GENERATED FROM PYTHON SOURCE LINES 131-136

.. note::
   ``strict`` also controls behavior for HDF5 attribute writes; a :exc:`TypeError`
   is raised (or warned) when a value cannot be stored as an HDF5 attribute – for
   example, if the value is an arbitrary Python object that :mod:`h5py` does not
   know how to serialize.


.. rst-class:: sphx-glr-timing

   **Total running time of the script:** (0 minutes 0.010 seconds)


.. _sphx_glr_download_gallery_02_writing_files_p02_writing_datasets_with_attributes.py:

.. only:: html

  .. container:: sphx-glr-footer sphx-glr-footer-example

    .. container:: sphx-glr-download sphx-glr-download-jupyter

      :download:`Download Jupyter notebook: p02_writing_datasets_with_attributes.ipynb <p02_writing_datasets_with_attributes.ipynb>`

    .. container:: sphx-glr-download sphx-glr-download-python

      :download:`Download Python source code: p02_writing_datasets_with_attributes.py <p02_writing_datasets_with_attributes.py>`

    .. container:: sphx-glr-download sphx-glr-download-zip

      :download:`Download zipped: p02_writing_datasets_with_attributes.zip <p02_writing_datasets_with_attributes.zip>`


.. only:: html

 .. rst-class:: sphx-glr-signature

    `Gallery generated by Sphinx-Gallery <https://sphinx-gallery.github.io>`_
