Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(3a -> 3) Debug missing PredictedInstances (not displaying in GUI) #1757

Conversation

roomrys
Copy link
Collaborator

@roomrys roomrys commented Apr 25, 2024

Description

TriangulateSession calls frame_group.upsert_points which should create PredictedInstances for any Camcorders that do not already have an assigned Instance (or PredictedIntance). However, after triangulating, the PredictedInstances were not being displayed in the GUI - even though the containing InstanceGroup appeared to have been filled in with PredictedInstances for each "missing" view.

This PR does 3 things:

  1. adds the filler PredictedInstances to the LabeledFrame
  2. replaces PredictedInstances with Instances (when creating an Instance from a PredictedInstance)
  3. replaces Instance with PredictedInstance (when removing an Instance that ha an associated PredictedInstance)

Types of changes

  • Bugfix
  • New feature
  • Refactor / Code style update (no logical changes)
  • Build / CI changes
  • Documentation Update
  • Other (explain)

Does this address any currently open issues?

[list open issues here]

Outside contributors checklist

  • Review the guidelines for contributing to this repository
  • Read and sign the CLA and add yourself to the authors list
  • Make sure you are making a pull request against the develop branch (not main). Also you should start your branch off develop
  • Add tests that prove your fix is effective or that your feature works
  • Add necessary documentation (if appropriate)

Thank you for contributing to SLEAP!

❤️

Summary by CodeRabbit

  • New Features
    • Enhanced functionality for adding and removing instances in frame groups, ensuring better data management and user interaction within the application.

Copy link

coderabbitai bot commented Apr 25, 2024

Walkthrough

This update enhances the handling of instances within frame groups in the SLEAP project. It introduces refined logic for adding and removing instances, ensuring proper management and linking of these instances in various structures, thus improving the software's robustness and functionality in tracking scenarios.

Changes

Files Change Summary
sleap/gui/commands.py
sleap/io/dataset.py
Added and refined logic for handling instances in FrameGroup, including addition, replacement, and removal of instances.
sleap/io/cameras.py Refined instance handling in FrameGroup to ensure proper linking without an InstanceGroup.

Possibly related issues

🐇🎉
Oh hooray, oh joy, let's hop and twirl,
For code that's neat as a bunny's whirl.
Instances join, and none shall miss,
In frame groups' dance, a coder's bliss.
🌟🐾


Recent Review Details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits Files that changed from the base of the PR and between 8d3e232 and 0b3adbf.
Files selected for processing (3)
  • sleap/gui/commands.py (1 hunks)
  • sleap/io/cameras.py (3 hunks)
  • sleap/io/dataset.py (2 hunks)
Additional Context Used
Ruff (34)
sleap/gui/commands.py (11)

38-38: itertools.permutations imported but unused


38-38: itertools.product imported but unused


40-40: typing.cast imported but unused


57-57: sleap.io.cameras.Camcorder imported but unused


196-196: Undefined name MainWindow


834-834: Local variable file_dir is assigned to but never used


1708-1708: Do not use bare except


1729-1729: Do not use bare except


2466-2466: f-string without any placeholders


2798-2798: f-string without any placeholders


3161-3161: Do not use bare except

sleap/io/cameras.py (7)

79-79: f-string without any placeholders


80-80: f-string without any placeholders


81-81: f-string without any placeholders


448-448: Undefined name Skeleton


601-601: Undefined name Skeleton


829-829: Do not use bare except


1003-1003: Undefined name Labels

sleap/io/dataset.py (16)

55-55: Redefinition of unused Callable from line 45


61-61: h5py imported but unused


69-69: Do not use bare except


70-70: typing._ForwardRef imported but unused


365-365: Do not assign a lambda expression, use a def


367-370: Do not assign a lambda expression, use a def


372-375: Do not assign a lambda expression, use a def


934-934: Do not compare types, use isinstance()


1484-1484: Do not compare types, use isinstance()


2389-2389: Undefined name glob


2484-2484: Avoid equality comparisons to False; use if not ret: for false checks


2572-2572: Avoid equality comparisons to False; use if not ret: for false checks


2587-2587: Undefined name sleap


2677-2677: Do not compare types, use isinstance()


2680-2680: Local variable e is assigned to but never used


2682-2682: f-string without any placeholders

Additional comments not posted (2)
sleap/io/cameras.py (1)

Line range hint 601-601: The name Skeleton is undefined in this scope, which will cause a runtime error.

sleap/gui/commands.py (1)

2931-2950: Ensure that the new instance is correctly added to the InstanceGroup.

Please verify that the InstanceGroup and FrameGroup are correctly updated when a new instance is added. This is crucial for maintaining data integrity and ensuring that the GUI reflects the current state of the model.


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share
Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@roomrys roomrys added the MultiView Stack This PR is part of the MultView stacked PRs. label Apr 25, 2024
@roomrys roomrys changed the title Debug missing PredictedInstances (not displaying in GUI) (3a -> 3) Debug missing PredictedInstances (not displaying in GUI) Apr 25, 2024
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Out of diff range and nitpick comments (7)
sleap/io/cameras.py (4)

Line range hint 79-81: Consider removing unnecessary f-string usage as there are no placeholders.

- logger.warning(f"{session} not found in {self}.")
+ logger.warning(f"{session} not found in this Camcorder.")
- logger.warning(f"{video} not found in {self}.")
+ logger.warning(f"{video} not found in this Camcorder.")

Line range hint 448-448: The name Skeleton is undefined in this scope, which will cause a runtime error.

Please ensure that Skeleton is defined or imported correctly in this file.


Line range hint 829-829: Avoid using a bare except statement as it can catch unexpected exceptions and make debugging difficult.

- except:
+ except Exception as e:
+     logger.error(f"Error occurred: {e}")

Line range hint 1003-1003: The name Labels is undefined in this scope, which will cause a runtime error.

Please ensure that Labels is defined or imported correctly in this file.

sleap/io/dataset.py (3)

Line range hint 61-61: Remove unused import of h5py.

- import h5py as h5

Line range hint 69-69: Replace bare except with specific exceptions to avoid catching unexpected errors.

- except:
+ except ImportError:

Line range hint 55-55: Remove duplicate import of Callable.

- from typing import (
-     Callable,
+ from typing import (

Comment on lines +2931 to +2950
# Also add the instance to the frame group if it exists
video = context.state["video"]
session = context.labels.get_session(video=video)
if session is None:
return

frame_idx = context.state["frame_idx"]
frame_group = session.frame_groups.get(frame_idx, None)
if frame_group is None:
return

instance_group = frame_group.get_instance_group(instance=from_predicted)
if instance_group is None:
return

camera = session.get_camera(video=video)
frame_group.add_instance(
instance=new_instance, camera=camera, instance_group=instance_group
)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactor the addition of new instances to InstanceGroup for clarity and error handling.

Consider refactoring this block to separate the concerns of checking for the existence of session, frame group, and instance group, and the actual addition of the instance. This can improve readability and maintainability. Additionally, consider adding error handling for cases where the session, frame group, or instance group does not exist.

-        if session is None:
-            return
-        frame_idx = context.state["frame_idx"]
-        frame_group = session.frame_groups.get(frame_idx, None)
-        if frame_group is None:
-            return
-        instance_group = frame_group.get_instance_group(instance=from_predicted)
-        if instance_group is None:
-            return
-        camera = session.get_camera(video=video)
-        frame_group.add_instance(
-            instance=new_instance, camera=camera, instance_group=instance_group
-        )
+        if session and frame_group and instance_group:
+            frame_idx = context.state["frame_idx"]
+            frame_group = session.frame_groups.get(frame_idx, None)
+            instance_group = frame_group.get_instance_group(instance=from_predicted)
+            camera = session.get_camera(video=video)
+            frame_group.add_instance(
+                instance=new_instance, camera=camera, instance_group=instance_group
+            )
+        else:
+            logger.error("Session, FrameGroup, or InstanceGroup not found.")

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
# Also add the instance to the frame group if it exists
video = context.state["video"]
session = context.labels.get_session(video=video)
if session is None:
return
frame_idx = context.state["frame_idx"]
frame_group = session.frame_groups.get(frame_idx, None)
if frame_group is None:
return
instance_group = frame_group.get_instance_group(instance=from_predicted)
if instance_group is None:
return
camera = session.get_camera(video=video)
frame_group.add_instance(
instance=new_instance, camera=camera, instance_group=instance_group
)
# Also add the instance to the frame group if it exists
video = context.state["video"]
session = context.labels.get_session(video=video)
if session and frame_group and instance_group:
frame_idx = context.state["frame_idx"]
frame_group = session.frame_groups.get(frame_idx, None)
instance_group = frame_group.get_instance_group(instance=from_predicted)
camera = session.get_camera(video=video)
frame_group.add_instance(
instance=new_instance, camera=camera, instance_group=instance_group
)
else:
logger.error("Session, FrameGroup, or InstanceGroup not found.")

Comment on lines +1408 to +1442
"""Remove instance from frame, updating track occupancy and `FrameGroup`."""

frame.instances.remove(instance)
if not in_transaction:
self._cache.remove_instance(frame, instance)

# Also remove instance from `InstanceGroup` if any
session = self.get_session(frame.video)
if session is None:
return # No session, so no `FrameGroup` to update
frame_group: FrameGroup = session.frame_groups.get(frame.frame_idx, None)
if frame_group is None:
return # No `FrameGroup` for this frame
video = frame.video
camera = session.get_camera(video=video)
if camera is None:
return # No camera, so no `InstanceGroup` to update

# If `Instance.from_predicted`, then replace with `PredictedInstance`
instance_group = frame_group.get_instance_group(instance=instance)
replace_instance = (instance.from_predicted is not None) and (
instance_group is not None
)

# Add the new instance to the `FrameGroup` and replace the old one
if replace_instance:
frame_group.add_instance(
instance=instance.from_predicted,
camera=camera,
instance_group=instance_group,
)
# Otherwise just remove the instance
else:
frame_group.remove_instance(instance=instance)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactor remove_instance to simplify logic and improve readability.

-        if not in_transaction:
-            self._cache.remove_instance(frame, instance)
-
-        # Also remove instance from `InstanceGroup` if any
-        session = self.get_session(frame.video)
-        if session is None:
-            return  # No session, so no `FrameGroup` to update
-        frame_group: FrameGroup = session.frame_groups.get(frame.frame_idx, None)
-        if frame_group is None:
-            return  # No `FrameGroup` for this frame
-        video = frame.video
-        camera = session.get_camera(video=video)
-        if camera is None:
-            return  # No camera, so no `InstanceGroup` to update
-
-        # If `Instance.from_predicted`, then replace with `PredictedInstance`
-        instance_group = frame_group.get_instance_group(instance=instance)
-        replace_instance = (instance.from_predicted is not None) and (
-            instance_group is not None
-        )
-
-        # Add the new instance to the `FrameGroup` and replace the old one
-        if replace_instance:
-            frame_group.add_instance(
-                instance=instance.from_predicted,
-                camera=camera,
-                instance_group=instance_group,
-            )
-        # Otherwise just remove the instance
-        else:
-            frame_group.remove_instance(instance=instance)
+        if not in_transaction:
+            self._cache.remove_instance(frame, instance)
+
+        session = self.get_session(frame.video)
+        if session:
+            frame_group = session.frame_groups.get(frame.frame_idx, None)
+            if frame_group:
+                video = frame.video
+                camera = session.get_camera(video=video)
+                if camera:
+                    instance_group = frame_group.get_instance_group(instance=instance)
+                    if instance.from_predicted and instance_group:
+                        frame_group.add_instance(
+                            instance=instance.from_predicted,
+                            camera=camera,
+                            instance_group=instance_group,
+                        )
+                    else:
+                        frame_group.remove_instance(instance=instance)

This refactoring reduces the depth of conditional nesting and clarifies the conditions under which different actions are taken. It also combines checks to reduce redundancy and improve the flow of the method.


Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
"""Remove instance from frame, updating track occupancy and `FrameGroup`."""
frame.instances.remove(instance)
if not in_transaction:
self._cache.remove_instance(frame, instance)
# Also remove instance from `InstanceGroup` if any
session = self.get_session(frame.video)
if session is None:
return # No session, so no `FrameGroup` to update
frame_group: FrameGroup = session.frame_groups.get(frame.frame_idx, None)
if frame_group is None:
return # No `FrameGroup` for this frame
video = frame.video
camera = session.get_camera(video=video)
if camera is None:
return # No camera, so no `InstanceGroup` to update
# If `Instance.from_predicted`, then replace with `PredictedInstance`
instance_group = frame_group.get_instance_group(instance=instance)
replace_instance = (instance.from_predicted is not None) and (
instance_group is not None
)
# Add the new instance to the `FrameGroup` and replace the old one
if replace_instance:
frame_group.add_instance(
instance=instance.from_predicted,
camera=camera,
instance_group=instance_group,
)
# Otherwise just remove the instance
else:
frame_group.remove_instance(instance=instance)
"""Remove instance from frame, updating track occupancy and `FrameGroup`."""
frame.instances.remove(instance)
if not in_transaction:
self._cache.remove_instance(frame, instance)
session = self.get_session(frame.video)
if session:
frame_group = session.frame_groups.get(frame.frame_idx, None)
if frame_group:
video = frame.video
camera = session.get_camera(video=video)
if camera:
instance_group = frame_group.get_instance_group(instance=instance)
if instance.from_predicted and instance_group:
frame_group.add_instance(
instance=instance.from_predicted,
camera=camera,
instance_group=instance_group,
)
else:
frame_group.remove_instance(instance=instance)

Copy link

codecov bot commented Apr 25, 2024

Codecov Report

Attention: Patch coverage is 29.03226% with 22 lines in your changes are missing coverage. Please review.

Project coverage is 73.78%. Comparing base (8d3e232) to head (0b3adbf).

Files Patch % Lines
sleap/io/dataset.py 25.00% 12 Missing ⚠️
sleap/gui/commands.py 30.76% 9 Missing ⚠️
sleap/io/cameras.py 50.00% 1 Missing ⚠️
Additional details and impacted files
@@                                 Coverage Diff                                 @@
##           liezl/asc-initial-update-instances-across-views    #1757      +/-   ##
===================================================================================
- Coverage                                            73.84%   73.78%   -0.06%     
===================================================================================
  Files                                                  135      135              
  Lines                                                24890    24919      +29     
===================================================================================
+ Hits                                                 18379    18387       +8     
- Misses                                                6511     6532      +21     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@roomrys roomrys merged commit 507eefa into liezl/asc-initial-update-instances-across-views Apr 25, 2024
6 of 9 checks passed
@roomrys roomrys deleted the liezl/debug-missing-predicted-instances branch April 25, 2024 21:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
MultiView Stack This PR is part of the MultView stacked PRs.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant