Repository: roboflow/supervision
File: supervision/annotators/core.py (Python)

Code before:
        Returns:
            The annotated image, matching the type of `scene` (`numpy.ndarray`
                or `PIL.Image.Image`)

        Example:
            ```python
            import supervision as sv

            image = ...
            detections = sv.Detections(...)

            labels = [
                f"{class_name} {confidence:.2f}"
                for class_name, confidence
                in zip(detections['class_name'], detections.confidence)
            ]

            label_annotator = sv.LabelAnnotator(text_position=sv.Position.CENTER)
            annotated_frame = label_annotator.annotate(
                scene=image.copy(),
                detections=detections,
                labels=labels
            )
            ```

        ![label-annotator-example](https://media.roboflow.com/
        supervision-annotator-examples/label-annotator-example-purple.png)
        """

        assert isinstance(scene, np.ndarray)
        self._validate_labels(labels, detections)

        labels = self._get_labels_text(detections, labels)
        text_properties = self._get_text_properties(labels)

        xyxy = self._calculate_label_positions(
            detections, text_properties, self.text_anchor
        )

        if self.spread_out:
            xyxy = spread_out_boxes(xyxy, step=2, max_iterations=len(xyxy) * 20)

        self._draw_labels(
            scene=scene,
            xyxy=xyxy,
            text_properties=text_properties,
            detections=detections,
            custom_color_lookup=custom_color_lookup,
        )

        return scene

Review comment (suggestion):
It seems to me that `_get_text_properties` and `_calculate_label_positions` should be merge into a single function that returns numpy array. You can than cut out `xyxy` portion of that numpy array and pass it to `spread_out_boxes`.

Code after:
            detections = sv.Detections(...)

            labels = [
                f"{class_name} {confidence:.2f}"
                for class_name, confidence
                in zip(detections['class_name'], detections.confidence)
            ]

            label_annotator = sv.LabelAnnotator(text_position=sv.Position.CENTER)
            annotated_frame = label_annotator.annotate(
                scene=image.copy(),
                detections=detections,
                labels=labels
            )
            ```

        ![label-annotator-example](https://media.roboflow.com/
        supervision-annotator-examples/label-annotator-example-purple.png)
        """

        assert isinstance(scene, np.ndarray)
        self._validate_labels(labels, detections)

        labels = self._get_labels_text(detections, labels)
        label_properties = self._get_label_properties(detections, labels)

        if self.smart_position:
            xyxy = label_properties[:, :4]
            xyxy = spread_out_boxes(xyxy)
            label_properties[:, :4] = xyxy

        self._draw_labels(
            scene=scene,
            labels=labels,
            label_properties=label_properties,
            detections=detections,
            custom_color_lookup=custom_color_lookup,
        )

        return scene

    def _validate_labels(self, labels: Optional[List[str]], detections: Detections):
        if labels is not None and len(labels) != len(detections):
            raise ValueError(
                f"The number of labels ({len(labels)}) does not match the "
                f"number of detections ({len(detections)}). Each detection "
                f"should have exactly 1 label."
            )

    def _get_label_properties(
        self,