Update & de-duplicate skeleton builder#3258
Merged
MMathisLab merged 5 commits intomainfrom Apr 12, 2026
Merged
Conversation
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().
7ddfe72 to
da51be4
Compare
Collaborator
Author
|
Fixed linting per #3263 |
deruyter92
approved these changes
Apr 7, 2026
MMathisLab
approved these changes
Apr 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
Resolves #3257 and improves maintainability by reducing duplication and increasing coverage.
Scope
This pull request refactors and modularizes the skeleton builder functionality for DeepLabCut, minimizing code reuse between the GUI and CLI, and enhancing maintainability. The main changes include moving core logic to a new
SkeletonBuilderbase class indeeplabcut/utils/skeleton.py, updating config read/write utilities for better encoding handling, and adapting the GUI skeleton builder to use the new base class, as well as unit tests for the updated class.Skeleton Builder Refactor and Code Reuse
clear()inconsistencies in updating the rendered skeletonDataFrame.groupby(..., axis=1)usage with the transpose-based pattern (df.T.groupby(...).T)SkeletonBuilderclass indeeplabcut/utils/skeleton.py, enabling both GUI and CLI to share the same code and logic. The GUI'sSkeletonBuildernow inherits from this base class, reducing code duplication and improving maintainability.deeplabcut/gui/widgets.py) was refactored to delegate skeleton-building logic to the new base class, and to implement only the UI-specific parts.Configuration Handling Improvements
deeplabcut/utils/skeleton.pyto use UTF-8 encoding and safe YAML loading/dumping, improving compatibility and preventing encoding issues.config.yamlin a consistent and sorted order, and normalized to lists for YAML compatibility.Code Cleanup and Maintenance
deeplabcut/gui/widgets.pyfor clarity and consistency.Testing
Pandas compatibility note
Removing the
axisargument fromDataFrame.groupbyis safe for our stack because: