Пример #1
0
def test_many_tracks_hdf5(tmpdir):
    labels = Labels()
    filename = os.path.join(tmpdir, "test.h5")

    labels.tracks = [Track(spawned_on=i, name=f"track {i}") for i in range(4000)]

    Labels.save_hdf5(filename=filename, labels=labels)
Пример #2
0
def run_tracker(frames, tracker):
    sig = inspect.signature(tracker.track)
    takes_img = "img" in sig.parameters

    # t0 = time.time()

    new_lfs = []

    # Run tracking on every frame
    for lf in frames:

        # Clear the tracks
        for inst in lf.instances:
            inst.track = None

        track_args = dict(untracked_instances=lf.instances)
        if takes_img:
            track_args["img"] = lf.video[lf.frame_idx]
        else:
            track_args["img"] = None

        new_lf = LabeledFrame(
            frame_idx=lf.frame_idx,
            video=lf.video,
            instances=tracker.track(**track_args),
        )
        new_lfs.append(new_lf)

        # if lf.frame_idx % 100 == 0: print(lf.frame_idx, time.time()-t0)

    # print(time.time() - t0)

    new_labels = Labels()
    new_labels.extend(new_lfs)
    return new_labels
Пример #3
0
def test_many_videos_hdf5(tmpdir):
    labels = Labels()
    filename = os.path.join(tmpdir, "test.h5")

    labels.videos = [Video.from_filename(f"video {i}.mp4") for i in range(3000)]

    Labels.save_hdf5(filename=filename, labels=labels)
Пример #4
0
    def loadProjectFile(self, filename: Optional[str] = None):
        """
        Loads given labels file into GUI.

        Args:
            filename: The path to the saved labels dataset. If None,
                then don't do anything.

        Returns:
            None:
        """
        if len(filename) == 0:
            return

        gui_video_callback = Labels.make_gui_video_callback(
            search_paths=[os.path.dirname(filename)])

        has_loaded = False
        labels = None
        if type(filename) == Labels:
            labels = filename
            filename = None
            has_loaded = True
        else:
            try:
                labels = Labels.load_file(filename,
                                          video_search=gui_video_callback)
                has_loaded = True
            except ValueError as e:
                print(e)
                QMessageBox(text=f"Unable to load {filename}.").exec_()

        if has_loaded:
            self.loadLabelsObject(labels, filename)
Пример #5
0
def test_save_labels_with_frame_data(multi_skel_vid_labels, tmpdir, format):
    """
    Test saving and loading a labels dataset with frame data included
    as JSON.
    """

    # Lets take a subset of the labels so this doesn't take too long
    multi_skel_vid_labels.labeled_frames = multi_skel_vid_labels.labeled_frames[
        5:30]

    filename = os.path.join(tmpdir, "test.json")
    Labels.save_json(
        multi_skel_vid_labels,
        filename=filename,
        save_frame_data=True,
        frame_data_format=format,
    )

    # Load the data back in
    loaded_labels = Labels.load_json(f"{filename}.zip")

    # Check that we have the same thing
    _check_labels_match(multi_skel_vid_labels, loaded_labels, format=format)

    # Make sure we can load twice
    loaded_labels = Labels.load_json(f"{filename}.zip")
Пример #6
0
def test_labels_json(tmpdir, multi_skel_vid_labels):
    json_file_path = os.path.join(tmpdir, "dataset.json")

    if os.path.isfile(json_file_path):
        os.remove(json_file_path)

    # Save to json
    Labels.save_json(labels=multi_skel_vid_labels, filename=json_file_path)

    # Make sure the filename is there
    assert os.path.isfile(json_file_path)

    # Lets load the labels back in and make sure we haven't lost anything.
    loaded_labels = Labels.load_json(json_file_path)

    # Check that we have the same thing
    _check_labels_match(multi_skel_vid_labels, loaded_labels)

    # Check that we don't have the very same objects
    assert not multi_skel_vid_labels.skeletons[0] is loaded_labels.skeletons[0]
    assert not multi_skel_vid_labels.nodes[3] in loaded_labels.nodes
    assert not multi_skel_vid_labels.videos[0] is loaded_labels.videos[0]

    # Reload json using objects from original labels
    # We'll also test load_file() here
    loaded_labels = Labels.load_file(json_file_path,
                                     match_to=multi_skel_vid_labels)

    # Check that we now do have the same objects
    assert multi_skel_vid_labels.skeletons[0] in loaded_labels.skeletons
    assert multi_skel_vid_labels.nodes[3] in loaded_labels.nodes
    assert multi_skel_vid_labels.videos[0] in loaded_labels.videos
Пример #7
0
def test_hdf5_empty_save(tmpdir):
    labels = Labels()
    filename = os.path.join(tmpdir, "test.h5")
    Labels.save_hdf5(filename=filename, labels=labels)

    dummy_video = Video.from_filename("foo.mp4")
    labels.videos.append(dummy_video)
    Labels.save_hdf5(filename=filename, labels=labels)
Пример #8
0
def test_labels_hdf5(multi_skel_vid_labels, tmpdir):
    labels = multi_skel_vid_labels
    filename = os.path.join(tmpdir, "test.h5")

    Labels.save_hdf5(filename=filename, labels=labels)

    loaded_labels = Labels.load_hdf5(filename=filename)

    _check_labels_match(labels, loaded_labels)
Пример #9
0
def test_load_labels_json_old(tmpdir):
    new_file_path = os.path.join(tmpdir, "centered_pair_v2.json")

    # Function to run some checks on loaded labels
    def check_labels(labels):
        skel_node_names = [
            "head",
            "neck",
            "thorax",
            "abdomen",
            "wingL",
            "wingR",
            "forelegL1",
            "forelegL2",
            "forelegL3",
            "forelegR1",
            "forelegR2",
            "forelegR3",
            "midlegL1",
            "midlegL2",
            "midlegL3",
            "midlegR1",
            "midlegR2",
            "midlegR3",
            "hindlegL1",
            "hindlegL2",
            "hindlegL3",
            "hindlegR1",
            "hindlegR2",
            "hindlegR3",
        ]

        # Do some basic checks
        assert len(labels) == 70

        # Make sure we only create one video object and it works
        assert len({label.video for label in labels}) == 1
        assert labels[0].video.get_frame(0).shape == (384, 384, 1)

        # Check some frame objects.
        assert labels[0].frame_idx == 0
        assert labels[40].frame_idx == 573

        # Check the skeleton
        assert labels[0].instances[0].skeleton.node_names == skel_node_names

    labels = Labels.load_json("tests/data/json_format_v1/centered_pair.json")
    check_labels(labels)

    # Save out to new JSON format
    Labels.save_json(labels, new_file_path)

    # Reload and check again.
    new_labels = Labels.load_json(new_file_path)
    check_labels(new_labels)
Пример #10
0
def test_local_path_save(tmpdir, monkeypatch):

    filename = "test.h5"

    # Set current working directory (monkeypatch isolates other tests)
    monkeypatch.chdir(tmpdir)

    # Try saving with relative path
    Labels.save_file(filename=filename, labels=Labels())

    assert os.path.exists(os.path.join(tmpdir, filename))
Пример #11
0
def test_duplicate_skeletons_serializing():
    vid = Video.from_filename("foo.mp4")

    skeleton_a = Skeleton.load_json("tests/data/skeleton/fly_skeleton_legs.json")
    skeleton_b = Skeleton.load_json("tests/data/skeleton/fly_skeleton_legs.json")

    lf_a = LabeledFrame(vid, frame_idx=2, instances=[Instance(skeleton_a)])
    lf_b = LabeledFrame(vid, frame_idx=3, instances=[Instance(skeleton_b)])

    new_labels = Labels(labeled_frames=[lf_a, lf_b])
    new_labels_json = new_labels.to_dict()
Пример #12
0
def test_instance_access():
    labels = Labels()

    dummy_skeleton = Skeleton()
    dummy_video = Video(backend=MediaVideo)
    dummy_video2 = Video(backend=MediaVideo)

    for i in range(10):
        labels.append(
            LabeledFrame(
                dummy_video,
                frame_idx=i,
                instances=[Instance(dummy_skeleton),
                           Instance(dummy_skeleton)],
            ))
    for i in range(10):
        labels.append(
            LabeledFrame(
                dummy_video2,
                frame_idx=i,
                instances=[
                    Instance(dummy_skeleton),
                    Instance(dummy_skeleton),
                    Instance(dummy_skeleton),
                ],
            ))

    assert len(labels.all_instances) == 50
    assert len(list(labels.instances(video=dummy_video))) == 20
    assert len(list(labels.instances(video=dummy_video2))) == 30
Пример #13
0
def test_distinct_skeletons_serializing():
    vid = Video.from_filename("foo.mp4")

    skeleton_a = Skeleton.load_json("tests/data/skeleton/fly_skeleton_legs.json")
    skeleton_b = Skeleton.load_json("tests/data/skeleton/fly_skeleton_legs.json")
    skeleton_b.add_node("foo")

    lf_a = LabeledFrame(vid, frame_idx=2, instances=[Instance(skeleton_a)])
    lf_b = LabeledFrame(vid, frame_idx=3, instances=[Instance(skeleton_b)])

    new_labels = Labels(labeled_frames=[lf_a, lf_b])

    # Make sure we can serialize this
    new_labels_json = new_labels.to_dict()
Пример #14
0
def test_has_missing_videos():
    labels = Labels()
    labels.add_video(Video.from_filename("small_robot.mp4"))
    assert labels.has_missing_videos

    labels = Labels()
    labels.add_video(Video.from_filename("tests/data/videos/small_robot.mp4"))
    assert not labels.has_missing_videos
Пример #15
0
def main():
    import argparse

    parser = argparse.ArgumentParser()
    parser.add_argument("data_path", help="Path to labels json file")
    args = parser.parse_args()

    video_callback = Labels.make_video_callback(
        [os.path.dirname(args.data_path)])
    labels = Labels.load_file(args.data_path, video_search=video_callback)

    print(f"Labeled frames: {len(labels)}")
    print(f"Tracks: {len(labels.tracks)}")

    print(f"Video files:")

    total_user_frames = 0

    for vid in labels.videos:
        lfs = labels.find(vid)

        first_idx = min((lf.frame_idx for lf in lfs))
        last_idx = max((lf.frame_idx for lf in lfs))

        tracks = {inst.track for lf in lfs for inst in lf}
        concurrent_count = max((len(lf.instances) for lf in lfs))
        user_frames = labels.get_labeled_frame_count(vid, "user")

        total_user_frames += user_frames

        print(f"  {vid.filename}")
        print(f"    labeled frames from {first_idx} to {last_idx}")
        print(f"    labeled frames: {len(lfs)}")
        print(f"    user labeled frames: {user_frames}")
        print(f"    tracks: {len(tracks)}")
        print(f"    max instances in frame: {concurrent_count}")

    print(f"Total user labeled frames: {total_user_frames}")

    if labels.provenance:
        print()
        print(f"Provenance:")

        for key, value in labels.provenance.items():
            print(f"  {key}: {value}")
Пример #16
0
def test_labels_append_hdf5(multi_skel_vid_labels, tmpdir):
    labels = multi_skel_vid_labels
    filename = os.path.join(tmpdir, "test.h5")

    # Save each frame of the Labels dataset one by one in append
    # mode
    for label in labels:

        # Just do the first 20 to speed things up
        if label.frame_idx > 20:
            break

        Labels.save_hdf5(filename=filename, labels=Labels([label]), append=True)

    # Now load the dataset and make sure we get the same thing we started
    # with.
    loaded_labels = Labels.load_hdf5(filename=filename)

    _check_labels_match(labels, loaded_labels)
Пример #17
0
def test_hdf5_from_predicted(multi_skel_vid_labels, tmpdir):
    labels = multi_skel_vid_labels
    filename = os.path.join(tmpdir, "test.h5")

    # Add some predicted instances to create from_predicted links
    for frame_num, frame in enumerate(labels):
        if frame_num % 20 == 0:
            frame.instances[
                0].from_predicted = PredictedInstance.from_instance(
                    frame.instances[0], float(frame_num))
            frame.instances.append(frame.instances[0].from_predicted)

    # Save and load, compare the results
    Labels.save_hdf5(filename=filename, labels=labels)
    loaded_labels = Labels.load_hdf5(filename=filename)

    for frame_num, frame in enumerate(loaded_labels):
        if frame_num % 20 == 0:
            assert frame.instances[0].from_predicted.score == float(frame_num)
Пример #18
0
def test_save_labels_and_frames_hdf5(multi_skel_vid_labels, tmpdir):
    # Lets take a subset of the labels so this doesn't take too long
    labels = multi_skel_vid_labels
    labels.labeled_frames = labels.labeled_frames[5:30]

    filename = os.path.join(tmpdir, "test.h5")

    Labels.save_hdf5(filename=filename, labels=labels, save_frame_data=True)

    loaded_labels = Labels.load_hdf5(filename=filename)

    _check_labels_match(labels, loaded_labels)

    # Rename file (after closing videos)
    for vid in loaded_labels.videos:
        vid.close()
    filerename = os.path.join(tmpdir, "test_rename.h5")
    os.rename(filename, filerename)

    # Make sure we open can after rename
    loaded_labels = Labels.load_hdf5(filename=filerename)
Пример #19
0
def test_labels_merge():
    dummy_video = Video(backend=MediaVideo)
    dummy_skeleton = Skeleton()
    dummy_skeleton.add_node("node")

    labels = Labels()
    dummy_frames = []

    # Add 10 instances with different points (so they aren't "redundant")
    for i in range(10):
        instance = Instance(skeleton=dummy_skeleton, points=dict(node=Point(i, i)))
        dummy_frame = LabeledFrame(dummy_video, frame_idx=0, instances=[instance])
        dummy_frames.append(dummy_frame)

    labels.labeled_frames.extend(dummy_frames)
    assert len(labels) == 10
    assert len(labels.labeled_frames[0].instances) == 1

    labels.merge_matching_frames()
    assert len(labels) == 1
    assert len(labels.labeled_frames[0].instances) == 10
Пример #20
0
def test_multivideo_tracks():
    vid_a = Video.from_filename("foo.mp4")
    vid_b = Video.from_filename("bar.mp4")

    skeleton = Skeleton.load_json("tests/data/skeleton/fly_skeleton_legs.json")

    track_a = Track(spawned_on=2, name="A")
    track_b = Track(spawned_on=3, name="B")

    inst_a = Instance(track=track_a, skeleton=skeleton)
    inst_b = Instance(track=track_b, skeleton=skeleton)

    lf_a = LabeledFrame(vid_a, frame_idx=2, instances=[inst_a])
    lf_b = LabeledFrame(vid_b, frame_idx=3, instances=[inst_b])

    labels = Labels(labeled_frames=[lf_a, lf_b])

    # Try setting video B instance to track used in video A
    labels.track_swap(vid_b, new_track=track_a, old_track=track_b, frame_range=(3, 4))

    assert inst_b.track == track_a
Пример #21
0
def test_merge_predictions():
    dummy_video_a = Video.from_filename("foo.mp4")
    dummy_video_b = Video.from_filename("foo.mp4")

    dummy_skeleton_a = Skeleton()
    dummy_skeleton_a.add_node("node")

    dummy_skeleton_b = Skeleton()
    dummy_skeleton_b.add_node("node")

    dummy_instances_a = []
    dummy_instances_a.append(
        Instance(skeleton=dummy_skeleton_a, points=dict(node=Point(1, 1)))
    )
    dummy_instances_a.append(
        Instance(skeleton=dummy_skeleton_a, points=dict(node=Point(2, 2)))
    )

    labels_a = Labels()
    labels_a.append(
        LabeledFrame(dummy_video_a, frame_idx=0, instances=dummy_instances_a)
    )

    dummy_instances_b = []
    dummy_instances_b.append(
        Instance(skeleton=dummy_skeleton_b, points=dict(node=Point(1, 1)))
    )
    dummy_instances_b.append(
        PredictedInstance(
            skeleton=dummy_skeleton_b, points=dict(node=Point(3, 3)), score=1
        )
    )

    labels_b = Labels()
    labels_b.append(
        LabeledFrame(dummy_video_b, frame_idx=0, instances=dummy_instances_b)
    )

    # Frames have one redundant instance (perfect match) and all the
    # non-matching instances are different types (one predicted, one not).
    merged, extra_a, extra_b = Labels.complex_merge_between(labels_a, labels_b)
    assert len(merged[dummy_video_a]) == 1
    assert len(merged[dummy_video_a][0]) == 1  # the predicted instance was merged
    assert not extra_a
    assert not extra_b
Пример #22
0
    def finishMerge(self):
        """
        Finishes merge process, possibly resolving conflicts.

        This is connected to `accepted` signal.

        Args:
            None.

        Raises:
            ValueError: If no valid merge method was selected in dialog.

        Returns:
            None.
        """
        merge_method = self.merge_method.currentText()
        if merge_method == USE_BASE_STRING:
            Labels.finish_complex_merge(self.base_labels, self.extra_base)
        elif merge_method == USE_NEW_STRING:
            Labels.finish_complex_merge(self.base_labels, self.extra_new)
        elif merge_method in (USE_NEITHER_STRING, CLEAN_STRING):
            Labels.finish_complex_merge(self.base_labels, [])
        else:
            raise ValueError("No valid merge method selected.")

        self.accept()
Пример #23
0
def test_labels_predicted_hdf5(multi_skel_vid_labels, tmpdir):
    labels = multi_skel_vid_labels
    filename = os.path.join(tmpdir, "test.h5")

    # Lets promote some of these Instances to predicted instances
    for label in labels:
        for i, instance in enumerate(label.instances):
            if i % 2 == 0:
                label.instances[i] = PredictedInstance.from_instance(
                    instance, 0.3)

    # Lets also add some from_predicted values
    for label in labels:
        label.instances[1].from_predicted = label.instances[0]

    # Try adding a node to the skeleton
    labels.skeletons[0].add_node("new node")

    # Save and compare the results
    Labels.save_hdf5(filename=filename, labels=labels)
    loaded_labels = Labels.load_hdf5(filename=filename)
    _check_labels_match(labels, loaded_labels)

    # Try deleting nodes from the skeleton
    node = labels.skeletons[0].nodes[-1]
    labels.skeletons[0].delete_node(node)
    node = labels.skeletons[0].nodes[-1]
    labels.skeletons[0].delete_node(node)

    # Save and compare the results
    Labels.save_hdf5(filename=filename, labels=labels)
    loaded_labels = Labels.load_hdf5(filename=filename)
    _check_labels_match(labels, loaded_labels)
Пример #24
0
    def __init__(self, labels_path: Optional[str] = None, *args, **kwargs):
        """Initialize the app.

        Args:
            labels_path: Path to saved :class:`Labels` dataset.

        Returns:
            None.
        """
        super(MainWindow, self).__init__(*args, **kwargs)

        self.state = GuiState()
        self.labels = Labels()

        self.commands = CommandContext(state=self.state,
                                       app=self,
                                       update_callback=self.on_data_update)

        self._menu_actions = dict()
        self._buttons = dict()
        self._child_windows = dict()

        self.overlays = dict()

        self.state.connect("filename", self.setWindowTitle)

        self.state["skeleton"] = Skeleton()
        self.state["labeled_frame"] = None
        self.state["filename"] = None
        self.state["show labels"] = True
        self.state["show edges"] = True
        self.state["edge style"] = "Line"
        self.state["fit"] = False
        self.state["color predicted"] = prefs["color predicted"]

        self._initialize_gui()

        if labels_path:
            self.loadProjectFile(labels_path)
Пример #25
0
def test_provenance(tmpdir):
    labels = Labels(provenance=dict(source="test_provenance"))
    filename = os.path.join(tmpdir, "test.slp")

    # Add a video without a full path
    labels.add_video(Video.from_filename("small_robot.mp4"))

    Labels.save_file(filename=filename, labels=labels)

    labels = Labels.load_file(filename)
    print(labels.provenance)
    assert labels.provenance["source"] == "test_provenance"
Пример #26
0
def test_many_suggestions_hdf5(tmpdir):
    labels = Labels()
    filename = os.path.join(tmpdir, "test.h5")
    video = Video.from_filename("foo.mp4")
    labels.videos = [video]

    labels.suggestions = [SuggestionFrame(video, i) for i in range(3000)]

    Labels.save_hdf5(filename=filename, labels=labels)
Пример #27
0
def multi_skel_vid_labels(hdf5_vid, small_robot_mp4_vid, skeleton, stickman):
    """
    Build a big list of LabeledFrame objects and wrap it in Labels class.

    Args:
        hdf5_vid: An HDF5 video fixture
        small_robot_mp4_vid: An MP4 video fixture
        skeleton: A fly skeleton.
        stickman: A stickman skeleton

    Returns:
        The Labels object containing all the labeled frames
    """
    labels = []
    stick_tracks = [
        Track(spawned_on=0, name=f"Stickman {i}") for i in range(6)
    ]
    fly_tracks = [Track(spawned_on=0, name=f"Fly {i}") for i in range(6)]

    # Make some tracks None to test that
    fly_tracks[3] = None
    stick_tracks[2] = None

    for f in range(500):
        vid = [hdf5_vid, small_robot_mp4_vid][f % 2]
        label = LabeledFrame(video=vid, frame_idx=f % vid.frames)

        fly_instances = []
        for i in range(6):
            fly_instances.append(
                Instance(skeleton=skeleton, track=fly_tracks[i]))
            for node in skeleton.nodes:
                fly_instances[i][node] = Point(x=i % vid.width,
                                               y=i % vid.height)

        stickman_instances = []
        for i in range(6):
            stickman_instances.append(
                Instance(skeleton=stickman, track=stick_tracks[i]))
            for node in stickman.nodes:
                stickman_instances[i][node] = Point(x=i % vid.width,
                                                    y=i % vid.height)

        label.instances = stickman_instances + fly_instances
        labels.append(label)

    labels = Labels(labels)

    return labels
Пример #28
0
def simple_predictions():

    video = Video.from_filename("video.mp4")

    skeleton = Skeleton()
    skeleton.add_node("a")
    skeleton.add_node("b")

    track_a = Track(0, "a")
    track_b = Track(0, "b")

    labels = Labels()

    instances = []
    instances.append(
        PredictedInstance(
            skeleton=skeleton,
            score=2,
            track=track_a,
            points=dict(a=PredictedPoint(1, 1, score=0.5),
                        b=PredictedPoint(1, 1, score=0.5)),
        ))
    instances.append(
        PredictedInstance(
            skeleton=skeleton,
            score=5,
            track=track_b,
            points=dict(a=PredictedPoint(1, 1, score=0.7),
                        b=PredictedPoint(1, 1, score=0.7)),
        ))

    labeled_frame = LabeledFrame(video, frame_idx=0, instances=instances)
    labels.append(labeled_frame)

    instances = []
    instances.append(
        PredictedInstance(
            skeleton=skeleton,
            score=3,
            track=track_a,
            points=dict(a=PredictedPoint(4, 5, score=1.5),
                        b=PredictedPoint(1, 1, score=1.0)),
        ))
    instances.append(
        PredictedInstance(
            skeleton=skeleton,
            score=6,
            track=track_b,
            points=dict(a=PredictedPoint(6, 13, score=1.7),
                        b=PredictedPoint(1, 1, score=1.0)),
        ))

    labeled_frame = LabeledFrame(video, frame_idx=1, instances=instances)
    labels.append(labeled_frame)

    return labels
Пример #29
0
def removal_test_labels():
    skeleton = Skeleton()
    video = Video(backend=MediaVideo)
    lf_user_only = LabeledFrame(
        video=video, frame_idx=0, instances=[Instance(skeleton=skeleton)]
    )
    lf_pred_only = LabeledFrame(
        video=video, frame_idx=1, instances=[PredictedInstance(skeleton=skeleton)]
    )
    lf_both = LabeledFrame(
        video=video,
        frame_idx=2,
        instances=[Instance(skeleton=skeleton), PredictedInstance(skeleton=skeleton)],
    )
    labels = Labels([lf_user_only, lf_pred_only, lf_both])
    return labels
Пример #30
0
def test_deserialize_suggestions(small_robot_mp4_vid, tmpdir):
    dummy_video = small_robot_mp4_vid
    dummy_skeleton = Skeleton()
    dummy_instance = Instance(dummy_skeleton)
    dummy_frame = LabeledFrame(dummy_video, frame_idx=0, instances=[dummy_instance])

    labels = Labels()
    labels.append(dummy_frame)

    suggestions = VideoFrameSuggestions.suggest(
        labels=labels, params=dict(method="sample", per_video=13)
    )
    labels.set_suggestions(suggestions)

    filename = os.path.join(tmpdir, "new_suggestions.h5")
    Labels.save_file(filename=filename, labels=labels)

    new_suggestion_labels = Labels.load_file(filename)
    assert len(suggestions) == len(new_suggestion_labels.suggestions)
    assert [frame.frame_idx for frame in suggestions] == [
        frame.frame_idx for frame in new_suggestion_labels.suggestions
    ]