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

Add Skeleton Templates #1122

Merged
merged 25 commits into from
Feb 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
7f991a4
Initial Commit.
aaprasad Jan 17, 2023
2524e57
Added initial attempt at skeleton template box
aaprasad Jan 17, 2023
3b63210
Got MVP working:
aaprasad Jan 17, 2023
3a2e6cc
Added Qlabel for templates dropdown
aaprasad Jan 17, 2023
4610ebc
added test for template loading
aaprasad Jan 18, 2023
1a026a9
removed print statements and debugging stuff
aaprasad Jan 18, 2023
aa608ab
Fixed style issues
aaprasad Jan 18, 2023
2ca8bb6
Aadi/add skeleton template pr 2 (#1145)
aaprasad Feb 16, 2023
eda4c5e
Merge branch 'develop' into aadi/add-skeleton-template
roomrys Feb 16, 2023
2aa3284
Add test from replace skeleton table when no add/delete nodes
roomrys Feb 16, 2023
0c3a2de
Fix docstring in test_viz
roomrys Feb 16, 2023
db68e72
Reorganize imports and fix docstrings in util.py
roomrys Feb 16, 2023
d8c1a16
Remove QGroupBox for node/edge tables
roomrys Feb 16, 2023
6b09833
Nit: docstring fix
roomrys Feb 16, 2023
2a15615
Last of the nits
roomrys Feb 16, 2023
25f913f
Reorganize skeleton dialog
roomrys Feb 21, 2023
02327b4
Remove extra callbacks
roomrys Feb 22, 2023
900d1ce
Add collapsible group box
roomrys Feb 22, 2023
feab260
Create MVP of collapsible widget
roomrys Feb 22, 2023
491d726
Clean-up collapsible widget class
roomrys Feb 22, 2023
3e1a795
Fix arrow/content initialization
roomrys Feb 22, 2023
f77f802
Style collapsible widget
roomrys Feb 22, 2023
76d5fef
Final? clean-up for collapsible widget
roomrys Feb 22, 2023
e186d8c
Keep combo closed when toggling visibility
roomrys Feb 22, 2023
3c84be4
Merge branch 'develop' into aadi/add-skeleton-template
roomrys Feb 23, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ jobs:
if: matrix.os == 'windows-2019'
shell: bash -l {0}
run: |
pytest
pytest --durations=-1
- name: Test with pytest (Ubuntu)
if: matrix.os == 'ubuntu-20.04'
shell:
Expand All @@ -111,7 +111,7 @@ jobs:
sudo apt install xvfb libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libxcb-xfixes0
sudo Xvfb :1 -screen 0 1024x768x24 </dev/null &
export DISPLAY=":1"
xvfb-run pytest --cov=sleap --cov-report=xml tests/
xvfb-run pytest --cov=sleap --cov-report=xml --durations=-1 tests/
- name: Upload coverage
uses: codecov/codecov-action@v1
if: matrix.os == 'ubuntu-20.04'
Expand Down
113 changes: 99 additions & 14 deletions sleap/gui/app.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
"""
Main GUI application for labeling, training/inference, and proofreading.
"""Main GUI application for labeling, training/inference, and proofreading.

Each open project is an instance of :py:class:`MainWindow`.

Expand Down Expand Up @@ -50,7 +49,6 @@
import os
import random
import platform
import requests
from pathlib import Path

from typing import Callable, List, Optional, Tuple
Expand All @@ -59,7 +57,7 @@
from qtpy.QtCore import Qt, QEvent

from qtpy.QtWidgets import QApplication, QMainWindow, QWidget, QDockWidget
from qtpy.QtWidgets import QVBoxLayout, QHBoxLayout, QGroupBox
from qtpy.QtWidgets import QVBoxLayout, QHBoxLayout, QGroupBox, QTabWidget
from qtpy.QtWidgets import QLabel, QPushButton, QComboBox
from qtpy.QtWidgets import QMessageBox

Expand All @@ -70,6 +68,7 @@
from sleap.io.dataset import Labels
from sleap.info.summary import StatisticSeries
from sleap.gui.commands import CommandContext, UpdateTopic
from sleap.gui.widgets.views import CollapsibleWidget
from sleap.gui.widgets.video import QtVideoPlayer
from sleap.gui.widgets.slider import set_slider_marks_from_labels
from sleap.gui.dataviews import (
Expand All @@ -81,7 +80,12 @@
LabeledFrameTableModel,
SkeletonNodeModel,
)
from sleap.util import parse_uri_path
from sleap.util import (
parse_uri_path,
decode_preview_image,
get_package_file,
find_files_by_suffix,
)

from sleap.gui.dialogs.filedialog import FileDialog
from sleap.gui.dialogs.formbuilder import YamlFormWidget, FormBuilderModalDialog
Expand Down Expand Up @@ -161,6 +165,8 @@ def __init__(
self.state["propagate track labels"] = prefs["propagate track labels"]
self.state["node label size"] = prefs["node label size"]
self.state["share usage data"] = prefs["share usage data"]
self.state["skeleton_preview_image"] = None
self.state["skeleton_description"] = "No skeleton loaded yet"
if no_usage_data:
self.state["share usage data"] = False
self.state.connect("marker size", self.plotFrame)
Expand Down Expand Up @@ -1006,8 +1012,78 @@ def _add_button(to, label, action, key=None):
"Skeleton", tab_with=videos_layout.parent().parent()
)

gb = QGroupBox("Nodes")
gb = CollapsibleWidget("Templates")
vb = QVBoxLayout()
hb = QHBoxLayout()

skeletons_folder = get_package_file("sleap/skeletons")
skeletons_json_files = find_files_by_suffix(
skeletons_folder, suffix=".json", depth=1
)
skeletons_names = [json.name.split(".")[0] for json in skeletons_json_files]
self.skeletonTemplates = QComboBox()
self.skeletonTemplates.addItems(skeletons_names)
self.skeletonTemplates.setEditable(False)
hb.addWidget(self.skeletonTemplates)
_add_button(hb, "Load", self.commands.openSkeletonTemplate)
hbw = QWidget()
hbw.setLayout(hb)
vb.addWidget(hbw)

hb = QHBoxLayout()
self.skeleton_preview_image = QLabel("Preview Skeleton")
hb.addWidget(self.skeleton_preview_image)
hb.setAlignment(self.skeleton_preview_image, Qt.AlignLeft)

self.skeleton_description = QLabel(
f'<strong>Description:</strong> {self.state["skeleton_description"]}'
)
self.skeleton_description.setWordWrap(True)
hb.addWidget(self.skeleton_description)
hb.setAlignment(self.skeleton_description, Qt.AlignLeft)

hbw = QWidget()
hbw.setLayout(hb)
vb.addWidget(hbw)

def updatePreviewImage(preview_image_bytes: bytes):

# Decode the preview image
preview_image = decode_preview_image(preview_image_bytes)

# Create a QImage from the Image
preview_image = QtGui.QImage(
preview_image.tobytes(),
preview_image.size[0],
preview_image.size[1],
QtGui.QImage.Format_RGBA8888, # Format for RGBA images (see Image.mode)
)

preview_image = QtGui.QPixmap.fromImage(preview_image)

self.skeleton_preview_image.setPixmap(preview_image)

gb.set_content_layout(vb)
skeleton_layout.addWidget(gb)

def update_skeleton_preview(idx: int):
skel = Skeleton.load_json(skeletons_json_files[idx])
self.state["skeleton_description"] = (
f"<strong>Description:</strong> {skel.description}<br><br>"
f"<strong>Nodes ({len(skel)}):</strong> {', '.join(skel.node_names)}"
)
self.skeleton_description.setText(self.state["skeleton_description"])
updatePreviewImage(skel.preview_image)

self.skeletonTemplates.currentIndexChanged.connect(update_skeleton_preview)
update_skeleton_preview(idx=0)

gb = QGroupBox("Project Skeleton")
vgb = QVBoxLayout()

nodes_widget = QWidget()
vb = QVBoxLayout()
graph_tabs = QTabWidget()
self.skeletonNodesTable = GenericTableView(
state=self.state,
row_name="node",
Expand All @@ -1023,13 +1099,13 @@ def _add_button(to, label, action, key=None):
hbw = QWidget()
hbw.setLayout(hb)
vb.addWidget(hbw)
gb.setLayout(vb)
skeleton_layout.addWidget(gb)
nodes_widget.setLayout(vb)
graph_tabs.addTab(nodes_widget, "Nodes")

def _update_edge_src():
self.skeletonEdgesDst.model().skeleton = self.state["skeleton"]

gb = QGroupBox("Edges")
edges_widget = QWidget()
vb = QVBoxLayout()
self.skeletonEdgesTable = GenericTableView(
state=self.state,
Expand Down Expand Up @@ -1066,16 +1142,21 @@ def new_edge():
hbw = QWidget()
hbw.setLayout(hb)
vb.addWidget(hbw)
gb.setLayout(vb)
skeleton_layout.addWidget(gb)
edges_widget.setLayout(vb)
graph_tabs.addTab(edges_widget, "Edges")
vgb.addWidget(graph_tabs)

hb = QHBoxLayout()
_add_button(hb, "Load Skeleton", self.commands.openSkeleton)
_add_button(hb, "Save Skeleton", self.commands.saveSkeleton)
_add_button(hb, "Load From File...", self.commands.openSkeleton)
_add_button(hb, "Save As...", self.commands.saveSkeleton)

hbw = QWidget()
hbw.setLayout(hb)
skeleton_layout.addWidget(hbw)
vgb.addWidget(hbw)

# Add graph tabs to "Project Skeleton" group box
gb.setLayout(vgb)
skeleton_layout.addWidget(gb)

####### Suggestions #######
suggestions_layout = _make_dock(
Expand Down Expand Up @@ -1836,3 +1917,7 @@ def main(args: Optional[list] = None):
app.exec_()

pass


if __name__ == "__main__":
main()
Loading