spacr 0.4.15__py3-none-any.whl → 0.5.0__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.
Files changed (54) hide show
  1. spacr/__init__.py +2 -2
  2. spacr/core.py +52 -10
  3. spacr/deep_spacr.py +2 -3
  4. spacr/gui.py +0 -1
  5. spacr/gui_core.py +247 -41
  6. spacr/gui_elements.py +133 -2
  7. spacr/gui_utils.py +22 -17
  8. spacr/io.py +624 -149
  9. spacr/ml.py +141 -258
  10. spacr/plot.py +76 -34
  11. spacr/resources/MEDIAR/__pycache__/SetupDict.cpython-39.pyc +0 -0
  12. spacr/resources/MEDIAR/__pycache__/evaluate.cpython-39.pyc +0 -0
  13. spacr/resources/MEDIAR/__pycache__/generate_mapping.cpython-39.pyc +0 -0
  14. spacr/resources/MEDIAR/__pycache__/main.cpython-39.pyc +0 -0
  15. spacr/resources/MEDIAR/core/Baseline/__pycache__/Predictor.cpython-39.pyc +0 -0
  16. spacr/resources/MEDIAR/core/Baseline/__pycache__/Trainer.cpython-39.pyc +0 -0
  17. spacr/resources/MEDIAR/core/Baseline/__pycache__/__init__.cpython-39.pyc +0 -0
  18. spacr/resources/MEDIAR/core/Baseline/__pycache__/utils.cpython-39.pyc +0 -0
  19. spacr/resources/MEDIAR/core/MEDIAR/__pycache__/EnsemblePredictor.cpython-39.pyc +0 -0
  20. spacr/resources/MEDIAR/core/MEDIAR/__pycache__/Predictor.cpython-39.pyc +0 -0
  21. spacr/resources/MEDIAR/core/MEDIAR/__pycache__/Trainer.cpython-39.pyc +0 -0
  22. spacr/resources/MEDIAR/core/MEDIAR/__pycache__/__init__.cpython-39.pyc +0 -0
  23. spacr/resources/MEDIAR/core/MEDIAR/__pycache__/utils.cpython-39.pyc +0 -0
  24. spacr/resources/MEDIAR/core/__pycache__/BasePredictor.cpython-39.pyc +0 -0
  25. spacr/resources/MEDIAR/core/__pycache__/BaseTrainer.cpython-39.pyc +0 -0
  26. spacr/resources/MEDIAR/core/__pycache__/__init__.cpython-39.pyc +0 -0
  27. spacr/resources/MEDIAR/core/__pycache__/utils.cpython-39.pyc +0 -0
  28. spacr/resources/MEDIAR/train_tools/__pycache__/__init__.cpython-39.pyc +0 -0
  29. spacr/resources/MEDIAR/train_tools/__pycache__/measures.cpython-39.pyc +0 -0
  30. spacr/resources/MEDIAR/train_tools/__pycache__/utils.cpython-39.pyc +0 -0
  31. spacr/resources/MEDIAR/train_tools/data_utils/__pycache__/__init__.cpython-39.pyc +0 -0
  32. spacr/resources/MEDIAR/train_tools/data_utils/__pycache__/datasetter.cpython-39.pyc +0 -0
  33. spacr/resources/MEDIAR/train_tools/data_utils/__pycache__/transforms.cpython-39.pyc +0 -0
  34. spacr/resources/MEDIAR/train_tools/data_utils/__pycache__/utils.cpython-39.pyc +0 -0
  35. spacr/resources/MEDIAR/train_tools/data_utils/custom/__pycache__/CellAware.cpython-39.pyc +0 -0
  36. spacr/resources/MEDIAR/train_tools/data_utils/custom/__pycache__/LoadImage.cpython-39.pyc +0 -0
  37. spacr/resources/MEDIAR/train_tools/data_utils/custom/__pycache__/NormalizeImage.cpython-39.pyc +0 -0
  38. spacr/resources/MEDIAR/train_tools/data_utils/custom/__pycache__/__init__.cpython-39.pyc +0 -0
  39. spacr/resources/MEDIAR/train_tools/models/__pycache__/MEDIARFormer.cpython-39.pyc +0 -0
  40. spacr/resources/MEDIAR/train_tools/models/__pycache__/__init__.cpython-39.pyc +0 -0
  41. spacr/sequencing.py +73 -38
  42. spacr/settings.py +161 -135
  43. spacr/submodules.py +618 -215
  44. spacr/timelapse.py +197 -29
  45. spacr/toxo.py +23 -23
  46. spacr/utils.py +186 -128
  47. {spacr-0.4.15.dist-info → spacr-0.5.0.dist-info}/METADATA +5 -2
  48. {spacr-0.4.15.dist-info → spacr-0.5.0.dist-info}/RECORD +53 -24
  49. spacr/stats.py +0 -221
  50. /spacr/{cellpose.py → spacr_cellpose.py} +0 -0
  51. {spacr-0.4.15.dist-info → spacr-0.5.0.dist-info}/LICENSE +0 -0
  52. {spacr-0.4.15.dist-info → spacr-0.5.0.dist-info}/WHEEL +0 -0
  53. {spacr-0.4.15.dist-info → spacr-0.5.0.dist-info}/entry_points.txt +0 -0
  54. {spacr-0.4.15.dist-info → spacr-0.5.0.dist-info}/top_level.txt +0 -0
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
@@ -370,31 +370,32 @@ def convert_settings_dict_for_gui(settings):
370
370
  chans_v4 = [0, 1, 2, 3, None]
371
371
  variables = {}
372
372
  special_cases = {
373
- 'metadata_type': ('combo', ['cellvoyager', 'cq1', 'nikon', 'zeis', 'custom'], 'cellvoyager'),
373
+ 'metadata_type': ('combo', ['cellvoyager', 'cq1', 'auto', 'custom'], 'cellvoyager'),
374
374
  'channels': ('combo', chan_list, '[0,1,2,3]'),
375
375
  'train_channels': ('combo', ["['r','g','b']", "['r','g']", "['r','b']", "['g','b']", "['r']", "['g']", "['b']"], "['r','g','b']"),
376
376
  'channel_dims': ('combo', chan_list, '[0,1,2,3]'),
377
377
  'dataset_mode': ('combo', ['annotation', 'metadata', 'recruitment'], 'metadata'),
378
378
  'cov_type': ('combo', ['HC0', 'HC1', 'HC2', 'HC3', None], None),
379
- 'cell_mask_dim': ('combo', chans, None),
380
- 'cell_chann_dim': ('combo', chans, None),
381
- 'nucleus_mask_dim': ('combo', chans, None),
382
- 'nucleus_chann_dim': ('combo', chans, None),
383
- 'pathogen_mask_dim': ('combo', chans, None),
384
- 'pathogen_chann_dim': ('combo', chans, 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
385
  'crop_mode': ('combo', ["['cell']", "['nucleus']", "['pathogen']", "['cell', 'nucleus']", "['cell', 'pathogen']", "['nucleus', 'pathogen']", "['cell', 'nucleus', 'pathogen']"], "['cell']"),
386
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),
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),
391
391
  'timelapse_mode': ('combo', ['trackpy', 'btrack'], 'trackpy'),
392
392
  'train_mode': ('combo', ['erm', 'irm'], 'erm'),
393
393
  'clustering': ('combo', ['dbscan', 'kmean'], 'dbscan'),
394
394
  'reduction_method': ('combo', ['umap', 'tsne'], 'umap'),
395
395
  'model_name': ('combo', ['cyto', 'cyto_2', 'cyto_3', 'nuclei'], 'cyto'),
396
396
  'regression_type': ('combo', ['ols','gls','wls','rlm','glm','mixed','quantile','logit','probit','poisson','lasso','ridge'], 'ols'),
397
- 'timelapse_objects': ('combo', ['cell', 'nucleus', 'pathogen', 'cytoplasm', None], None),
397
+ 'timelapse_objects': ('combo', ["['cell']", "['nucleus']", "['pathogen']", "['cell', 'nucleus']", "['cell', 'pathogen']", "['nucleus', 'pathogen']", "['cell', 'nucleus', 'pathogen']", None], None),
398
+ #'timelapse_objects': ('combo', '[cell]', '[nucleus]', '[pathogen]', '[cytoplasm]', None, None),
398
399
  'model_type': ('combo', torchvision_models, 'resnet50'),
399
400
  'optimizer_type': ('combo', ['adamw', 'adam'], 'adamw'),
400
401
  'schedule': ('combo', ['reduce_lr_on_plateau', 'step_lr'], 'reduce_lr_on_plateau'),
@@ -464,12 +465,13 @@ def function_gui_wrapper(function=None, settings={}, q=None, fig_queue=None, imp
464
465
  finally:
465
466
  # Restore the original plt.show function
466
467
  plt.show = original_show
468
+
467
469
 
470
+
468
471
  def run_function_gui(settings_type, settings, q, fig_queue, stop_requested):
469
472
 
470
- from .gui_utils import process_stdout_stderr
471
473
  from .core import generate_image_umap, preprocess_generate_masks
472
- from .cellpose import identify_masks_finetune, check_cellpose_models, compare_cellpose_masks
474
+ from .spacr_cellpose import identify_masks_finetune, check_cellpose_models, compare_cellpose_masks
473
475
  from .submodules import analyze_recruitment
474
476
  from .ml import generate_ml_scores, perform_regression
475
477
  from .submodules import train_cellpose, analyze_plaques
@@ -478,9 +480,10 @@ def run_function_gui(settings_type, settings, q, fig_queue, stop_requested):
478
480
  from .sim import run_multiple_simulations
479
481
  from .deep_spacr import deep_spacr, apply_model_to_tar
480
482
  from .sequencing import generate_barecode_mapping
483
+
481
484
  process_stdout_stderr(q)
482
-
483
- print(f'run_function_gui settings_type: {settings_type}')
485
+
486
+ print(f'run_function_gui settings_type: {settings_type}')
484
487
 
485
488
  if settings_type == 'mask':
486
489
  function = preprocess_generate_masks
@@ -525,7 +528,7 @@ def run_function_gui(settings_type, settings, q, fig_queue, stop_requested):
525
528
  function = process_non_tif_non_2D_images
526
529
  imports = 1
527
530
  else:
528
- raise ValueError(f"Invalid settings type: {settings_type}")
531
+ raise ValueError(f"Error: Invalid settings type: {settings_type}")
529
532
  try:
530
533
  function_gui_wrapper(function, settings, q, fig_queue, imports)
531
534
  except Exception as e:
@@ -937,8 +940,10 @@ def convert_to_number(value):
937
940
 
938
941
  """
939
942
  Converts a string value to an integer if possible, otherwise converts to a float.
943
+
940
944
  Args:
941
945
  value (str): The string representation of the number.
946
+
942
947
  Returns:
943
948
  int or float: The converted number.
944
949
  """