Skip to content

Commit

Permalink
Fix Datumaro visualizer's import errors after introducing lazy import (
Browse files Browse the repository at this point in the history
…#1220)

- Ticket no. 127143

### How to test
This Python code raises `ImportError` before this patch.

<details>
<summary>code</summary>

```python
import numpy as np
import datumaro as dm

### Create example dataset ###


def create_example_dataset() -> dm.Dataset:
    blank_img = dm.Image.from_numpy(np.zeros([10, 10, 3], dtype=np.uint8))
    categories = ["label_1", "label_2", "label_3"]

    points_of_1x1_box = np.array([0, 0, 0, 1, 1, 1, 1, 0])

    item_not_to_drop = dm.DatasetItem(
        id="item_not_to_drop",
        media=blank_img,
        annotations=[
            dm.Polygon(
                points=label + points_of_1x1_box,
                label=label,
            )
            for label in range(len(categories))
        ],
    )

    item_drop_by_big_polygon = dm.DatasetItem(
        id="item_drop_by_big_polygon",
        media=blank_img,
        annotations=[
            dm.Polygon(
                points=8 * points_of_1x1_box,  # 8x8 box
                label=0,
            )
        ],
    )

    item_drop_by_polygon_union = dm.DatasetItem(
        id="item_drop_by_polygon_union",
        media=blank_img,
        annotations=[
            dm.Polygon(
                points=offset + 4 * points_of_1x1_box,  # 10 5x5 boxes placed in diagnoal
                label=1,
            )
            for offset in range(10)
        ],
    )

    return dm.Dataset.from_iterable(
        iterable=[
            item_not_to_drop,
            item_drop_by_big_polygon,
            item_drop_by_polygon_union,
        ],
        categories=categories,
    )


dataset = create_example_dataset()
vis = dm.Visualizer(dataset)
fig = vis.vis_gallery([item for item in dataset])
fig.show()
```

</details>


![image](https://github.com/openvinotoolkit/datumaro/assets/26541465/8e04c9d2-d195-47ea-9e6c-79f5617a745c)

After this patch, there is no more these errors.

Signed-off-by: Kim, Vinnam <vinnam.kim@intel.com>
  • Loading branch information
vinnamkim authored Dec 13, 2023
1 parent 9b254ce commit 4faaae5
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 10 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
(<https://github.com/openvinotoolkit/datumaro/pull/1210>)
- Fix label compare of distance method
(<https://github.com/openvinotoolkit/datumaro/pull/1205>)
- Fix Datumaro visualizer's import errors after introducing lazy import
(<https://github.com/openvinotoolkit/datumaro/pull/1220>)
- Fix broken link to supported formats in readme
(<https://github.com/openvinotoolkit/datumaro/pull/1221>)

Expand Down
5 changes: 2 additions & 3 deletions src/datumaro/cli/util/compare.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,11 @@
from datumaro.util.import_util import lazy_import

if TYPE_CHECKING:
import matplotlib.pyplot as plt

with warnings.catch_warnings():
warnings.simplefilter("ignore")
import tensorboardX as tb
else:
tb = lazy_import("tensorboardX")
plt = lazy_import("matplotlib.pyplot")


class DistanceCompareVisualizer:
Expand Down Expand Up @@ -292,6 +289,8 @@ def save_as_tensorboard(self, img, name):
self._file_writer.add_image(name, img)

def save_conf_matrix(self, conf_matrix, filename):
import matplotlib.pyplot as plt

def _get_class_map(label_categories):
classes = None
if label_categories is not None:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Copyright (C) 2023 Intel Corporation
#
# SPDX-License-Identifier: MIT
from __future__ import annotations

from collections import defaultdict
from dataclasses import dataclass, field
Expand All @@ -13,8 +14,6 @@
if TYPE_CHECKING:
from matplotlib.figure import Figure
from pandas import DataFrame, Series
else:
DataFrame, Series, Figure = None, None, None


__all__ = ["LossDynamicsAnalyzer", "NoisyLabelCandidate"]
Expand Down
6 changes: 2 additions & 4 deletions src/datumaro/components/visualizer.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Copyright (C) 2023 Intel Corporation
#
# SPDX-License-Identifier: MIT
from __future__ import annotations

import logging as log
import math
import random
Expand Down Expand Up @@ -35,10 +37,6 @@
from matplotlib.axes import Axes
from matplotlib.figure import Figure
from matplotlib.text import Text
else:
Figure = None
Axes = None
Text = None

CAPTION_BBOX_PAD = 0.2
DEFAULT_COLOR_CYCLES: List[str] = [
Expand Down
45 changes: 44 additions & 1 deletion tests/unit/test_compare.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
# Copyright (C) 2020-2023 Intel Corporation
#
# SPDX-License-Identifier: MIT
import os
import platform
import unittest
from unittest import TestCase, skipIf
from unittest.mock import call, mock_open, patch
from unittest.mock import MagicMock, call, mock_open, patch

import numpy as np
import pytest

from datumaro.cli.util.compare import DistanceCompareVisualizer
from datumaro.components.annotation import Bbox, Caption, Label, Mask, Points
from datumaro.components.comparator import DistanceComparator, EqualityComparator, TableComparator
from datumaro.components.dataset_base import DEFAULT_SUBSET_NAME, DatasetItem
Expand Down Expand Up @@ -462,3 +468,40 @@ def test_save_compare_report(
call(f"Low-level Comparison:\n{mock_low_level_table}\n\n"),
]
)


class DistanceCompareVisualizerTest:
@pytest.fixture
def fxt_dataset_pair(self):
"""Two datasets pair which has the same (id, subset) dataset item to be compared."""
class_count = 3
dataset_1 = Dataset.from_iterable(
[DatasetItem(id=1, annotations=[Label(label=idx) for idx in range(class_count)])],
categories=[f"label_{idx}" for idx in range(class_count)],
)
dataset_2 = Dataset.from_iterable(
[DatasetItem(id=1, annotations=[Label(label=idx) for idx in range(class_count)])],
categories=[f"label_{idx}" for idx in range(class_count)],
)
return dataset_1, dataset_2

@pytest.mark.parametrize("output_format", ["simple", "tensorboard"])
def test_save(self, fxt_dataset_pair, test_dir, output_format):
mock_dist_comparator = MagicMock(spec=DistanceComparator)

# matches, a_unmatched, b_unmatched = label_diff
mock_dist_comparator.match_labels.return_value = ([0], [1], [2])
mock_dist_comparator.match_boxes.return_value = ([], [], [], [])
mock_dist_comparator.match_polygons.return_value = ([], [], [], [])
mock_dist_comparator.match_masks.return_value = ([], [], [], [])

with DistanceCompareVisualizer(
save_dir=test_dir,
comparator=mock_dist_comparator,
output_format=output_format,
) as visualizer:
first_dataset, second_dataset = fxt_dataset_pair
visualizer.save(first_dataset, second_dataset)

# Assert non-empty after save()
assert os.listdir(test_dir)

0 comments on commit 4faaae5

Please sign in to comment.