Visitar URL original
Fix GUI freeze when showing trajectory plots in Analyze Videos by C-Achard · Pull Request #3466 · DeepLabCut/DeepLabCut · GitHub
Skip to content
Merged
Changes from 4 commits
Commits
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
99 changes: 94 additions & 5 deletions deeplabcut/gui/tabs/analyze_videos.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from pathlib import Path

from PySide6 import QtWidgets
from PySide6.QtCore import Qt
from PySide6.QtCore import Qt, QTimer, Slot

import deeplabcut
from deeplabcut.core.config import ProjectConfig
Expand Down Expand Up @@ -53,12 +53,72 @@ class AnalyzeVideos(DefaultTab):
def __init__(self, root, parent, h1_description):
super().__init__(root, parent, h1_description)

self._pending_plot_timer = QTimer(self)
self._pending_plot_timer.setSingleShot(True)
self._pending_plot_timer.setInterval(0)
self._pending_plot_timer.timeout.connect(self._show_pending_trajectory_plots)
self._pending_plot_options: AnalyzeVideosOptions | None = None
self._pending_plot_batches: list[tuple[str, list[Path]]] | None = None
self._analysis_failed = False

self._set_page()

@property
def files(self):
return self.video_selection_widget.files

@Slot(object)
def _handle_analysis_error(self, _error):
self._analysis_failed = True

Comment thread
C-Achard marked this conversation as resolved.
Resolved
def _show_trajectory_plots_safely(
self,
options: AnalyzeVideosOptions,
batches: list[tuple[str, list[Path]]],
):
try:
self._show_trajectory_plots(options, batches)
except Exception as error:
self.root.logger.error(
"Failed to display trajectory plots.",
exc_info=True,
)
self.root.show_task_error(error)

@Slot()
def _show_pending_trajectory_plots(self):
options = self._pending_plot_options
batches = self._pending_plot_batches

self._pending_plot_options = None
self._pending_plot_batches = None

if options is None or batches is None:
return

self._show_trajectory_plots_safely(options, batches)

@Slot()
def _handle_analysis_finished(self):
should_show_plots = (
not self._analysis_failed
and self._pending_plot_options is not None
and self._pending_plot_batches is not None
and self._pending_plot_options.plot_trajectories
and self._pending_plot_options.show_trajectory_plots
)

self._analysis_failed = False

self.analyze_videos_btn.setEnabled(True)
self.root._progress_bar.hide()

if should_show_plots:
self._pending_plot_timer.start()
else:
self._pending_plot_options = None
self._pending_plot_batches = None

Comment thread
C-Achard marked this conversation as resolved.
Resolved
def _set_page(self):
self.main_layout.addWidget(_create_label_widget("Video Selection", "font:bold"))
self.video_selection_widget = VideoSelectionWidget(
Expand Down Expand Up @@ -392,15 +452,15 @@ def _run_postprocessing_for_group(
track_method=options.track_method,
)

if options.plot_trajectories:
if options.plot_trajectories and not options.show_trajectory_plots:
deeplabcut.plot_trajectories(
options.config_path,
videos=videos,
displayedbodyparts=options.displayed_bodyparts,
video_extensions=videotype,
shuffle=options.shuffle,
filtered=options.filter_data,
showfigures=options.show_trajectory_plots,
showfigures=False,
Comment thread
C-Achard marked this conversation as resolved.
Resolved
track_method=options.track_method,
)

Expand All @@ -414,7 +474,26 @@ def _convert_outputs_to_csv_once_per_folder(self, batches: list[tuple[str, list[
listofvideos=False,
)

def _show_trajectory_plots(
self,
options: AnalyzeVideosOptions,
batches: list[tuple[str, list[Path]]],
):
for videotype, videos in batches:
deeplabcut.plot_trajectories(
options.config_path,
videos=videos,
displayedbodyparts=options.displayed_bodyparts,
video_extensions=videotype,
shuffle=options.shuffle,
filtered=options.filter_data,
showfigures=True,
track_method=options.track_method,
)

Comment on lines +455 to +465

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The worker thread had already run plot_trajectories by this stage. Also the GUI still hangs while redrawing the figures here on the GUI thread.

This can be fixed in a follow-up PR (see #3578)

def analyze_videos(self):
self._pending_plot_timer.stop()

options = self._collect_options()
batches = self._get_video_batches()

Expand All @@ -431,12 +510,22 @@ def analyze_videos(self):
cfg.default_track_method = options.track_method
cfg.to_yaml(self.root.config_path, overwrite=True, log_changes=True, mark_clean=True)

self._pending_plot_options = options
self._pending_plot_batches = batches
self._analysis_failed = False

func = partial(self._run_pipeline, options, batches)

self.worker, self.thread = move_to_separate_thread(func)

self.worker.error.connect(self._handle_analysis_error)
self.worker.error.connect(self.root.show_task_error)
self.worker.finished.connect(lambda: self.analyze_videos_btn.setEnabled(True))
self.worker.finished.connect(lambda: self.root._progress_bar.hide())

self.worker.finished.connect(
self._handle_analysis_finished,
Qt.ConnectionType.QueuedConnection,
)

self.thread.start()
self.analyze_videos_btn.setEnabled(False)
self.root._progress_bar.show()
Loading