Skip to content

Commit a1364ec

Browse files
committed
hit my first cursor usage limit
1 parent d088213 commit a1364ec

13 files changed

Lines changed: 240 additions & 167 deletions

src/kymflow/core/image_loaders/kym_analysis.py

Lines changed: 69 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@
2525
from kymflow.core.analysis.utils import _medianFilter, _removeOutliers
2626
from kymflow.core.utils.logging import get_logger
2727

28-
from kymflow.core.analysis.stall_analysis import StallAnalysis, StallAnalysisParams
28+
# DEPRECATED: Stall analysis is deprecated
29+
# from kymflow.core.analysis.stall_analysis import StallAnalysis, StallAnalysisParams
2930
from kymflow.core.analysis.velocity_events.velocity_events import (
3031
UserType,
3132
VelocityEvent,
@@ -145,7 +146,8 @@ def __init__(
145146
self._analysis_metadata: Dict[int, RoiAnalysisMetadata] = {}
146147
self._df: Optional[pd.DataFrame] = None
147148
self._dirty: bool = False
148-
self._stall_analysis: Dict[int, StallAnalysis] = {}
149+
# DEPRECATED: Stall analysis is deprecated
150+
# self._stall_analysis: Dict[int, StallAnalysis] = {}
149151
# Stall analysis is computed on-demand from stored analysis values (e.g., velocity).
150152
self._velocity_events: Dict[int, List[VelocityEvent]] = {}
151153
# Velocity events are computed on-demand from stored analysis values (e.g., velocity).
@@ -449,9 +451,10 @@ def save_analysis(self) -> bool:
449451
}
450452
for rid, meta in self._analysis_metadata.items()
451453
},
452-
"stall_analysis": {
453-
str(rid): sa.to_dict() for rid, sa in self._stall_analysis.items()
454-
},
454+
# DEPRECATED: Stall analysis is deprecated
455+
# "stall_analysis": {
456+
# str(rid): sa.to_dict() for rid, sa in self._stall_analysis.items()
457+
# },
455458
"velocity_events": {
456459
str(rid): [ev.to_dict() for ev in evs]
457460
for rid, evs in self._velocity_events.items()
@@ -534,15 +537,15 @@ def load_analysis(self) -> bool:
534537
except Exception as e:
535538
logger.warning(f"Skipping invalid analysis metadata entry {key}: {e}")
536539

537-
538-
# Load stall analysis (optional; may be absent in older analysis JSON).
539-
self._stall_analysis.clear()
540-
for roi_id_str, payload in json_data.get("stall_analysis", {}).items():
541-
try:
542-
roi_id = int(roi_id_str)
543-
self._stall_analysis[roi_id] = StallAnalysis.from_dict(payload)
544-
except Exception as e:
545-
logger.warning(f"Skipping invalid stall_analysis entry {roi_id_str}: {e}")
540+
# DEPRECATED: Stall analysis is deprecated
541+
# # Load stall analysis (optional; may be absent in older analysis JSON).
542+
# self._stall_analysis.clear()
543+
# for roi_id_str, payload in json_data.get("stall_analysis", {}).items():
544+
# try:
545+
# roi_id = int(roi_id_str)
546+
# self._stall_analysis[roi_id] = StallAnalysis.from_dict(payload)
547+
# except Exception as e:
548+
# logger.warning(f"Skipping invalid stall_analysis entry {roi_id_str}: {e}")
546549

547550
# Load velocity events (optional; may be absent in older analysis JSON).
548551
self._velocity_events.clear()
@@ -568,9 +571,10 @@ def load_analysis(self) -> bool:
568571
self._analysis_metadata = {
569572
rid: meta for rid, meta in self._analysis_metadata.items() if rid in current_roi_ids
570573
}
571-
self._stall_analysis = {
572-
rid: sa for rid, sa in self._stall_analysis.items() if rid in current_roi_ids
573-
}
574+
# DEPRECATED: Stall analysis is deprecated
575+
# self._stall_analysis = {
576+
# rid: sa for rid, sa in self._stall_analysis.items() if rid in current_roi_ids
577+
# }
574578
# Remove events for deleted ROIs and clean up UUID mappings
575579
removed_roi_ids = set(self._velocity_events.keys()) - current_roi_ids
576580
for removed_roi_id in removed_roi_ids:
@@ -655,53 +659,54 @@ def get_analysis_value(
655659
return values
656660

657661

658-
def run_stall_analysis(self, roi_id: int, params: StallAnalysisParams) -> StallAnalysis:
659-
"""Run stall analysis for a single ROI and store results.
660-
661-
This method is intentionally **on-demand**: it does not run automatically
662-
when flow analysis is computed. A caller (GUI/script) supplies parameters and
663-
explicitly requests stall detection once the underlying analysis values exist.
664-
665-
The source signal is selected via `params.velocity_key` (e.g. 'velocity',
666-
'cleanVelocity', 'signedVelocity').
667-
668-
Args:
669-
roi_id: Identifier of the ROI to analyze.
670-
params: Stall analysis parameters.
671-
672-
Returns:
673-
The computed `StallAnalysis` instance.
674-
675-
Raises:
676-
ValueError: If the requested analysis values are missing for this ROI.
677-
"""
678-
values = self.get_analysis_value(
679-
roi_id=roi_id,
680-
key=params.velocity_key,
681-
remove_outliers=False,
682-
)
683-
if values is None:
684-
raise ValueError(
685-
f"Cannot run stall analysis: ROI {roi_id} has no analysis values for key '{params.velocity_key}'."
686-
)
687-
688-
analysis = StallAnalysis.run(velocity=values, params=params)
689-
self._stall_analysis[roi_id] = analysis
690-
# Mark dirty so callers know there are unsaved results.
691-
self._dirty = True
692-
return analysis
693-
694-
def get_stall_analysis(self, roi_id: int) -> Optional[StallAnalysis]:
695-
"""Return stall analysis results for roi_id, or None if not present.
696-
697-
Args:
698-
roi_id: Identifier of the ROI.
699-
700-
Returns:
701-
Stored `StallAnalysis` results, or None if stall analysis has not been run
702-
for this ROI (or results were not loaded).
703-
"""
704-
return self._stall_analysis.get(roi_id)
662+
# DEPRECATED: Stall analysis is deprecated
663+
# def run_stall_analysis(self, roi_id: int, params: StallAnalysisParams) -> StallAnalysis:
664+
# """Run stall analysis for a single ROI and store results.
665+
#
666+
# This method is intentionally **on-demand**: it does not run automatically
667+
# when flow analysis is computed. A caller (GUI/script) supplies parameters and
668+
# explicitly requests stall detection once the underlying analysis values exist.
669+
#
670+
# The source signal is selected via `params.velocity_key` (e.g. 'velocity',
671+
# 'cleanVelocity', 'signedVelocity').
672+
#
673+
# Args:
674+
# roi_id: Identifier of the ROI to analyze.
675+
# params: Stall analysis parameters.
676+
#
677+
# Returns:
678+
# The computed `StallAnalysis` instance.
679+
#
680+
# Raises:
681+
# ValueError: If the requested analysis values are missing for this ROI.
682+
# """
683+
# values = self.get_analysis_value(
684+
# roi_id=roi_id,
685+
# key=params.velocity_key,
686+
# remove_outliers=False,
687+
# )
688+
# if values is None:
689+
# raise ValueError(
690+
# f"Cannot run stall analysis: ROI {roi_id} has no analysis values for key '{params.velocity_key}'."
691+
# )
692+
#
693+
# analysis = StallAnalysis.run(velocity=values, params=params)
694+
# self._stall_analysis[roi_id] = analysis
695+
# # Mark dirty so callers know there are unsaved results.
696+
# self._dirty = True
697+
# return analysis
698+
#
699+
# def get_stall_analysis(self, roi_id: int) -> Optional[StallAnalysis]:
700+
# """Return stall analysis results for roi_id, or None if not present.
701+
#
702+
# Args:
703+
# roi_id: Identifier of the ROI.
704+
#
705+
# Returns:
706+
# Stored `StallAnalysis` results, or None if stall analysis has not been run
707+
# for this ROI (or results were not loaded).
708+
# """
709+
# return self._stall_analysis.get(roi_id)
705710

706711
def run_velocity_event_analysis(
707712
self,

src/kymflow/core/plotting/line_plots.py

Lines changed: 47 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -372,49 +372,50 @@ def plot_image_line_plotly(
372372
)
373373

374374
# ------------------------------------------------------------------
375-
# Stall analysis overlays (row=2: velocity vs time)
375+
# DEPRECATED: Stall analysis is deprecated
376+
# # Stall analysis overlays (row=2: velocity vs time)
377+
# #
378+
# # Stalls are stored on the KymAnalysis object (computed on-demand).
379+
# # We map stall bin indices to time using analysis_time_values and draw
380+
# # vertical rectangles spanning the full subplot height.
381+
# # ------------------------------------------------------------------
382+
# if selected_roi_id is not None:
383+
# stall_analysis = kym_analysis.get_stall_analysis(selected_roi_id)
384+
# else:
385+
# stall_analysis = None
376386
#
377-
# Stalls are stored on the KymAnalysis object (computed on-demand).
378-
# We map stall bin indices to time using analysis_time_values and draw
379-
# vertical rectangles spanning the full subplot height.
380-
# ------------------------------------------------------------------
381-
if selected_roi_id is not None:
382-
stall_analysis = kym_analysis.get_stall_analysis(selected_roi_id)
383-
else:
384-
stall_analysis = None
385-
386-
if stall_analysis is not None and stall_analysis.stalls:
387-
n_time = len(analysis_time_values)
388-
for stall in stall_analysis.stalls:
389-
if not (0 <= stall.bin_start < n_time and 0 <= stall.bin_stop < n_time):
390-
logger.warning(
391-
"Skipping out-of-range stall for ROI %s: [%s, %s] (time_len=%s)",
392-
selected_roi_id,
393-
stall.bin_start,
394-
stall.bin_stop,
395-
n_time,
396-
)
397-
continue
398-
399-
x0 = float(analysis_time_values[stall.bin_start])
400-
x1 = float(analysis_time_values[stall.bin_stop])
401-
if x1 < x0:
402-
x0, x1 = x1, x0
403-
404-
# Use yref='y2 domain' so rectangles span the full height of row=2.
405-
fig.add_shape(
406-
type="rect",
407-
xref="x2",
408-
yref="y2 domain",
409-
x0=x0,
410-
x1=x1,
411-
y0=0,
412-
y1=1,
413-
fillcolor="cyan",
414-
opacity=0.25,
415-
line_width=0,
416-
layer="below",
417-
)
387+
# if stall_analysis is not None and stall_analysis.stalls:
388+
# n_time = len(analysis_time_values)
389+
# for stall in stall_analysis.stalls:
390+
# if not (0 <= stall.bin_start < n_time and 0 <= stall.bin_stop < n_time):
391+
# logger.warning(
392+
# "Skipping out-of-range stall for ROI %s: [%s, %s] (time_len=%s)",
393+
# selected_roi_id,
394+
# stall.bin_start,
395+
# stall.bin_stop,
396+
# n_time,
397+
# )
398+
# continue
399+
#
400+
# x0 = float(analysis_time_values[stall.bin_start])
401+
# x1 = float(analysis_time_values[stall.bin_stop])
402+
# if x1 < x0:
403+
# x0, x1 = x1, x0
404+
#
405+
# # Use yref='y2 domain' so rectangles span the full height of row=2.
406+
# fig.add_shape(
407+
# type="rect",
408+
# xref="x2",
409+
# yref="y2 domain",
410+
# x0=x0,
411+
# x1=x1,
412+
# y0=0,
413+
# y1=1,
414+
# fillcolor="cyan",
415+
# opacity=0.25,
416+
# line_width=0,
417+
# layer="below",
418+
# )
418419
else:
419420
# No analysis data - show message
420421
fig.add_annotation(
@@ -539,9 +540,10 @@ def _add_single_roi_line_plot(
539540
col=1,
540541
)
541542

542-
# Add stall analysis overlays
543-
logger.warning('turned of stall analysis plot')
544-
if 0:
543+
# DEPRECATED: Stall analysis is deprecated
544+
# # Add stall analysis overlays
545+
# logger.warning('turned of stall analysis plot')
546+
if 0: # DEPRECATED: Stall analysis is deprecated
545547
stall_analysis = kym_analysis.get_stall_analysis(roi_id)
546548
if stall_analysis is not None and stall_analysis.stalls:
547549
n_time = len(analysis_time_values)

src/kymflow/core/user_config.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,9 @@ def save(self) -> None:
310310
payload = self.data.to_json_dict()
311311
logger.info('saving user_config to disk')
312312
# logger.info(f'payload: {payload}')
313+
from pprint import pprint
314+
pprint(payload, sort_dicts=False, indent=4)
315+
313316
self.path.write_text(json.dumps(payload, indent=2), encoding="utf-8")
314317

315318
def ensure_exists(self) -> None:

src/kymflow/gui_v2/app.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ def _warm_mpl_font_cache_once() -> None:
9898
# _DEFAULT_DEV_FOLDER = Path("/Users/cudmore/Dropbox/data/declan/2026/data/20251204")
9999

100100
DEV_FOLDER = Path(os.getenv("KYMFLOW_DEV_FOLDER", str(_DEFAULT_DEV_FOLDER))).expanduser()
101-
USE_DEV_FOLDER = os.getenv("KYMFLOW_USE_DEV_FOLDER", "1") == "1"
101+
USE_DEV_FOLDER = os.getenv("KYMFLOW_USE_DEV_FOLDER", "0") == "1" # Default to "0" (disabled)
102102

103103
# USE_DEV_FOLDER = False # abb turn of before impleenting ~/ kymflow config json
104104

@@ -265,7 +265,8 @@ def main(*, reload: bool | None = None, native: bool | None = None) -> None:
265265

266266
reload = False
267267
native = True
268-
install_shutdown_handlers(context)
268+
269+
install_shutdown_handlers(context, native=native)
269270

270271
ui.run(
271272
port=DEFAULT_PORT,

src/kymflow/gui_v2/app_context.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from __future__ import annotations
99

1010
import multiprocessing as mp
11+
import os
1112
from pathlib import Path
1213
from typing import Optional
1314

@@ -78,7 +79,11 @@ def __init__(self) -> None:
7879

7980
# Shared state instances
8081
self.app_state = AppState()
81-
self.user_config = UserConfig.load()
82+
user_config_path = os.getenv("KYMFLOW_USER_CONFIG_PATH")
83+
if user_config_path:
84+
self.user_config = UserConfig.load(config_path=Path(user_config_path))
85+
else:
86+
self.user_config = UserConfig.load()
8287
logger.info(f"User config loaded from: {self.user_config.path}")
8388
self.home_task = TaskState()
8489
self.batch_task = TaskState()

0 commit comments

Comments
 (0)