spacr 0.4.0__py3-none-any.whl → 0.4.2__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/utils.py CHANGED
@@ -319,7 +319,6 @@ def load_settings(csv_file_path, show=False, setting_key='setting_key', setting_
319
319
 
320
320
  return result_dict
321
321
 
322
-
323
322
  def save_settings(settings, name='settings', show=False):
324
323
 
325
324
  settings_df = pd.DataFrame(list(settings.items()), columns=['Key', 'Value'])
@@ -328,14 +327,19 @@ def save_settings(settings, name='settings', show=False):
328
327
 
329
328
  if isinstance(settings['src'], list):
330
329
  src = settings['src'][0]
331
- #if os.path.exists(src):
332
-
333
330
  name = f"{name}_list"
334
331
  else:
335
332
  src = settings['src']
333
+
334
+ if 'test_mode' in settings.keys():
335
+ settings['test_mode'] = False
336
+
337
+ if 'plot' in settings.keys():
338
+ settings['plot'] = False
336
339
 
337
340
  settings_csv = os.path.join(src,'settings',f'{name}.csv')
338
341
  os.makedirs(os.path.join(src,'settings'), exist_ok=True)
342
+ print(f"Saving settings to {settings_csv}")
339
343
  settings_df.to_csv(settings_csv, index=False)
340
344
 
341
345
  def print_progress(files_processed, files_to_process, n_jobs, time_ls=None, batch_size=None, operation_type=""):
@@ -1145,7 +1149,7 @@ def _masks_to_masks_stack(masks):
1145
1149
  mask_stack.append(mask)
1146
1150
  return mask_stack
1147
1151
 
1148
- def _get_diam(mag, obj):
1152
+ def _get_diam_v1(mag, obj):
1149
1153
 
1150
1154
  if mag == 20:
1151
1155
  if obj == 'cell':
@@ -1176,11 +1180,28 @@ def _get_diam(mag, obj):
1176
1180
  diamiter = 60
1177
1181
  else:
1178
1182
  raise ValueError("Invalid magnification: Use 20, 40 or 60")
1183
+
1179
1184
  else:
1180
1185
  raise ValueError("Invalid magnification: Use 20, 40 or 60")
1181
1186
 
1182
1187
  return diamiter
1183
1188
 
1189
+ def _get_diam(mag, obj):
1190
+
1191
+ if obj == 'cell':
1192
+ diamiter = 2 * mag + 80
1193
+
1194
+ if obj == 'cell_large':
1195
+ diamiter = 2 * mag + 120
1196
+
1197
+ if obj == 'nucleus':
1198
+ diamiter = 0.75 * mag + 45
1199
+
1200
+ if obj == 'pathogen':
1201
+ diamiter = mag
1202
+
1203
+ return int(diamiter)
1204
+
1184
1205
  def _get_object_settings(object_type, settings):
1185
1206
  object_settings = {}
1186
1207
 
@@ -1333,20 +1354,25 @@ def annotate_conditions(df, cells=None, cell_loc=None, pathogens=None, pathogen_
1333
1354
  def _map_or_default(column_name, values, loc, df):
1334
1355
  """
1335
1356
  Consolidates the logic for mapping values or assigning defaults when loc is None.
1336
-
1357
+
1337
1358
  Args:
1338
1359
  column_name (str): The column in the DataFrame to annotate.
1339
1360
  values (list/str): The list of values or a single string to annotate.
1340
1361
  loc (list of lists): Location mapping for the values, or None if not used.
1341
1362
  df (pandas.DataFrame): The DataFrame to modify.
1342
1363
  """
1343
- if isinstance(values, str) or (isinstance(values, list) and loc is None):
1344
- # Assign all rows the first value in the list or the single string
1345
- df[column_name] = values if isinstance(values, str) else values[0]
1364
+ if isinstance(values, str) and loc is None:
1365
+ # If a single string is provided and loc is None, assign the value to all rows
1366
+ df[column_name] = values
1367
+
1368
+ elif isinstance(values, list) and loc is None:
1369
+ # If a list of values is provided but no loc, assign the first value to all rows
1370
+ df[column_name] = values[0]
1371
+
1346
1372
  elif values is not None and loc is not None:
1347
- # Perform the location-based mapping
1373
+ # Perform location-based mapping
1348
1374
  value_dict = {val: key for key, loc_list in zip(values, loc) for val in loc_list}
1349
- df[column_name] = np.nan
1375
+ df[column_name] = np.nan # Start with NaN
1350
1376
  for val, key in value_dict.items():
1351
1377
  loc_type = _get_type(val)
1352
1378
  if loc_type:
@@ -3099,12 +3125,8 @@ def _get_regex(metadata_type, img_format, custom_regex=None):
3099
3125
  regex = f'(?P<plateID>.*)_(?P<wellID>.*)_T(?P<timeID>.*)F(?P<fieldID>.*)L(?P<laserID>..)A(?P<AID>..)Z(?P<sliceID>.*)C(?P<chanID>.*){img_format}'
3100
3126
  elif metadata_type == 'cq1':
3101
3127
  regex = f'W(?P<wellID>.*)F(?P<fieldID>.*)T(?P<timeID>.*)Z(?P<sliceID>.*)C(?P<chanID>.*){img_format}'
3102
- elif metadata_type == 'nikon':
3103
- regex = f'(?P<plateID>.*)_(?P<wellID>.*)_T(?P<timeID>.*)F(?P<fieldID>.*)L(?P<laserID>..)A(?P<AID>..)Z(?P<sliceID>.*)C(?P<chanID>.*){img_format}'
3104
- elif metadata_type == 'zeis':
3105
- regex = f'(?P<plateID>.*)_(?P<wellID>.*)_T(?P<timeID>.*)F(?P<fieldID>.*)L(?P<laserID>..)A(?P<AID>..)Z(?P<sliceID>.*)C(?P<chanID>.*){img_format}'
3106
- elif metadata_type == 'leica':
3107
- regex = f'(?P<plateID>.*)_(?P<wellID>.*)_T(?P<timeID>.*)F(?P<fieldID>.*)L(?P<laserID>..)A(?P<AID>..)Z(?P<sliceID>.*)C(?P<chanID>.*){img_format}'
3128
+ elif metadata_type == 'auto':
3129
+ regex = f'(?P<plateID>.*)_(?P<wellID>.*)_T(?P<timeID>.*)F(?P<fieldID>.*)L(?P<laserID>.*)C(?P<chanID>.*).tif'
3108
3130
  elif metadata_type == 'custom':
3109
3131
  regex = f'({custom_regex}){img_format}'
3110
3132
 
@@ -4945,7 +4967,7 @@ def download_models(repo_id="einarolafsson/models", retries=5, delay=5):
4945
4967
  if not os.path.exists(local_dir):
4946
4968
  os.makedirs(local_dir)
4947
4969
  elif len(os.listdir(local_dir)) > 0:
4948
- print(f"Models already downloaded to: {local_dir}")
4970
+ #print(f"Models already downloaded to: {local_dir}")
4949
4971
  return local_dir
4950
4972
 
4951
4973
  attempt = 0
@@ -5011,22 +5033,22 @@ def generate_cytoplasm_mask(nucleus_mask, cell_mask):
5011
5033
  return cytoplasm_mask
5012
5034
 
5013
5035
  def add_column_to_database(settings):
5014
- #"""
5015
- #Adds a new column to the database table by matching on a common column from the DataFrame.
5016
- #If the column already exists in the database, it adds the column with a suffix.
5017
- #NaN values will remain as NULL in the database.
5018
-
5019
- #Parameters:
5020
- # settings (dict): A dictionary containing the following keys:
5021
- # csv_path (str): Path to the CSV file with the data to be added.
5022
- # db_path (str): Path to the SQLite database (or connection string for other databases).
5023
- # table_name (str): The name of the table in the database.
5024
- # update_column (str): The name of the new column in the DataFrame to add to the database.
5025
- # match_column (str): The common column used to match rows.
5026
-
5027
- #Returns:
5028
- # None
5029
- #"""
5036
+ """
5037
+ Adds a new column to the database table by matching on a common column from the DataFrame.
5038
+ If the column already exists in the database, it adds the column with a suffix.
5039
+ NaN values will remain as NULL in the database.
5040
+
5041
+ Parameters:
5042
+ settings (dict): A dictionary containing the following keys:
5043
+ csv_path (str): Path to the CSV file with the data to be added.
5044
+ db_path (str): Path to the SQLite database (or connection string for other databases).
5045
+ table_name (str): The name of the table in the database.
5046
+ update_column (str): The name of the new column in the DataFrame to add to the database.
5047
+ match_column (str): The common column used to match rows.
5048
+
5049
+ Returns:
5050
+ None
5051
+ """
5030
5052
 
5031
5053
  # Read the DataFrame from the provided CSV path
5032
5054
  df = pd.read_csv(settings['csv_path'])
@@ -5337,3 +5359,63 @@ def calculate_shortest_distance(df, object1, object2):
5337
5359
  df[f'{object1}_{object2}_shortest_distance'] = np.maximum(shortest_distance, 0)
5338
5360
 
5339
5361
  return df
5362
+
5363
+ def format_path_for_system(path):
5364
+ """
5365
+ Takes a file path and reformats it to be compatible with the current operating system.
5366
+
5367
+ Args:
5368
+ path (str): The file path to be formatted.
5369
+
5370
+ Returns:
5371
+ str: The formatted path for the current operating system.
5372
+ """
5373
+ system = platform.system()
5374
+
5375
+ # Convert Windows-style paths to Unix-style (Linux/macOS)
5376
+ if system in ["Linux", "Darwin"]: # Darwin is macOS
5377
+ formatted_path = path.replace("\\", "/")
5378
+
5379
+ # Convert Unix-style paths to Windows-style
5380
+ elif system == "Windows":
5381
+ formatted_path = path.replace("/", "\\")
5382
+
5383
+ else:
5384
+ raise ValueError(f"Unsupported OS: {system}")
5385
+
5386
+ # Normalize path to ensure consistency
5387
+ new_path = os.path.normpath(formatted_path)
5388
+ if os.path.exists(new_path):
5389
+ print(f"Found path: {new_path}")
5390
+ else:
5391
+ print(f"Path not found: {new_path}")
5392
+
5393
+ return new_path
5394
+
5395
+
5396
+ def normalize_src_path(src):
5397
+ """
5398
+ Ensures that the 'src' value is properly formatted as either a list of strings or a single string.
5399
+
5400
+ Args:
5401
+ src (str or list): The input source path(s).
5402
+
5403
+ Returns:
5404
+ list or str: A correctly formatted list if the input was a list (or string representation of a list),
5405
+ otherwise a single string.
5406
+ """
5407
+ if isinstance(src, list):
5408
+ return src # Already a list, return as-is
5409
+
5410
+ if isinstance(src, str):
5411
+ try:
5412
+ # Check if it is a string representation of a list
5413
+ evaluated_src = ast.literal_eval(src)
5414
+ if isinstance(evaluated_src, list) and all(isinstance(item, str) for item in evaluated_src):
5415
+ return evaluated_src # Convert to real list
5416
+ except (SyntaxError, ValueError):
5417
+ pass # Not a valid list, treat as a string
5418
+
5419
+ return src # Return as a string if not a list
5420
+
5421
+ raise ValueError(f"Invalid type for 'src': {type(src).__name__}, expected str or list")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: spacr
3
- Version: 0.4.0
3
+ Version: 0.4.2
4
4
  Summary: Spatial phenotype analysis of crisp screens (SpaCr)
5
5
  Home-page: https://github.com/EinarOlafsson/spacr
6
6
  Author: Einar Birnir Olafsson
@@ -41,6 +41,7 @@ Requires-Dist: pillow<11.0,>=10.2.0
41
41
  Requires-Dist: tifffile>=2023.4.12
42
42
  Requires-Dist: nd2reader<4.0,>=3.3.0
43
43
  Requires-Dist: czifile
44
+ Requires-Dist: readlif
44
45
  Requires-Dist: imageio<3.0,>=2.34.0
45
46
  Requires-Dist: pingouin<1.0,>=0.5.5
46
47
  Requires-Dist: umap-learn<1.0,>=0.5.6
@@ -1,4 +1,4 @@
1
- spacr/__init__.py,sha256=KgkkUyqbm4kh8bwxWeFpp4rilNE0y0RkeylPvS-cTLY,1395
1
+ spacr/__init__.py,sha256=iPlE-WRc1CjSNGPMbVvEKlJsTQlKjq29VjzvNUCpcOM,1401
2
2
  spacr/__main__.py,sha256=bkAJJD2kjIqOP-u1kLvct9jQQCeUXzlEjdgitwi1Lm8,75
3
3
  spacr/app_annotate.py,sha256=W9eLPa_LZIvXsXx_-0iDFEU938LBDvRy6prXo0qF4KQ,2533
4
4
  spacr/app_classify.py,sha256=urTP_wlZ58hSyM5a19slYlBxN0PdC-9-ga0hvq8CGWc,165
@@ -9,27 +9,28 @@ spacr/app_sequencing.py,sha256=DjG26jy4cpddnV8WOOAIiExtOe9MleVMY4MFa5uTo5w,157
9
9
  spacr/app_umap.py,sha256=ZWAmf_OsIKbYvolYuWPMYhdlVe-n2CADoJulAizMiEo,153
10
10
  spacr/cellpose.py,sha256=RBHMs2vwXcfkj0xqAULpALyzJYXddSRycgZSzmwI7v0,14755
11
11
  spacr/chat_bot.py,sha256=n3Fhqg3qofVXHmh3H9sUcmfYy9MmgRnr48663MVdY9E,1244
12
- spacr/core.py,sha256=lKeqmsVrGQ8cPU_WkoNGNBWrk-gtR1RkRkwDdnJ0u64,48829
13
- spacr/deep_spacr.py,sha256=AsAbehxPChAq65YVPuFqCt5JabdeO8AwVWZmcmyLeFw,58020
12
+ spacr/core.py,sha256=KymF-YPvODMkp4J3xva7NwAKBLAUK_Z5x8_pjl9oaP4,49448
13
+ spacr/deep_spacr.py,sha256=WN64EaQqF87JZg3Uan46t5Y28xsAGD2KMjr2ht6CyDs,54563
14
14
  spacr/gui.py,sha256=ARyn9Q_g8HoP-cXh1nzMLVFCKqthY4v2u9yORyaQqQE,8230
15
- spacr/gui_core.py,sha256=U0A7waKgWq_Es9fMwcZbXUZYGzCqt2bgfY3HbxiFXnw,47466
16
- spacr/gui_elements.py,sha256=HmITDncklKwtdFhxLhtYXOwndsRfgwWIPVi83VlXHB4,146419
17
- spacr/gui_utils.py,sha256=0rDF23BUGcmjSJvfCiLoxhlGJdHkio1jTxyCzrMXr-g,41211
18
- spacr/io.py,sha256=oqJwDJWksVdWE0bRAwytTOsjlL0o-J9lr_pQaw2cQ4Y,138288
15
+ spacr/gui_core.py,sha256=BZpIdNztQn9U2BZxRsmYhr2uhVAm7ZW8-nZxu38QUvs,59027
16
+ spacr/gui_elements.py,sha256=Or38I_X9-lJRsyIAtbEfZPXzls0IORagf7vEe6IlI5Y,152647
17
+ spacr/gui_utils.py,sha256=dWVPFwDj793Z3ERG4mMC0hI0MKkOrvXJpUYlcjpCBsU,41357
18
+ spacr/io.py,sha256=bOfKwTqo5Z4YtS2E9PB5JVOvn1NkUJKeYxg8nDdGdGE,151762
19
19
  spacr/logger.py,sha256=lJhTqt-_wfAunCPl93xE65Wr9Y1oIHJWaZMjunHUeIw,1538
20
- spacr/measure.py,sha256=jmOnLBudq3TuY723Cfo1EJBn67P6rlEvL6I-2FSkUgI,55315
20
+ spacr/measure.py,sha256=Z3u4BU5RzcY82IZuboQ0OsxuXaPVwOlH65Rw6FrL5z4,55045
21
21
  spacr/mediar.py,sha256=FwLvbLQW5LQzPgvJZG8Lw7GniA2vbZx6Jv6vIKu7I5c,14743
22
22
  spacr/ml.py,sha256=MrIAtUUxMOibWVL1SjCUnYlizawCp3l3SeY4Y9yEsPw,97251
23
23
  spacr/openai.py,sha256=5vBZ3Jl2llYcW3oaTEXgdyCB2aJujMUIO5K038z7w_A,1246
24
- spacr/plot.py,sha256=p4AY5EWmVNPMqFD0I4NARJkvJA5gTErbDDYqDMU18pc,169479
24
+ spacr/plot.py,sha256=Q5TbsR2NUWhA7z4HyF_2_FAEBFSNMU-G3UNDbRzW6mM,169485
25
25
  spacr/sequencing.py,sha256=ClUfwPPK6rNUbUuiEkzcwakzVyDKKUMv9ricrxT8qQY,25227
26
- spacr/settings.py,sha256=e6QWZ5o6Im02_t-3GQh3H4kksMTQmIZ1Rbh3BeQmmsw,84000
26
+ spacr/settings.py,sha256=72bhOwr0U83uoWwaKtSNZucYhpgwTP1_GItRk9f6A6c,87592
27
27
  spacr/sim.py,sha256=1xKhXimNU3ukzIw-3l9cF3Znc_brW8h20yv8fSTzvss,71173
28
+ spacr/sp_stats.py,sha256=mbhwsyIqt5upsSD346qGjdCw7CFBa0tIS7zHU9e0jNI,9536
28
29
  spacr/stats.py,sha256=mbhwsyIqt5upsSD346qGjdCw7CFBa0tIS7zHU9e0jNI,9536
29
- spacr/submodules.py,sha256=e_JNMGBHakEra_2pstHFmgI1NhF9TybfvTNDAegVsl0,67626
30
+ spacr/submodules.py,sha256=jFlJeVNuIEf63TtCOpTlOZ4iiSLr238kRBiGAAAgKE4,67626
30
31
  spacr/timelapse.py,sha256=KGfG4L4-QnFfgbF7L6C5wL_3gd_rqr05Foje6RsoTBg,39603
31
32
  spacr/toxo.py,sha256=TmuhejSIPLBvsgeblsUgSvBFCR1gOkApyTKidooJ5Us,26044
32
- spacr/utils.py,sha256=m4MZiNbmQpZD78eu5DNmxk4cU_tk2VeVLCe_R_7YShY,226287
33
+ spacr/utils.py,sha256=v13vzgEQwUnQAtQya_akKIkem26-0Nn5j9uhx_NcJXQ,228599
33
34
  spacr/version.py,sha256=axH5tnGwtgSnJHb5IDhiu4Zjk5GhLyAEDRe-rnaoFOA,409
34
35
  spacr/resources/MEDIAR/.gitignore,sha256=Ff1q9Nme14JUd-4Q3jZ65aeQ5X4uttptssVDgBVHYo8,152
35
36
  spacr/resources/MEDIAR/LICENSE,sha256=yEj_TRDLUfDpHDNM0StALXIt6mLqSgaV2hcCwa6_TcY,1065
@@ -152,9 +153,9 @@ spacr/resources/icons/umap.png,sha256=dOLF3DeLYy9k0nkUybiZMe1wzHQwLJFRmgccppw-8b
152
153
  spacr/resources/images/plate1_E01_T0001F001L01A01Z01C02.tif,sha256=Tl0ZUfZ_AYAbu0up_nO0tPRtF1BxXhWQ3T3pURBCCRo,7958528
153
154
  spacr/resources/images/plate1_E01_T0001F001L01A02Z01C01.tif,sha256=m8N-V71rA1TT4dFlENNg8s0Q0YEXXs8slIn7yObmZJQ,7958528
154
155
  spacr/resources/images/plate1_E01_T0001F001L01A03Z01C03.tif,sha256=Pbhk7xn-KUP6RSIhJsxQcrHFImBm3GEpLkzx7WOc-5M,7958528
155
- spacr-0.4.0.dist-info/LICENSE,sha256=SR-2MeGc6SCM1UORJYyarSWY_A-JaOMFDj7ReSs9tRM,1083
156
- spacr-0.4.0.dist-info/METADATA,sha256=uloYFy8DrWtHZvy5W47jBRNUEF_SeX4nLZ0OL2wMizc,6072
157
- spacr-0.4.0.dist-info/WHEEL,sha256=HiCZjzuy6Dw0hdX5R3LCFPDmFS4BWl8H-8W39XfmgX4,91
158
- spacr-0.4.0.dist-info/entry_points.txt,sha256=BMC0ql9aNNpv8lUZ8sgDLQMsqaVnX5L535gEhKUP5ho,296
159
- spacr-0.4.0.dist-info/top_level.txt,sha256=GJPU8FgwRXGzKeut6JopsSRY2R8T3i9lDgya42tLInY,6
160
- spacr-0.4.0.dist-info/RECORD,,
156
+ spacr-0.4.2.dist-info/LICENSE,sha256=SR-2MeGc6SCM1UORJYyarSWY_A-JaOMFDj7ReSs9tRM,1083
157
+ spacr-0.4.2.dist-info/METADATA,sha256=1yh08ENDvMjQGyCKwh6BX5j78vwd9JyE8JlBzpkYg7o,6095
158
+ spacr-0.4.2.dist-info/WHEEL,sha256=HiCZjzuy6Dw0hdX5R3LCFPDmFS4BWl8H-8W39XfmgX4,91
159
+ spacr-0.4.2.dist-info/entry_points.txt,sha256=BMC0ql9aNNpv8lUZ8sgDLQMsqaVnX5L535gEhKUP5ho,296
160
+ spacr-0.4.2.dist-info/top_level.txt,sha256=GJPU8FgwRXGzKeut6JopsSRY2R8T3i9lDgya42tLInY,6
161
+ spacr-0.4.2.dist-info/RECORD,,
File without changes
File without changes