spacr 0.4.12__py3-none-any.whl → 0.4.60__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
spacr/gui_elements.py CHANGED
@@ -726,8 +726,8 @@ class spacrProgressBar(ttk.Progressbar):
726
726
 
727
727
  def set_label_position(self):
728
728
  if self.label and self.progress_label:
729
- row_info = self.grid_info().get('row_name', 0)
730
- col_info = self.grid_info().get('column', 0)
729
+ row_info = self.grid_info().get('rowID', 0)
730
+ col_info = self.grid_info().get('columnID', 0)
731
731
  col_span = self.grid_info().get('columnspan', 1)
732
732
  self.progress_label.grid(row=row_info + 1, column=col_info, columnspan=col_span, pady=5, padx=5, sticky='ew')
733
733
 
@@ -2285,6 +2285,9 @@ class AnnotateApp:
2285
2285
 
2286
2286
  self.train_button = Button(self.button_frame,text="orig.",command=self.swich_back_annotation_column,bg=self.bg_color,fg=self.fg_color,highlightbackground=self.fg_color,highlightcolor=self.fg_color,highlightthickness=1)
2287
2287
  self.train_button.pack(side="right", padx=5)
2288
+
2289
+ self.settings_button = Button(self.button_frame, text="Settings", command=self.open_settings_window, bg=self.bg_color, fg=self.fg_color, highlightbackground=self.fg_color,highlightcolor=self.fg_color,highlightthickness=1)
2290
+ self.settings_button.pack(side="right", padx=5)
2288
2291
 
2289
2292
  # Calculate grid rows and columns based on the root window size and image size
2290
2293
  self.calculate_grid_dimensions()
@@ -2308,6 +2311,134 @@ class AnnotateApp:
2308
2311
  for col in range(self.grid_cols):
2309
2312
  self.grid_frame.grid_columnconfigure(col, weight=1)
2310
2313
 
2314
+ def open_settings_window(self):
2315
+ from .gui_utils import generate_annotate_fields, convert_to_number
2316
+
2317
+ # Create settings window
2318
+ settings_window = tk.Toplevel(self.root)
2319
+ settings_window.title("Modify Annotation Settings")
2320
+
2321
+ style_out = set_dark_style(ttk.Style())
2322
+ settings_window.configure(bg=style_out['bg_color'])
2323
+
2324
+ settings_frame = tk.Frame(settings_window, bg=style_out['bg_color'])
2325
+ settings_frame.pack(fill=tk.BOTH, expand=True)
2326
+
2327
+ # Generate fields with current settings pre-filled
2328
+ vars_dict = generate_annotate_fields(settings_frame)
2329
+
2330
+ # Pre-fill the current settings into vars_dict
2331
+ current_settings = {
2332
+ 'image_type': self.image_type or '',
2333
+ 'channels': ','.join(self.channels) if self.channels else '',
2334
+ 'img_size': f"{self.image_size[0]},{self.image_size[1]}",
2335
+ 'annotation_column': self.annotation_column or '',
2336
+ 'normalize': str(self.normalize),
2337
+ 'percentiles': ','.join(map(str, self.percentiles)),
2338
+ 'measurement': ','.join(self.measurement) if self.measurement else '',
2339
+ 'threshold': str(self.threshold) if self.threshold is not None else '',
2340
+ 'normalize_channels': ','.join(self.normalize_channels) if self.normalize_channels else ''
2341
+ }
2342
+
2343
+ for key, data in vars_dict.items():
2344
+ if key in current_settings:
2345
+ data['entry'].delete(0, tk.END)
2346
+ data['entry'].insert(0, current_settings[key])
2347
+
2348
+ def apply_new_settings():
2349
+ settings = {key: data['entry'].get() for key, data in vars_dict.items()}
2350
+
2351
+ # Process settings exactly as your original initiation function does
2352
+ settings['channels'] = settings['channels'].split(',') if settings['channels'] else None
2353
+ settings['img_size'] = list(map(int, settings['img_size'].split(',')))
2354
+ settings['percentiles'] = list(map(convert_to_number, settings['percentiles'].split(','))) if settings['percentiles'] else [1, 99]
2355
+ settings['normalize'] = settings['normalize'].lower() == 'true'
2356
+ settings['normalize_channels'] = settings['normalize_channels'].split(',') if settings['normalize_channels'] else None
2357
+
2358
+ try:
2359
+ settings['measurement'] = settings['measurement'].split(',') if settings['measurement'] else None
2360
+ settings['threshold'] = None if settings['threshold'].lower() == 'none' else int(settings['threshold'])
2361
+ except:
2362
+ settings['measurement'] = None
2363
+ settings['threshold'] = None
2364
+
2365
+ # Convert empty strings to None
2366
+ for key, value in settings.items():
2367
+ if isinstance(value, list):
2368
+ settings[key] = [v if v != '' else None for v in value]
2369
+ elif value == '':
2370
+ settings[key] = None
2371
+
2372
+ # Apply these settings dynamically using update_settings method
2373
+ self.update_settings(**{
2374
+ 'image_type': settings.get('image_type'),
2375
+ 'channels': settings.get('channels'),
2376
+ 'image_size': settings.get('img_size'),
2377
+ 'annotation_column': settings.get('annotation_column'),
2378
+ 'normalize': settings.get('normalize'),
2379
+ 'percentiles': settings.get('percentiles'),
2380
+ 'measurement': settings.get('measurement'),
2381
+ 'threshold': settings.get('threshold'),
2382
+ 'normalize_channels': settings.get('normalize_channels')
2383
+ })
2384
+
2385
+ settings_window.destroy()
2386
+
2387
+ apply_button = spacrButton(settings_window, text="Apply Settings", command=apply_new_settings,show_text=False)
2388
+ apply_button.pack(pady=10)
2389
+
2390
+ def update_settings(self, **kwargs):
2391
+ allowed_attributes = {
2392
+ 'image_type', 'channels', 'image_size', 'annotation_column',
2393
+ 'normalize', 'percentiles', 'measurement', 'threshold', 'normalize_channels'
2394
+ }
2395
+
2396
+ updated = False
2397
+
2398
+ for attr, value in kwargs.items():
2399
+ if attr in allowed_attributes and value is not None:
2400
+ setattr(self, attr, value)
2401
+ updated = True
2402
+
2403
+ if 'image_size' in kwargs:
2404
+ if isinstance(self.image_size, list):
2405
+ self.image_size = (int(self.image_size[0]), int(self.image_size[0]))
2406
+ elif isinstance(self.image_size, int):
2407
+ self.image_size = (self.image_size, self.image_size)
2408
+ else:
2409
+ raise ValueError("Invalid image size")
2410
+
2411
+ self.calculate_grid_dimensions()
2412
+ self.recreate_image_grid()
2413
+
2414
+ if updated:
2415
+ current_index = self.index # Retain current index
2416
+ self.prefilter_paths_annotations()
2417
+
2418
+ # Ensure the retained index is still valid (not out of bounds)
2419
+ max_index = len(self.filtered_paths_annotations) - 1
2420
+ self.index = min(current_index, max_index := max(0, max(0, max(len(self.filtered_paths_annotations) - self.grid_rows * self.grid_cols, 0))))
2421
+ self.load_images()
2422
+
2423
+ def recreate_image_grid(self):
2424
+ # Remove current labels
2425
+ for label in self.labels:
2426
+ label.destroy()
2427
+ self.labels.clear()
2428
+
2429
+ # Recreate the labels grid with updated dimensions
2430
+ for i in range(self.grid_rows * self.grid_cols):
2431
+ label = Label(self.grid_frame, bg=self.root.cget('bg'))
2432
+ label.grid(row=i // self.grid_cols, column=i % self.grid_cols, padx=2, pady=2, sticky="nsew")
2433
+ self.labels.append(label)
2434
+
2435
+ # Reconfigure grid weights
2436
+ for row in range(self.grid_rows):
2437
+ self.grid_frame.grid_rowconfigure(row, weight=1)
2438
+ for col in range(self.grid_cols):
2439
+ self.grid_frame.grid_columnconfigure(col, weight=1)
2440
+
2441
+
2311
2442
  def swich_back_annotation_column(self):
2312
2443
  self.annotation_column = self.orig_annotation_columns
2313
2444
  self.prefilter_paths_annotations()
spacr/gui_utils.py CHANGED
@@ -106,7 +106,6 @@ def parse_list(value):
106
106
  except (ValueError, SyntaxError) as e:
107
107
  raise ValueError(f"Invalid format for list: {value}. Error: {e}")
108
108
 
109
- # Usage example in your create_input_field function
110
109
  def create_input_field(frame, label_text, row, var_type='entry', options=None, default_value=None):
111
110
  """
112
111
  Create an input field in the specified frame.
@@ -365,27 +364,30 @@ def convert_settings_dict_for_gui(settings):
365
364
  from torchvision import models as torch_models
366
365
  torchvision_models = [name for name, obj in torch_models.__dict__.items() if callable(obj)]
367
366
  chans = ['0', '1', '2', '3', '4', '5', '6', '7', '8', None]
367
+ chan_list = ['[0,1,2,3,4,5,6,7,8]','[0,1,2,3,4,5,6,7]','[0,1,2,3,4,5,6]','[0,1,2,3,4,5]','[0,1,2,3,4]','[0,1,2,3]', '[0,1,2]', '[0,1]', '[0]', '[0,0]']
368
368
  chans_v2 = [0, 1, 2, 3, None]
369
+ chans_v3 = list(range(0, 21, 1)) + [None]
370
+ chans_v4 = [0, 1, 2, 3, None]
369
371
  variables = {}
370
372
  special_cases = {
371
- 'metadata_type': ('combo', ['cellvoyager', 'cq1', 'nikon', 'zeis', 'custom'], 'cellvoyager'),
372
- 'channels': ('combo', ['[0,1,2,3]', '[0,1,2]', '[0,1]', '[0]', '[0,0]'], '[0,1,2,3]'),
373
+ 'metadata_type': ('combo', ['cellvoyager', 'cq1', 'auto', 'custom'], 'cellvoyager'),
374
+ 'channels': ('combo', chan_list, '[0,1,2,3]'),
373
375
  'train_channels': ('combo', ["['r','g','b']", "['r','g']", "['r','b']", "['g','b']", "['r']", "['g']", "['b']"], "['r','g','b']"),
374
- 'channel_dims': ('combo', ['[0,1,2,3]', '[0,1,2]', '[0,1]', '[0]'], '[0,1,2,3]'),
376
+ 'channel_dims': ('combo', chan_list, '[0,1,2,3]'),
375
377
  'dataset_mode': ('combo', ['annotation', 'metadata', 'recruitment'], 'metadata'),
376
378
  'cov_type': ('combo', ['HC0', 'HC1', 'HC2', 'HC3', None], None),
377
- 'cell_mask_dim': ('combo', chans, None),
378
- 'cell_chann_dim': ('combo', chans, None),
379
- 'nucleus_mask_dim': ('combo', chans, None),
380
- 'nucleus_chann_dim': ('combo', chans, None),
381
- 'pathogen_mask_dim': ('combo', chans, None),
382
- 'pathogen_chann_dim': ('combo', chans, None),
383
- 'crop_mode': ('combo', [['cell'], ['nucleus'], ['pathogen'], ['cell', 'nucleus'], ['cell', 'pathogen'], ['nucleus', 'pathogen'], ['cell', 'nucleus', 'pathogen']], ['cell']),
384
- 'magnification': ('combo', [20, 40, 60], 20),
385
- 'nucleus_channel': ('combo', chans_v2, None),
386
- 'cell_channel': ('combo', chans_v2, None),
387
- 'channel_of_interest': ('combo', chans_v2, None),
388
- 'pathogen_channel': ('combo', chans_v2, None),
379
+ #'cell_mask_dim': ('combo', chans_v3, None),
380
+ #'cell_chann_dim': ('combo', chans_v3, None),
381
+ #'nucleus_mask_dim': ('combo', chans_v3, None),
382
+ #'nucleus_chann_dim': ('combo', chans_v3, None),
383
+ #'pathogen_mask_dim': ('combo', chans_v3, None),
384
+ #'pathogen_chann_dim': ('combo', chans_v3, None),
385
+ 'crop_mode': ('combo', ["['cell']", "['nucleus']", "['pathogen']", "['cell', 'nucleus']", "['cell', 'pathogen']", "['nucleus', 'pathogen']", "['cell', 'nucleus', 'pathogen']"], "['cell']"),
386
+ #'magnification': ('combo', [20, 40, 60], 20),
387
+ #'nucleus_channel': ('combo', chans_v3, None),
388
+ #'cell_channel': ('combo', chans_v3, None),
389
+ #'channel_of_interest': ('combo', chans_v3, None),
390
+ #'pathogen_channel': ('combo', chans_v3, None),
389
391
  'timelapse_mode': ('combo', ['trackpy', 'btrack'], 'trackpy'),
390
392
  'train_mode': ('combo', ['erm', 'irm'], 'erm'),
391
393
  'clustering': ('combo', ['dbscan', 'kmean'], 'dbscan'),
@@ -462,10 +464,11 @@ def function_gui_wrapper(function=None, settings={}, q=None, fig_queue=None, imp
462
464
  finally:
463
465
  # Restore the original plt.show function
464
466
  plt.show = original_show
467
+
465
468
 
469
+
466
470
  def run_function_gui(settings_type, settings, q, fig_queue, stop_requested):
467
471
 
468
- from .gui_utils import process_stdout_stderr
469
472
  from .core import generate_image_umap, preprocess_generate_masks
470
473
  from .cellpose import identify_masks_finetune, check_cellpose_models, compare_cellpose_masks
471
474
  from .submodules import analyze_recruitment
@@ -476,9 +479,10 @@ def run_function_gui(settings_type, settings, q, fig_queue, stop_requested):
476
479
  from .sim import run_multiple_simulations
477
480
  from .deep_spacr import deep_spacr, apply_model_to_tar
478
481
  from .sequencing import generate_barecode_mapping
482
+
479
483
  process_stdout_stderr(q)
480
-
481
- print(f'run_function_gui settings_type: {settings_type}')
484
+
485
+ print(f'run_function_gui settings_type: {settings_type}')
482
486
 
483
487
  if settings_type == 'mask':
484
488
  function = preprocess_generate_masks
@@ -523,7 +527,7 @@ def run_function_gui(settings_type, settings, q, fig_queue, stop_requested):
523
527
  function = process_non_tif_non_2D_images
524
528
  imports = 1
525
529
  else:
526
- raise ValueError(f"Invalid settings type: {settings_type}")
530
+ raise ValueError(f"Error: Invalid settings type: {settings_type}")
527
531
  try:
528
532
  function_gui_wrapper(function, settings, q, fig_queue, imports)
529
533
  except Exception as e: