Skip to content

labels

Module which currently only hosts prepare_label_group.

prepare_label_group(image_group, label_name, label_attrs, overwrite=False, logger=None)

Set the stage for writing labels to a zarr group

This helper function is similar to write_table, in that it prepares the appropriate zarr groups (labels and the new-label one) and performs overwrite-dependent checks. At a difference with write_table, this function does not actually write the label array to the new zarr group; such writing operation must take place in the actual task function, since in fractal-tasks-core it is done sequentially on different regions of the zarr array.

What this function does is:

  1. Create the labels group, if needed.
  2. If overwrite=False, check that the new label does not exist (either in zarr attributes or as a zarr sub-group).
  3. Update the labels attribute of the image group.
  4. If label_attrs is set, include this set of attributes in the new-label zarr group.
PARAMETER DESCRIPTION
image_group

The group to write to.

TYPE: Group

label_name

The name of the new label; this name also overrides the multiscale name in NGFF-image Zarr attributes, if needed.

TYPE: str

overwrite

If False, check that the new label does not exist (either in zarr attributes or as a zarr sub-group); if True propagate parameter to create_group method, making it overwrite any existing sub-group with the given name.

TYPE: bool DEFAULT: False

label_attrs

Zarr attributes of the label-image group.

TYPE: dict[str, Any]

logger

The logger to use (if unset, use logging.getLogger(None)).

TYPE: Optional[Logger] DEFAULT: None

RETURNS DESCRIPTION
group

Zarr group of the new label.

Source code in fractal_tasks_core/labels.py
 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
def prepare_label_group(
    image_group: zarr.hierarchy.Group,
    label_name: str,
    label_attrs: dict[str, Any],
    overwrite: bool = False,
    logger: Optional[logging.Logger] = None,
) -> zarr.group:
    """
    Set the stage for writing labels to a zarr group

    This helper function is similar to `write_table`, in that it prepares the
    appropriate zarr groups (`labels` and the new-label one) and performs
    `overwrite`-dependent checks. At a difference with `write_table`, this
    function does not actually write the label array to the new zarr group;
    such writing operation must take place in the actual task function, since
    in fractal-tasks-core it is done sequentially on different `region`s of the
    zarr array.

    What this function does is:

    1. Create the `labels` group, if needed.
    2. If `overwrite=False`, check that the new label does not exist (either in
       zarr attributes or as a zarr sub-group).
    3. Update the `labels` attribute of the image group.
    4. If `label_attrs` is set, include this set of attributes in the
       new-label zarr group.

    Args:
        image_group:
            The group to write to.
        label_name:
            The name of the new label; this name also overrides the multiscale
            name in NGFF-image Zarr attributes, if needed.
        overwrite:
            If `False`, check that the new label does not exist (either in zarr
            attributes or as a zarr sub-group); if `True` propagate parameter
            to `create_group` method, making it overwrite any existing
            sub-group with the given name.
        label_attrs:
            Zarr attributes of the label-image group.
        logger:
            The logger to use (if unset, use `logging.getLogger(None)`).

    Returns:
        Zarr group of the new label.
    """

    # Set logger
    if logger is None:
        logger = logging.getLogger(None)

    # Create labels group (if needed) and extract current_labels
    if "labels" not in set(image_group.group_keys()):
        labels_group = image_group.create_group("labels", overwrite=False)
    else:
        labels_group = image_group["labels"]
    current_labels = labels_group.attrs.asdict().get("labels", [])

    # If overwrite=False, check that the new label does not exist (either as a
    # zarr sub-group or as part of the zarr-group attributes)
    if not overwrite:
        if label_name in set(labels_group.group_keys()):
            error_msg = (
                f"Sub-group '{label_name}' of group {image_group.store.path} "
                f"already exists, but `{overwrite=}`.\n"
                "Hint: try setting `overwrite=True`."
            )
            logger.error(error_msg)
            raise OverwriteNotAllowedError(error_msg)
        if label_name in current_labels:
            error_msg = (
                f"Item '{label_name}' already exists in `labels` attribute of "
                f"group {image_group.store.path}, but `{overwrite=}`.\n"
                "Hint: try setting `overwrite=True`."
            )
            logger.error(error_msg)
            raise OverwriteNotAllowedError(error_msg)

    # Update the `labels` metadata of the image group, if needed
    if label_name not in current_labels:
        new_labels = current_labels + [label_name]
        labels_group.attrs["labels"] = new_labels

    # Define new-label group
    label_group = labels_group.create_group(label_name, overwrite=overwrite)

    # Validate attrs against NGFF specs 0.4
    try:
        meta = NgffImageMeta(**label_attrs)
    except ValidationError as e:
        error_msg = (
            "Label attributes do not comply with NGFF image "
            "specifications, as encoded in fractal-tasks-core.\n"
            f"Original error:\nValidationError: {str(e)}"
        )
        logger.error(error_msg)
        raise ValueError(error_msg)
    # Replace multiscale name with label_name, if needed
    current_multiscale_name = meta.multiscale.name
    if current_multiscale_name != label_name:
        logger.warning(
            f"Setting multiscale name to '{label_name}' (old value: "
            f"'{current_multiscale_name}') in label-image NGFF "
            "attributes."
        )
        label_attrs["multiscales"][0]["name"] = label_name
    # Overwrite label_group attributes with label_attrs key/value pairs
    label_group.attrs.put(label_attrs)

    return label_group