Skip to content

Keypoint cannot be switched (dropdown / next / prev) while a point is selected — labels silently go to the wrong bodypart #233

Description

@Kamisho-1802

Pre-submission checklist

  • I am using the latest released version of napari-deeplabcut. If not, I have provided minimal installation information, e.g. via the debug log.
  • I have searched existing issues to avoid duplicates

Bug summary

While a point is selected in the Points layer, switching the current keypoint has no effect — via the dropdown, the next/previous-keypoint shortcuts, or the automatic advance after placing a point. There is no error; the current keypoint just stays put, so the next point gets labeled as the previous bodypart. It looks like "the label won't stick" or "the label goes to the wrong bodypart."

Root cause: the three "current keypoint" setters in KeypointStore (current_keypoint, current_label, current_id) are guarded by if not len(layer.selected_data):, which skips the whole update whenever any point is selected.

Steps to reproduce

In the GUI:

  1. Open an image folder + config.yaml and start labeling.
  2. Place a keypoint (e.g. ear_left).
  3. Click that point to select it (this leaves selected_data non-empty).
  4. Try to switch to another bodypart via the dropdown or the next/previous-keypoint shortcut.
  5. The current keypoint does not change; any point placed now gets the old bodypart's label.

Minimal reproduction (no GUI, only napari + numpy) — isolates the setter logic from keypoints.py:282-288 (v0.3.1.2):

import numpy as np
from napari.layers import Points

layer = Points(
np.array([[0, 10, 10]], dtype=float),
properties={"label": np.array(["nose"], dtype=object),
"id": np.array([""], dtype=object)},
)

def set_current_label(label):
if not len(layer.selected_data): # the guard under test
cp = layer.current_properties
cp["label"] = np.asarray([label])
layer.current_properties = cp

def current_label():
return layer.current_properties["label"][0]

layer.selected_data = set()
set_current_label("ear_left")
print(current_label()) # -> 'ear_left' (OK)

layer.selected_data = {0}
set_current_label("tail")
print(current_label()) # -> 'nose' (BUG: switch ignored while a point is selected)

Expected behavior

Selecting a different bodypart (dropdown / next / previous keypoint) should switch the current keypoint even when a point is currently selected, so the next point I place is labeled with the bodypart I chose.

Actual behavior

When a point is selected, the switch is silently ignored: the current keypoint stays on the previous bodypart, and the next placed point is labeled with that old bodypart. No error or warning is shown.

Data type

Single-animal

How are you running napari?

From within the DeepLabCut GUI

Additional context

Suggested fix: clear the point selection first, then update current_properties — this keeps the guard's original intent while allowing the switch:

if len(layer.selected_data):
    layer.selected_data = set()
current_properties = layer.current_properties
current_properties["label"] = np.asarray([keypoint.label])
current_properties["id"] = np.asarray([keypoint.id])
layer.current_properties = current_properties

The same applies to current_label and current_id.

Why not just drop the guard: in napari, assigning current_properties while a point is selected also rewrites that selected point's properties, so removing the check would silently relabel the selected point. Clearing the selection first avoids that.

I verified on a real napari Points layer that (1) the switch now works while a point is selected, (2) the previously selected point's label is unchanged, (3) behavior is unchanged with nothing selected. The existing core/test_keypoints.py suite still passes (11/11), and test_widgets.py results are identical before and after.

Line numbers/verification are against current main (v0.3.1.2, commit 635a585).

Possibly related (same symptom, different root cause): #130 / DeepLabCut#2387 (closed by #137, a different error), DeepLabCut#2303 (a loading failure), #99 / #160 (Keypoint Selection Window not shown). #184 lists a distinct LOOP-mode frame-advance bug. Also: if the W/S keypoint-switch shortcuts in #225 go through the same setters, they'd inherit this guard.

Debug log (highly recommended)

I couldn't run the in-app "Generate napari-dlc log" from the original labeling session, but here are the package versions from the same conda environment where the bug occurs:

  • OS: Windows
  • Python: 3.10.20
  • napari-deeplabcut: 0.3.1.2
  • napari: 0.7.1
  • PySide6: 6.11.1
  • QtPy: 2.4.3
  • numpy: 1.26.4
  • pydantic: 2.13.4

The bug is pure-Python logic (the selected_data guard), and the minimal reproduction above only needs napari + numpy, so it's reproducible without the original session's log.

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions