spacr 0.5.0__py3-none-any.whl → 0.9.1__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 (100) hide show
  1. spacr/__init__.py +0 -2
  2. spacr/__main__.py +3 -3
  3. spacr/core.py +13 -106
  4. spacr/gui_core.py +2 -77
  5. spacr/gui_utils.py +1 -13
  6. spacr/io.py +24 -25
  7. spacr/mediar.py +12 -8
  8. spacr/plot.py +50 -135
  9. spacr/settings.py +42 -30
  10. spacr/submodules.py +11 -1
  11. spacr/timelapse.py +7 -79
  12. spacr/utils.py +152 -61
  13. {spacr-0.5.0.dist-info → spacr-0.9.1.dist-info}/METADATA +62 -62
  14. spacr-0.9.1.dist-info/RECORD +109 -0
  15. {spacr-0.5.0.dist-info → spacr-0.9.1.dist-info}/WHEEL +1 -1
  16. spacr/resources/MEDIAR/.gitignore +0 -18
  17. spacr/resources/MEDIAR/LICENSE +0 -21
  18. spacr/resources/MEDIAR/README.md +0 -189
  19. spacr/resources/MEDIAR/SetupDict.py +0 -39
  20. spacr/resources/MEDIAR/__pycache__/SetupDict.cpython-39.pyc +0 -0
  21. spacr/resources/MEDIAR/__pycache__/evaluate.cpython-39.pyc +0 -0
  22. spacr/resources/MEDIAR/__pycache__/generate_mapping.cpython-39.pyc +0 -0
  23. spacr/resources/MEDIAR/__pycache__/main.cpython-39.pyc +0 -0
  24. spacr/resources/MEDIAR/config/baseline.json +0 -60
  25. spacr/resources/MEDIAR/config/mediar_example.json +0 -72
  26. spacr/resources/MEDIAR/config/pred/pred_mediar.json +0 -17
  27. spacr/resources/MEDIAR/config/step1_pretraining/phase1.json +0 -55
  28. spacr/resources/MEDIAR/config/step1_pretraining/phase2.json +0 -58
  29. spacr/resources/MEDIAR/config/step2_finetuning/finetuning1.json +0 -66
  30. spacr/resources/MEDIAR/config/step2_finetuning/finetuning2.json +0 -66
  31. spacr/resources/MEDIAR/config/step3_prediction/base_prediction.json +0 -16
  32. spacr/resources/MEDIAR/config/step3_prediction/ensemble_tta.json +0 -23
  33. spacr/resources/MEDIAR/core/BasePredictor.py +0 -120
  34. spacr/resources/MEDIAR/core/BaseTrainer.py +0 -240
  35. spacr/resources/MEDIAR/core/Baseline/Predictor.py +0 -59
  36. spacr/resources/MEDIAR/core/Baseline/Trainer.py +0 -113
  37. spacr/resources/MEDIAR/core/Baseline/__init__.py +0 -2
  38. spacr/resources/MEDIAR/core/Baseline/__pycache__/Predictor.cpython-39.pyc +0 -0
  39. spacr/resources/MEDIAR/core/Baseline/__pycache__/Trainer.cpython-39.pyc +0 -0
  40. spacr/resources/MEDIAR/core/Baseline/__pycache__/__init__.cpython-39.pyc +0 -0
  41. spacr/resources/MEDIAR/core/Baseline/__pycache__/utils.cpython-39.pyc +0 -0
  42. spacr/resources/MEDIAR/core/Baseline/utils.py +0 -80
  43. spacr/resources/MEDIAR/core/MEDIAR/EnsemblePredictor.py +0 -105
  44. spacr/resources/MEDIAR/core/MEDIAR/Predictor.py +0 -234
  45. spacr/resources/MEDIAR/core/MEDIAR/Trainer.py +0 -172
  46. spacr/resources/MEDIAR/core/MEDIAR/__init__.py +0 -3
  47. spacr/resources/MEDIAR/core/MEDIAR/__pycache__/EnsemblePredictor.cpython-39.pyc +0 -0
  48. spacr/resources/MEDIAR/core/MEDIAR/__pycache__/Predictor.cpython-39.pyc +0 -0
  49. spacr/resources/MEDIAR/core/MEDIAR/__pycache__/Trainer.cpython-39.pyc +0 -0
  50. spacr/resources/MEDIAR/core/MEDIAR/__pycache__/__init__.cpython-39.pyc +0 -0
  51. spacr/resources/MEDIAR/core/MEDIAR/__pycache__/utils.cpython-39.pyc +0 -0
  52. spacr/resources/MEDIAR/core/MEDIAR/utils.py +0 -429
  53. spacr/resources/MEDIAR/core/__init__.py +0 -2
  54. spacr/resources/MEDIAR/core/__pycache__/BasePredictor.cpython-39.pyc +0 -0
  55. spacr/resources/MEDIAR/core/__pycache__/BaseTrainer.cpython-39.pyc +0 -0
  56. spacr/resources/MEDIAR/core/__pycache__/__init__.cpython-39.pyc +0 -0
  57. spacr/resources/MEDIAR/core/__pycache__/utils.cpython-39.pyc +0 -0
  58. spacr/resources/MEDIAR/core/utils.py +0 -40
  59. spacr/resources/MEDIAR/evaluate.py +0 -71
  60. spacr/resources/MEDIAR/generate_mapping.py +0 -121
  61. spacr/resources/MEDIAR/image/examples/img1.tiff +0 -0
  62. spacr/resources/MEDIAR/image/examples/img2.tif +0 -0
  63. spacr/resources/MEDIAR/image/failure_cases.png +0 -0
  64. spacr/resources/MEDIAR/image/mediar_framework.png +0 -0
  65. spacr/resources/MEDIAR/image/mediar_model.PNG +0 -0
  66. spacr/resources/MEDIAR/image/mediar_results.png +0 -0
  67. spacr/resources/MEDIAR/main.py +0 -125
  68. spacr/resources/MEDIAR/predict.py +0 -70
  69. spacr/resources/MEDIAR/requirements.txt +0 -14
  70. spacr/resources/MEDIAR/train_tools/__init__.py +0 -3
  71. spacr/resources/MEDIAR/train_tools/__pycache__/__init__.cpython-39.pyc +0 -0
  72. spacr/resources/MEDIAR/train_tools/__pycache__/measures.cpython-39.pyc +0 -0
  73. spacr/resources/MEDIAR/train_tools/__pycache__/utils.cpython-39.pyc +0 -0
  74. spacr/resources/MEDIAR/train_tools/data_utils/__init__.py +0 -1
  75. spacr/resources/MEDIAR/train_tools/data_utils/__pycache__/__init__.cpython-39.pyc +0 -0
  76. spacr/resources/MEDIAR/train_tools/data_utils/__pycache__/datasetter.cpython-39.pyc +0 -0
  77. spacr/resources/MEDIAR/train_tools/data_utils/__pycache__/transforms.cpython-39.pyc +0 -0
  78. spacr/resources/MEDIAR/train_tools/data_utils/__pycache__/utils.cpython-39.pyc +0 -0
  79. spacr/resources/MEDIAR/train_tools/data_utils/custom/CellAware.py +0 -88
  80. spacr/resources/MEDIAR/train_tools/data_utils/custom/LoadImage.py +0 -161
  81. spacr/resources/MEDIAR/train_tools/data_utils/custom/NormalizeImage.py +0 -77
  82. spacr/resources/MEDIAR/train_tools/data_utils/custom/__init__.py +0 -3
  83. spacr/resources/MEDIAR/train_tools/data_utils/custom/__pycache__/CellAware.cpython-39.pyc +0 -0
  84. spacr/resources/MEDIAR/train_tools/data_utils/custom/__pycache__/LoadImage.cpython-39.pyc +0 -0
  85. spacr/resources/MEDIAR/train_tools/data_utils/custom/__pycache__/NormalizeImage.cpython-39.pyc +0 -0
  86. spacr/resources/MEDIAR/train_tools/data_utils/custom/__pycache__/__init__.cpython-39.pyc +0 -0
  87. spacr/resources/MEDIAR/train_tools/data_utils/custom/modalities.pkl +0 -0
  88. spacr/resources/MEDIAR/train_tools/data_utils/datasetter.py +0 -208
  89. spacr/resources/MEDIAR/train_tools/data_utils/transforms.py +0 -148
  90. spacr/resources/MEDIAR/train_tools/data_utils/utils.py +0 -84
  91. spacr/resources/MEDIAR/train_tools/measures.py +0 -200
  92. spacr/resources/MEDIAR/train_tools/models/MEDIARFormer.py +0 -102
  93. spacr/resources/MEDIAR/train_tools/models/__init__.py +0 -1
  94. spacr/resources/MEDIAR/train_tools/models/__pycache__/MEDIARFormer.cpython-39.pyc +0 -0
  95. spacr/resources/MEDIAR/train_tools/models/__pycache__/__init__.cpython-39.pyc +0 -0
  96. spacr/resources/MEDIAR/train_tools/utils.py +0 -70
  97. spacr-0.5.0.dist-info/RECORD +0 -190
  98. {spacr-0.5.0.dist-info → spacr-0.9.1.dist-info}/LICENSE +0 -0
  99. {spacr-0.5.0.dist-info → spacr-0.9.1.dist-info}/entry_points.txt +0 -0
  100. {spacr-0.5.0.dist-info → spacr-0.9.1.dist-info}/top_level.txt +0 -0
spacr/plot.py CHANGED
@@ -1241,103 +1241,6 @@ def _display_gif(path):
1241
1241
  """
1242
1242
  with open(path, 'rb') as file:
1243
1243
  display(ipyimage(file.read()))
1244
-
1245
- def _plot_recruitment_v2(df, df_type, channel_of_interest, columns=[], figuresize=10):
1246
- """
1247
- Plot recruitment data for different conditions and pathogens.
1248
-
1249
- Args:
1250
- df (DataFrame): The input DataFrame containing the recruitment data.
1251
- df_type (str): The type of DataFrame (e.g., 'train', 'test').
1252
- channel_of_interest (str): The channel of interest for plotting.
1253
- target (str): The target variable for plotting.
1254
- columns (list, optional): Additional columns to plot. Defaults to an empty list.
1255
- figuresize (int, optional): The size of the figure. Defaults to 50.
1256
-
1257
- Returns:
1258
- None
1259
- """
1260
-
1261
- color_list = [(55/255, 155/255, 155/255),
1262
- (155/255, 55/255, 155/255),
1263
- (55/255, 155/255, 255/255),
1264
- (255/255, 55/255, 155/255)]
1265
-
1266
- sns.set_palette(sns.color_palette(color_list))
1267
- font = figuresize/2
1268
- width=figuresize
1269
- height=figuresize/4
1270
-
1271
- # Create the subplots
1272
- fig, axes = plt.subplots(nrows=1, ncols=4, figsize=(width, height))
1273
-
1274
- # Plot for 'cell_channel' on axes[0]
1275
- plotter_cell = spacrGraph(df,grouping_column='condition', data_column=f'cell_channel_{channel_of_interest}_mean_intensity')
1276
- plotter_cell.create_plot(ax=axes[0])
1277
- axes[0].set_xlabel(f'pathogen {df_type}', fontsize=font)
1278
- axes[0].set_ylabel(f'cell_channel_{channel_of_interest}_mean_intensity', fontsize=font)
1279
-
1280
- # Plot for 'nucleus_channel' on axes[1]
1281
- plotter_nucleus = spacrGraph(df,grouping_column='condition', data_column=f'nucleus_channel_{channel_of_interest}_mean_intensity')
1282
- plotter_nucleus.create_plot(ax=axes[1])
1283
- axes[1].set_xlabel(f'pathogen {df_type}', fontsize=font)
1284
- axes[1].set_ylabel(f'nucleus_channel_{channel_of_interest}_mean_intensity', fontsize=font)
1285
-
1286
- # Plot for 'cytoplasm_channel' on axes[2]
1287
- plotter_cytoplasm = spacrGraph(df, grouping_column='condition', data_column=f'cytoplasm_channel_{channel_of_interest}_mean_intensity')
1288
- plotter_cytoplasm.create_plot(ax=axes[2])
1289
- axes[2].set_xlabel(f'pathogen {df_type}', fontsize=font)
1290
- axes[2].set_ylabel(f'cytoplasm_channel_{channel_of_interest}_mean_intensity', fontsize=font)
1291
-
1292
- # Plot for 'pathogen_channel' on axes[3]
1293
- plotter_pathogen = spacrGraph(df, grouping_column='condition', data_column=f'pathogen_channel_{channel_of_interest}_mean_intensity')
1294
- plotter_pathogen.create_plot(ax=axes[3])
1295
- axes[3].set_xlabel(f'pathogen {df_type}', fontsize=font)
1296
- axes[3].set_ylabel(f'pathogen_channel_{channel_of_interest}_mean_intensity', fontsize=font)
1297
-
1298
- #axes[0].legend_.remove()
1299
- #axes[1].legend_.remove()
1300
- #axes[2].legend_.remove()
1301
- #axes[3].legend_.remove()
1302
-
1303
- handles, labels = axes[3].get_legend_handles_labels()
1304
- axes[3].legend(handles, labels, bbox_to_anchor=(1.05, 0.5), loc='center left')
1305
- for i in [0,1,2,3]:
1306
- axes[i].tick_params(axis='both', which='major', labelsize=font)
1307
- axes[i].set_xticklabels(axes[i].get_xticklabels(), rotation=45)
1308
-
1309
- plt.tight_layout()
1310
- plt.show()
1311
-
1312
- columns = columns + ['pathogen_cytoplasm_mean_mean', 'pathogen_cytoplasm_q75_mean', 'pathogen_periphery_cytoplasm_mean_mean', 'pathogen_outside_cytoplasm_mean_mean', 'pathogen_outside_cytoplasm_q75_mean']
1313
- #columns = columns + [f'pathogen_slope_channel_{channel_of_interest}', f'pathogen_cell_distance_channel_{channel_of_interest}', f'nucleus_cell_distance_channel_{channel_of_interest}']
1314
-
1315
- width = figuresize*2
1316
- columns_per_row = math.ceil(len(columns) / 2)
1317
- height = (figuresize*2)/columns_per_row
1318
-
1319
- fig, axes = plt.subplots(nrows=2, ncols=columns_per_row, figsize=(width, height * 2))
1320
- axes = axes.flatten()
1321
-
1322
- print(f'{columns}')
1323
- for i, col in enumerate(columns):
1324
- ax = axes[i]
1325
- plotter_col = spacrGraph(df, grouping_column='condition', data_column=col)
1326
- plotter_col.create_plot(ax=ax)
1327
- ax.set_xlabel(f'pathogen {df_type}', fontsize=font)
1328
- ax.set_ylabel(f'{col}', fontsize=int(font * 2))
1329
- #ax.legend_.remove()
1330
- ax.tick_params(axis='both', which='major', labelsize=font)
1331
- ax.set_xticklabels(ax.get_xticklabels(), rotation=45)
1332
- if i <= 5:
1333
- ax.set_ylim(1, None)
1334
-
1335
- # Turn off any unused axes
1336
- for i in range(len(columns), len(axes)):
1337
- axes[i].axis('off')
1338
-
1339
- plt.tight_layout()
1340
- plt.show()
1341
1244
 
1342
1245
  def _plot_recruitment(df, df_type, channel_of_interest, columns=[], figuresize=10):
1343
1246
  """
@@ -1414,7 +1317,8 @@ def _plot_recruitment(df, df_type, channel_of_interest, columns=[], figuresize=1
1414
1317
  sns.barplot(ax=ax, data=df, x='condition', y=f'{col}', hue='pathogen', capsize=.1, ci='sd', dodge=False)
1415
1318
  ax.set_xlabel(f'pathogen {df_type}', fontsize=font)
1416
1319
  ax.set_ylabel(f'{col}', fontsize=int(font*2))
1417
- ax.legend_.remove()
1320
+ if ax.get_legend() is not None:
1321
+ ax.legend_.remove()
1418
1322
  ax.tick_params(axis='both', which='major', labelsize=font)
1419
1323
  ax.set_xticklabels(ax.get_xticklabels(), rotation=45)
1420
1324
  if i <= 5:
@@ -1842,31 +1746,6 @@ def print_mask_and_flows(stack, mask, flows, overlay=True, max_size=1000, thickn
1842
1746
  fig.tight_layout()
1843
1747
  plt.show()
1844
1748
 
1845
- def plot_resize_v1(images, resized_images, labels, resized_labels):
1846
- # Display an example image and label before and after resizing
1847
- fig, ax = plt.subplots(2, 2, figsize=(20, 20))
1848
-
1849
- # Check if the image is grayscale; if so, add a colormap and keep dimensions correct
1850
- if images[0].ndim == 2: # Grayscale image
1851
- ax[0, 0].imshow(images[0], cmap='gray')
1852
- else: # RGB or RGBA image
1853
- ax[0, 0].imshow(images[0])
1854
- ax[0, 0].set_title('Original Image')
1855
-
1856
- if resized_images[0].ndim == 2: # Grayscale image
1857
- ax[0, 1].imshow(resized_images[0], cmap='gray')
1858
- else: # RGB or RGBA image
1859
- ax[0, 1].imshow(resized_images[0])
1860
- ax[0, 1].set_title('Resized Image')
1861
-
1862
- # Assuming labels are always grayscale (most common scenario)
1863
- ax[1, 0].imshow(labels[0], cmap='gray')
1864
- ax[1, 0].set_title('Original Label')
1865
- ax[1, 1].imshow(resized_labels[0], cmap='gray')
1866
- ax[1, 1].set_title('Resized Label')
1867
- plt.show()
1868
-
1869
-
1870
1749
  def plot_resize(images, resized_images, labels, resized_labels):
1871
1750
  def prepare_image(img):
1872
1751
  if img.ndim == 2:
@@ -2031,7 +1910,7 @@ def plot_comparison_results(comparison_results):
2031
1910
  def plot_object_outlines(src, objects=['nucleus','cell','pathogen'], channels=[0,1,2], max_nr=10):
2032
1911
 
2033
1912
  for object_, channel in zip(objects, channels):
2034
- folders = [os.path.join(src, 'norm_channel_stack', f'{object_}_mask_stack'),
1913
+ folders = [os.path.join(src, 'masks', f'{object_}_mask_stack'),
2035
1914
  os.path.join(src,f'{channel+1}')]
2036
1915
  print(folders)
2037
1916
  plot_images_and_arrays(folders,
@@ -2597,7 +2476,7 @@ class spacrGraph:
2597
2476
  # Group by ['prc', grouping_column]
2598
2477
  group_cols = ['prc', self.grouping_column]
2599
2478
 
2600
- elif self.representation == 'plateID':
2479
+ elif self.representation == 'plate':
2601
2480
  # Make sure 'plateID' exists (split from 'prc' if needed)
2602
2481
  if 'plateID' not in df.columns:
2603
2482
  if 'prc' in df.columns:
@@ -2930,6 +2809,7 @@ class spacrGraph:
2930
2809
  self.df_melted = pd.melt(self.df, id_vars=[self.grouping_column], value_vars=self.data_column,var_name='Data Column', value_name='Value')
2931
2810
  unique_groups = self.df[self.grouping_column].unique()
2932
2811
  is_normal, normality_results = self.perform_normality_tests()
2812
+ is_normal = True
2933
2813
  levene_stat, levene_p = self.perform_levene_test(unique_groups)
2934
2814
  test_results = self.perform_statistical_tests(unique_groups, is_normal)
2935
2815
  posthoc_results = self.perform_posthoc_tests(is_normal, unique_groups)
@@ -3371,8 +3251,11 @@ class spacrGraph:
3371
3251
  return self.fig
3372
3252
 
3373
3253
  def plot_data_from_db(settings):
3254
+
3374
3255
  from .io import _read_db, _read_and_merge_data
3375
3256
  from .utils import annotate_conditions, save_settings
3257
+ from .settings import set_default_plot_data_from_db
3258
+
3376
3259
  """
3377
3260
  Extracts the specified table from the SQLite database and plots a specified column.
3378
3261
 
@@ -3385,8 +3268,8 @@ def plot_data_from_db(settings):
3385
3268
  df (pd.DataFrame): The extracted table as a DataFrame.
3386
3269
  """
3387
3270
 
3388
-
3389
-
3271
+ settings = set_default_plot_data_from_db(settings)
3272
+
3390
3273
  if isinstance(settings['src'], str):
3391
3274
  srcs = [settings['src']]
3392
3275
  elif isinstance(settings['src'], list):
@@ -3403,7 +3286,6 @@ def plot_data_from_db(settings):
3403
3286
 
3404
3287
  dfs = []
3405
3288
  for i, src in enumerate(srcs):
3406
-
3407
3289
  db_loc = os.path.join(src, 'measurements', settings['database'][i])
3408
3290
  print(f"Database: {db_loc}")
3409
3291
  if settings['table_names'] in ['saliency_image_correlations']:
@@ -3415,7 +3297,7 @@ def plot_data_from_db(settings):
3415
3297
  verbose=settings['verbose'],
3416
3298
  nuclei_limit=settings['nuclei_limit'],
3417
3299
  pathogen_limit=settings['pathogen_limit'])
3418
-
3300
+
3419
3301
  dft = annotate_conditions(df1,
3420
3302
  cells=settings['cell_types'],
3421
3303
  cell_loc=settings['cell_plate_metadata'],
@@ -3436,12 +3318,27 @@ def plot_data_from_db(settings):
3436
3318
 
3437
3319
  if settings['treatment_plate_metadata'] != None:
3438
3320
  df = df.dropna(subset='treatment')
3439
-
3321
+
3322
+ if settings['data_column'] == 'recruitment':
3323
+ pahtogen_measurement = df[f"pathogen_channel_{settings['channel_of_interest']}_mean_intensity"]
3324
+ cytoplasm_measurement = df[f"cytoplasm_channel_{settings['channel_of_interest']}_mean_intensity"]
3325
+ df['recruitment'] = pahtogen_measurement / cytoplasm_measurement
3326
+
3327
+ if settings['data_column'] not in df.columns:
3328
+ print(f"Data column {settings['data_column']} not found in DataFrame.")
3329
+ print(f'Please use one of the following columns:')
3330
+ for col in df.columns:
3331
+ print(col)
3332
+ display(df)
3333
+ return None
3334
+
3440
3335
  df = df.dropna(subset=settings['data_column'])
3441
3336
 
3442
3337
  if settings['grouping_column'] not in df.columns:
3443
3338
  print(f"Grouping column {settings['grouping_column']} not found in DataFrame.")
3444
- print(f'Please use one of the following columns: {df.columns}')
3339
+ print(f'Please use one of the following columns:')
3340
+ for col in df.columns:
3341
+ print(col)
3445
3342
  display(df)
3446
3343
  return None
3447
3344
 
@@ -3480,7 +3377,8 @@ def plot_data_from_db(settings):
3480
3377
 
3481
3378
  def plot_data_from_csv(settings):
3482
3379
  from .io import _read_db, _read_and_merge_data
3483
- from .utils import annotate_conditions, save_settings
3380
+ from .utils import annotate_conditions, save_settings, remove_outliers_by_group
3381
+ from .settings import get_plot_data_from_csv_default_settings
3484
3382
  """
3485
3383
  Extracts the specified table from the SQLite database and plots a specified column.
3486
3384
 
@@ -3492,7 +3390,12 @@ def plot_data_from_csv(settings):
3492
3390
  Returns:
3493
3391
  df (pd.DataFrame): The extracted table as a DataFrame.
3494
3392
  """
3393
+
3495
3394
 
3395
+ def filter_rows_by_column_values(df: pd.DataFrame, column: str, values: list) -> pd.DataFrame:
3396
+ """Return a filtered DataFrame where only rows with the column value in the list are kept."""
3397
+ return df[df[column].isin(values)].copy()
3398
+
3496
3399
  if isinstance(settings['src'], str):
3497
3400
  srcs = [settings['src']]
3498
3401
  elif isinstance(settings['src'], list):
@@ -3519,15 +3422,27 @@ def plot_data_from_csv(settings):
3519
3422
  except Exception as e:
3520
3423
  print(f"Could not split the prc column: {e}")
3521
3424
 
3522
-
3523
- display(df)
3524
-
3425
+ if 'keep_groups' in settings.keys():
3426
+ if isinstance(settings['keep_groups'], str):
3427
+ settings['keep_groups'] = [settings['keep_groups']]
3428
+ elif isinstance(settings['keep_groups'], list):
3429
+ df = filter_rows_by_column_values(df, settings['grouping_column'], settings['keep_groups'])
3430
+
3431
+ if settings['remove_outliers']:
3432
+ df = remove_outliers_by_group(df, settings['grouping_column'], settings['data_column'], method='iqr', threshold=1.5)
3433
+
3434
+ if settings['verbose']:
3435
+ display(df)
3436
+
3525
3437
  df = df.dropna(subset=settings['data_column'])
3526
3438
  df = df.dropna(subset=settings['grouping_column'])
3527
3439
  src = srcs[0]
3528
3440
  dst = os.path.join(os.path.dirname(src), 'results', settings['graph_name'])
3529
3441
  os.makedirs(dst, exist_ok=True)
3530
3442
 
3443
+ #data_csv = os.path.join(dst, f"{settings['graph_name']}_data.csv")
3444
+ #df.to_csv(data_csv, index=False)
3445
+
3531
3446
  spacr_graph = spacrGraph(
3532
3447
  df=df, # Your DataFrame
3533
3448
  grouping_column=settings['grouping_column'], # Column for grouping the data (x-axis)
spacr/settings.py CHANGED
@@ -29,7 +29,6 @@ def set_default_settings_preprocess_generate_masks(settings={}):
29
29
  settings.setdefault('denoise', False)
30
30
  settings.setdefault('src', 'path')
31
31
  settings.setdefault('delete_intermediate', False)
32
- settings.setdefault('segmentation_mode', 'cellpose')
33
32
  settings.setdefault('preprocess', True)
34
33
  settings.setdefault('masks', True)
35
34
  settings.setdefault('save', True)
@@ -100,30 +99,30 @@ def set_default_settings_preprocess_generate_masks(settings={}):
100
99
  settings.setdefault('adjust_cells', False)
101
100
  return settings
102
101
 
103
- def set_default_settings_preprocess_img_data_v1(settings):
104
-
105
- metadata_type = settings.setdefault('metadata_type', 'cellvoyager')
106
- custom_regex = settings.setdefault('custom_regex', None)
107
- nr = settings.setdefault('nr', 1)
108
- plot = settings.setdefault('plot', True)
109
- batch_size = settings.setdefault('batch_size', 50)
110
- timelapse = settings.setdefault('timelapse', False)
111
- lower_percentile = settings.setdefault('lower_percentile', 2)
112
- randomize = settings.setdefault('randomize', True)
113
- all_to_mip = settings.setdefault('all_to_mip', False)
114
- pick_slice = settings.setdefault('pick_slice', False)
115
- skip_mode = settings.setdefault('skip_mode', False)
116
-
117
- cmap = settings.setdefault('cmap', 'inferno')
118
- figuresize = settings.setdefault('figuresize', 10)
119
- normalize = settings.setdefault('normalize', True)
120
- save_dtype = settings.setdefault('save_dtype', 'uint16')
121
-
122
- test_mode = settings.setdefault('test_mode', False)
123
- test_images = settings.setdefault('test_images', 10)
124
- random_test = settings.setdefault('random_test', True)
125
-
126
- return settings, metadata_type, custom_regex, nr, plot, batch_size, timelapse, lower_percentile, randomize, all_to_mip, pick_slice, skip_mode, cmap, figuresize, normalize, save_dtype, test_mode, test_images, random_test
102
+ def set_default_plot_data_from_db(settings):
103
+ settings.setdefault('src', 'path')
104
+ settings.setdefault('database', 'measurements.db')
105
+ settings.setdefault('graph_name', 'Figure_1')
106
+ settings.setdefault('table_names', ['cell', 'cytoplasm', 'nucleus', 'pathogen'])
107
+ settings.setdefault('data_column', 'recruitment')
108
+ settings.setdefault('grouping_column', 'condition')
109
+ settings.setdefault('cell_types', ['Hela'])
110
+ settings.setdefault('cell_plate_metadata', None)
111
+ settings.setdefault('pathogen_types', None)
112
+ settings.setdefault('pathogen_plate_metadata', None)
113
+ settings.setdefault('treatments', None)
114
+ settings.setdefault('treatment_plate_metadata', None)
115
+ settings.setdefault('graph_type', 'jitter')
116
+ settings.setdefault('theme', 'deep')
117
+ settings.setdefault('save', True)
118
+ settings.setdefault('y_lim', [1,1.5])
119
+ settings.setdefault('verbose', False)
120
+ settings.setdefault('channel_of_interest', 1)
121
+ settings.setdefault('nuclei_limit', 2)
122
+ settings.setdefault('pathogen_limit', 3)
123
+ settings.setdefault('representation', 'well')
124
+ settings.setdefault('uninfected', False)
125
+ return settings
127
126
 
128
127
  def set_default_settings_preprocess_img_data(settings):
129
128
 
@@ -955,7 +954,6 @@ expected_types = {
955
954
  "png_type":str,
956
955
  "custom_model_path":str,
957
956
  "generate_training_dataset":bool,
958
- "segmentation_mode":str,
959
957
  "train_DL_model":bool,
960
958
  "normalize":bool,
961
959
  "overlay":bool,
@@ -1006,7 +1004,7 @@ expected_types = {
1006
1004
  }
1007
1005
 
1008
1006
  categories = {"Paths":[ "src", "grna", "barcodes", "custom_model_path", "dataset","model_path","grna_csv","row_csv","column_csv", "metadata_files", "score_data","count_data"],
1009
- "General": ["cell_mask_dim", "cytoplasm", "cell_chann_dim", "cell_channel", "nucleus_chann_dim", "nucleus_channel", "nucleus_mask_dim", "pathogen_mask_dim", "pathogen_chann_dim", "pathogen_channel", "test_mode", "plot", "metadata_type", "custom_regex", "experiment", "channels", "magnification", "channel_dims", "apply_model_to_dataset", "generate_training_dataset", "train_DL_model", "segmentation_mode", "delete_intermediate", "uninfected", ],
1007
+ "General": ["cell_mask_dim", "cytoplasm", "cell_chann_dim", "cell_channel", "nucleus_chann_dim", "nucleus_channel", "nucleus_mask_dim", "pathogen_mask_dim", "pathogen_chann_dim", "pathogen_channel", "test_mode", "plot", "metadata_type", "custom_regex", "experiment", "channels", "magnification", "channel_dims", "apply_model_to_dataset", "generate_training_dataset", "train_DL_model", "delete_intermediate", "uninfected", ],
1010
1008
  "Cellpose":["denoise","fill_in","from_scratch", "n_epochs", "width_height", "model_name", "custom_model", "resample", "rescale", "CP_prob", "flow_threshold", "percentiles", "invert", "diameter", "grayscale", "Signal_to_noise", "resize", "target_height", "target_width"],
1011
1009
  "Cell": ["cell_diamiter","cell_intensity_range", "cell_size_range", "cell_background", "cell_Signal_to_noise", "cell_CP_prob", "cell_FT", "remove_background_cell", "cell_min_size", "cytoplasm_min_size", "adjust_cells", "cells", "cell_loc"],
1012
1010
  "Nucleus": ["nucleus_diamiter","nucleus_intensity_range", "nucleus_size_range", "nucleus_background", "nucleus_Signal_to_noise", "nucleus_CP_prob", "nucleus_FT", "remove_background_nucleus", "nucleus_min_size", "nucleus_loc"],
@@ -1217,7 +1215,7 @@ def generate_fields(variables, scrollable_frame):
1217
1215
  "nucleus_min_size": "(int) - The minimum size of nucleus objects in pixels^2.",
1218
1216
  "normalize_by": "(str) - Normalize cropped png images by png or by field of view.",
1219
1217
  "dependent_variable": "(str) - The dependent variable for the regression analysis.",
1220
- "delete_intermediate": "(bool) - Delete intermediate folders (stack, channel, norm_channel_stack).",
1218
+ "delete_intermediate": "(bool) - Delete intermediate folders (stack, channel, masks).",
1221
1219
  "diameter": "(float) - Diameter of the objects to segment.",
1222
1220
  "dialate_png_ratios": "(list) - The ratios to use for dilating the PNG images. This will determine the amount of dilation applied to the images before cropping.",
1223
1221
  "dialate_pngs": "(bool) - Whether to dilate the PNG images before saving.",
@@ -1337,7 +1335,6 @@ def generate_fields(variables, scrollable_frame):
1337
1335
  "skip_mode": "(str) - The mode to use for skipping images. This will determine how to handle images that cannot be processed.",
1338
1336
  "smooth_lines": "(bool) - Whether to smooth lines in the plots.",
1339
1337
  "src": "(str, path) - Path to source directory.",
1340
- "segmentation_mode": "(str) - Algorithm to use for segmentation (cellpose or mediar).",
1341
1338
  "target": "(str) - Target variable for the analysis.",
1342
1339
  "target_height": "(int) - Target height for resizing the images.",
1343
1340
  "target_intensity_min": "(float) - Minimum intensity for the target objects.",
@@ -1376,7 +1373,6 @@ def generate_fields(variables, scrollable_frame):
1376
1373
  "dataset_mode": "str - How to generate train/test dataset.",
1377
1374
  "annotated_classes": "list - list of numbers in annotation column.",
1378
1375
  "um_per_pixel": "(float) - The micrometers per pixel for the images.",
1379
- "segmentation_model": "(str) - The segmentation model to use, either cellpose or mediar.",
1380
1376
  "pathogen_model": "(str) - use a custom cellpose model to detect pathogen objects.",
1381
1377
  "timelapse_displacement": "(int) - Displacement for timelapse tracking.",
1382
1378
  "timelapse_memory": "(int) - Memory for timelapse tracking.",
@@ -1596,4 +1592,20 @@ def set_analyze_class_proportion_defaults(settings):
1596
1592
  settings.setdefault('level','well')
1597
1593
  settings.setdefault('save',False)
1598
1594
  settings.setdefault('verbose', False)
1595
+ return settings
1596
+
1597
+ def get_plot_data_from_csv_default_settings(settings):
1598
+ settings.setdefault('src','path')
1599
+ settings.setdefault('data_column','choose column')
1600
+ settings.setdefault('grouping_column','choose column')
1601
+ settings.setdefault('graph_type','violin')
1602
+ settings.setdefault('save',False)
1603
+ settings.setdefault('y_lim',None)
1604
+ settings.setdefault('log_y',False)
1605
+ settings.setdefault('log_x',False)
1606
+ settings.setdefault('keep_groups',None)
1607
+ settings.setdefault('representation','well')
1608
+ settings.setdefault('theme','dark')
1609
+ settings.setdefault('remove_outliers',False)
1610
+ settings.setdefault('verbose',False)
1599
1611
  return settings
spacr/submodules.py CHANGED
@@ -1,5 +1,5 @@
1
1
  import seaborn as sns
2
- import os, random, sqlite3, re, shap, string, time
2
+ import os, random, sqlite3, re, shap, string, time, shutil
3
3
  import pandas as pd
4
4
  import numpy as np
5
5
 
@@ -580,6 +580,16 @@ def analyze_recruitment(settings):
580
580
  from .settings import get_analyze_recruitment_default_settings
581
581
 
582
582
  settings = get_analyze_recruitment_default_settings(settings=settings)
583
+
584
+ if settings['src'].endswith('/measurements.db'):
585
+ src_orig = settings['src']
586
+ settings['src'] = os.path.dirname(settings['src'])
587
+ if not settings['src'].endswith('/measurements'):
588
+ src_mes = os.path.join(settings['src'], 'measurements')
589
+ if not os.path.exists(src_mes):
590
+ os.makedirs(src_mes)
591
+ shutil.move(src_orig, os.path.join(src_mes, 'measurements.db'))
592
+
583
593
  save_settings(settings, name='recruitment')
584
594
 
585
595
  print(f"Cell(s): {settings['cell_types']}, in {settings['cell_plate_metadata']}")
spacr/timelapse.py CHANGED
@@ -255,57 +255,25 @@ def _relabel_masks_based_on_tracks(masks, tracks, mode='btrack'):
255
255
 
256
256
  return relabeled_masks
257
257
 
258
- def _prepare_for_tracking_v1(mask_array):
259
- """
260
- Prepare the mask array for object tracking.
261
-
262
- Args:
263
- mask_array (ndarray): Array of binary masks representing objects.
264
-
265
- Returns:
266
- DataFrame: DataFrame containing information about each object in the mask array.
267
- The DataFrame has the following columns:
268
- - frame: The frame number.
269
- - y: The y-coordinate of the object's centroid.
270
- - x: The x-coordinate of the object's centroid.
271
- - mass: The area of the object.
272
- - original_label: The original label of the object.
273
-
274
- """
275
- frames = []
276
- for t, frame in enumerate(mask_array):
277
- props = regionprops(frame)
278
- for obj in props:
279
- # Include 'label' in the dictionary to capture the original label of the object
280
- frames.append({
281
- 'frame': t,
282
- 'y': obj.centroid[0],
283
- 'x': obj.centroid[1],
284
- 'mass': obj.area,
285
- 'original_label': obj.label # Capture the original label
286
- })
287
- return pd.DataFrame(frames)
288
-
289
258
  def _prepare_for_tracking(mask_array):
290
259
  frames = []
291
260
  for t, frame in enumerate(mask_array):
292
261
  props = regionprops_table(
293
262
  frame,
294
- properties=('label', 'centroid-0', 'centroid-1', 'area',
295
- 'bbox-0', 'bbox-1', 'bbox-2', 'bbox-3',
296
- 'eccentricity')
263
+ properties=('label', 'centroid', 'area', 'bbox', 'eccentricity')
297
264
  )
298
265
  df = pd.DataFrame(props)
299
266
  df = df.rename(columns={
300
- 'centroid-0': 'y', 'centroid-1': 'x', 'area': 'mass',
301
- 'label': 'original_label'
267
+ 'centroid-0': 'y',
268
+ 'centroid-1': 'x',
269
+ 'area': 'mass',
270
+ 'label': 'original_label'
302
271
  })
303
272
  df['frame'] = t
304
273
  frames.append(df[['frame','y','x','mass','original_label',
305
274
  'bbox-0','bbox-1','bbox-2','bbox-3','eccentricity']])
306
275
  return pd.concat(frames, ignore_index=True)
307
276
 
308
-
309
277
  def _track_by_iou(masks, iou_threshold=0.1):
310
278
  """
311
279
  Build a track table by linking masks frame→frame via IoU.
@@ -504,47 +472,7 @@ def _facilitate_trackin_with_adaptive_removal(masks, search_range=None, max_atte
504
472
  f"Failed to track after {max_attempts} attempts; last search_range={search_range}"
505
473
  )
506
474
 
507
- def _facilitate_trackin_with_adaptive_removal_v1(masks, search_range=500, max_attempts=100, memory=3):
508
- """
509
- Facilitates object tracking with adaptive removal.
510
-
511
- Args:
512
- masks (numpy.ndarray): Array of binary masks representing objects in each frame.
513
- search_range (int, optional): Maximum distance objects can move between frames. Defaults to 500.
514
- max_attempts (int, optional): Maximum number of attempts to track objects. Defaults to 100.
515
- memory (int, optional): Number of frames to remember when linking tracks. Defaults to 3.
516
-
517
- Returns:
518
- tuple: A tuple containing the updated masks, features, and tracks_df.
519
- masks (numpy.ndarray): Updated array of binary masks.
520
- features (pandas.DataFrame): DataFrame containing features for object tracking.
521
- tracks_df (pandas.DataFrame): DataFrame containing the tracked object trajectories.
522
-
523
- Raises:
524
- Exception: If tracking fails after the maximum number of attempts.
525
-
526
- """
527
- attempts = 0
528
- first_frame = masks[0]
529
- starting_objects = np.unique(first_frame[first_frame != 0])
530
- while attempts < max_attempts:
531
- try:
532
- masks = _remove_objects_from_first_frame(masks, 10)
533
- first_frame = masks[0]
534
- objects = np.unique(first_frame[first_frame != 0])
535
- print(len(objects))
536
- features = _prepare_for_tracking(masks)
537
- tracks_df = tp.link(features, search_range=search_range, memory=memory)
538
- print(f"Success with {len(objects)} objects, started with {len(starting_objects)} objects")
539
- return masks, features, tracks_df
540
- except Exception as e: # Consider catching a more specific exception if possible
541
- print(f"Retrying with fewer objects. Exception: {e}", flush=True)
542
- finally:
543
- attempts += 1
544
- print(f"Failed to track objects after {max_attempts} attempts. Consider adjusting parameters.")
545
- return None, None, None
546
-
547
- def _trackpy_track_cells(src, name, batch_filenames, object_type, masks, timelapse_displacement, timelapse_memory, timelapse_remove_transient, plot, save, mode):
475
+ def _trackpy_track_cells(src, name, batch_filenames, object_type, masks, timelapse_displacement, timelapse_memory, timelapse_remove_transient, plot, save, mode, track_by_iou):
548
476
  """
549
477
  Track cells using the Trackpy library.
550
478
 
@@ -577,7 +505,7 @@ def _trackpy_track_cells(src, name, batch_filenames, object_type, masks, timelap
577
505
  if timelapse_displacement is None:
578
506
  timelapse_displacement = 50
579
507
 
580
- masks, features, tracks_df = _facilitate_trackin_with_adaptive_removal(masks, search_range=timelapse_displacement, max_attempts=100, memory=timelapse_memory)
508
+ masks, features, tracks_df = _facilitate_trackin_with_adaptive_removal(masks, search_range=timelapse_displacement, max_attempts=100, memory=timelapse_memory, track_by_iou=track_by_iou)
581
509
 
582
510
  tracks_df['particle'] += 1
583
511