◐ Shell
clean mode source ↗

Update & de-duplicate skeleton builder by C-Achard · Pull Request #3258 · DeepLabCut/DeepLabCut

@C-Achard self-assigned this

Mar 26, 2026
Switch YAML usage to YAML(typ="rt") with explicit UTF-8 encoding for read/write to avoid encoding issues and make config I/O consistent. Replace scipy.spatial.cKDTree alias with KDTree import and adjust on_pick to correctly identify and discard the clicked segment and its sorted index pair, update the LineCollection and trigger a canvas redraw. Ensure skeleton pairs are written in a consistent order by sorting indices before saving. Minor cleanup: comment out unused path/verts assignments in on_select and add a TODO note about duplicate config functions.
Extract and decouple skeleton-building logic into deeplabcut.utils.skeleton.SkeletonBuilder and adapt the GUI to reuse it. The widgets.SkeletonBuilder now subclasses the new BaseSkeletonBuilder and Qt dialog, delegating setup to BaseSkeletonBuilder.__init__ and providing GUI-specific build_ui/display implementations. The core builder no longer calls plt.show() directly; it exposes build_ui() and display() so different frontends (matplotlib or Qt) can control presentation. Also fixed/clarified pick_labeled_frame grouping logic for 'individuals' columns and replaced immediate show() calls with canvas.draw_idle() in the Qt UI. Minor cleanup and UI wiring changes to support the refactor.
Introduce tests/utils/test_skeleton.py containing unit tests for the skeleton builder utilities. Covers pick_labeled_frame (multi-animal drop and no-individual fallback), clear (resetting indices, segments, and LineCollection), export (sorting pairs, writing config, and warning on unconnected bodyparts), on_select (adding pairs/segments, ignoring duplicate hits), on_pick (removing segments on right-click only), and lightweight SkeletonBuilder.__init__ integration (loading dataframe/image and error when no labeled data). Tests use KDTree, LineCollection, pandas/numpy, and monkeypatching to isolate I/O and rendering.
Add read_config/write_config hooks to GUI and core SkeletonBuilder to centralize config IO and ensure skeleton pairs are normalized to plain lists before writing. Update export to call the instance write_config, and make clear() reset the LineCollection to an empty list and trigger a canvas redraw to avoid stale drawing state. Add a simple dev test script (dev/test_skeleton.py) and adjust the unit test to attach a fake canvas before calling clear().

deruyter92

MMathisLab