spacr 0.3.2__py3-none-any.whl → 0.3.22__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
@@ -1,4 +1,4 @@
1
- import os, re, sqlite3, torch, torchvision, random, string, shutil, cv2, tarfile, glob, psutil, platform, gzip, subprocess, time, requests
1
+ import os, re, sqlite3, torch, torchvision, random, string, shutil, cv2, tarfile, glob, psutil, platform, gzip, subprocess, time, requests, ast
2
2
 
3
3
  import numpy as np
4
4
  import pandas as pd
@@ -37,6 +37,7 @@ from torchvision import models
37
37
  from torchvision.models.resnet import ResNet18_Weights, ResNet34_Weights, ResNet50_Weights, ResNet101_Weights, ResNet152_Weights
38
38
  import torchvision.transforms as transforms
39
39
  from torchvision.models import resnet50
40
+ from torchvision.utils import make_grid
40
41
 
41
42
  import seaborn as sns
42
43
  import matplotlib.pyplot as plt
@@ -66,13 +67,84 @@ from huggingface_hub import list_repo_files
66
67
  import umap.umap_ as umap
67
68
  #import umap
68
69
 
70
+ def load_settings(csv_file_path, show=False, setting_key='setting_key', setting_value='setting_value'):
71
+ """
72
+ Convert a CSV file with 'settings_key' and 'settings_value' columns into a dictionary.
73
+ Handles special cases where values are lists, tuples, booleans, None, integers, floats, and nested dictionaries.
74
+
75
+ Args:
76
+ csv_file_path (str): The path to the CSV file.
77
+ show (bool): Whether to display the dataframe (for debugging).
78
+ setting_key (str): The name of the column that contains the setting keys.
79
+ setting_value (str): The name of the column that contains the setting values.
80
+
81
+ Returns:
82
+ dict: A dictionary where 'settings_key' are the keys and 'settings_value' are the values.
83
+ """
84
+ # Read the CSV file into a DataFrame
85
+ df = pd.read_csv(csv_file_path)
86
+
87
+ if show:
88
+ display(df)
89
+
90
+ # Ensure the columns 'setting_key' and 'setting_value' exist
91
+ if setting_key not in df.columns or setting_value not in df.columns:
92
+ raise ValueError(f"CSV file must contain {setting_key} and {setting_value} columns.")
93
+
94
+ def parse_value(value):
95
+ """Parse the string value into the appropriate Python data type."""
96
+ # Handle empty values
97
+ if pd.isna(value) or value == '':
98
+ return None
99
+
100
+ # Handle boolean values
101
+ if value == 'True':
102
+ return True
103
+ if value == 'False':
104
+ return False
105
+
106
+ # Handle lists, tuples, dictionaries, and other literals
107
+ if value.startswith(('(', '[', '{')): # If it starts with (, [ or {, use ast.literal_eval
108
+ try:
109
+ parsed_value = ast.literal_eval(value)
110
+ # If parsed_value is a dict, recursively parse its values
111
+ if isinstance(parsed_value, dict):
112
+ parsed_value = {k: parse_value(v) for k, v in parsed_value.items()}
113
+ return parsed_value
114
+ except (ValueError, SyntaxError):
115
+ pass # If there's an error, return the value as-is
116
+
117
+ # Handle numeric values (integers and floats)
118
+ try:
119
+ if '.' in value:
120
+ return float(value) # If it contains a dot, convert to float
121
+ return int(value) # Otherwise, convert to integer
122
+ except ValueError:
123
+ pass # If it's not a valid number, return the value as-is
124
+
125
+ # Return the original value if no other type matched
126
+ return value
127
+
128
+ # Convert the DataFrame to a dictionary, with parsing of each value
129
+ result_dict = {key: parse_value(value) for key, value in zip(df[setting_key], df[setting_value])}
130
+
131
+ return result_dict
132
+
133
+
69
134
  def save_settings(settings, name='settings', show=False):
70
135
 
71
136
  settings_df = pd.DataFrame(list(settings.items()), columns=['Key', 'Value'])
72
137
  if show:
73
138
  display(settings_df)
74
- settings_csv = os.path.join(settings['src'],'settings',f'{name}.csv')
75
- os.makedirs(os.path.join(settings['src'],'settings'), exist_ok=True)
139
+
140
+ if isinstance(settings['src'], list):
141
+ src = settings['src'][0]
142
+ name = f"{name}_list"
143
+ else:
144
+ src = settings['src']
145
+
146
+ settings_csv = os.path.join(src,'settings',f'{name}.csv')
147
+ os.makedirs(os.path.join(src,'settings'), exist_ok=True)
76
148
  settings_df.to_csv(settings_csv, index=False)
77
149
 
78
150
  def print_progress(files_processed, files_to_process, n_jobs, time_ls=None, batch_size=None, operation_type=""):
@@ -2987,7 +3059,6 @@ def preprocess_image(image_path, image_size=224, channels=[1,2,3], normalize=Tru
2987
3059
  input_tensor = transform(image).unsqueeze(0)
2988
3060
  return image, input_tensor
2989
3061
 
2990
-
2991
3062
  class SaliencyMapGenerator:
2992
3063
  def __init__(self, model):
2993
3064
  self.model = model
@@ -3008,17 +3079,63 @@ class SaliencyMapGenerator:
3008
3079
  saliency = X.grad.abs()
3009
3080
  return saliency
3010
3081
 
3011
- def plot_saliency_maps(self, X, y, saliency, class_names):
3082
+ def compute_saliency_and_predictions(self, X):
3083
+ self.model.eval()
3084
+ X.requires_grad_()
3085
+
3086
+ # Forward pass to get predictions (logits)
3087
+ scores = self.model(X).squeeze()
3088
+
3089
+ # Get predicted class (0 or 1 for binary classification)
3090
+ predictions = (scores > 0).long()
3091
+
3092
+ # Compute saliency maps
3093
+ self.model.zero_grad()
3094
+ target_scores = scores * (2 * predictions - 1)
3095
+ target_scores.backward(torch.ones_like(target_scores))
3096
+
3097
+ saliency = X.grad.abs()
3098
+
3099
+ return saliency, predictions
3100
+
3101
+ def plot_saliency_grid(self, X, saliency, predictions, mode='mean'):
3012
3102
  N = X.shape[0]
3103
+ rows = (N + 7) // 8 # Ensure we can handle batches of different sizes
3104
+ fig, axs = plt.subplots(rows, 8, figsize=(16, rows * 2))
3105
+
3013
3106
  for i in range(N):
3014
- plt.subplot(2, N, i + 1)
3015
- plt.imshow(X[i].permute(1, 2, 0).cpu().numpy())
3016
- plt.axis('off')
3017
- plt.title(class_names[y[i]])
3018
- plt.subplot(2, N, N + i + 1)
3019
- plt.imshow(saliency[i].cpu().numpy(), cmap=plt.cm.hot)
3020
- plt.axis('off')
3021
- plt.gcf().set_size_inches(12, 5)
3107
+ ax = axs[i // 8, i % 8]
3108
+
3109
+ if mode == 'mean':
3110
+ saliency_map = saliency[i].mean(dim=0).cpu().numpy() # Mean saliency over channels
3111
+ ax.imshow(X[i].permute(1, 2, 0).detach().cpu().numpy()) # Added .detach() here
3112
+ ax.imshow(saliency_map, cmap='jet', alpha=0.5)
3113
+
3114
+ elif mode == 'channel':
3115
+ # Plot individual channels in a loop if the image has multiple channels
3116
+ for j in range(X.shape[1]):
3117
+ saliency_map = saliency[i, j].cpu().numpy()
3118
+ ax.imshow(saliency_map, cmap='jet')
3119
+ ax.axis('off')
3120
+
3121
+ elif mode == '3-channel' and X.shape[1] == 3:
3122
+ saliency_map = saliency[i].cpu().numpy().transpose(1, 2, 0)
3123
+ ax.imshow(saliency_map)
3124
+
3125
+ elif mode == '2-channel' and X.shape[1] == 2:
3126
+ saliency_map = saliency[i].cpu().numpy().transpose(1, 2, 0)
3127
+ ax.imshow(saliency_map)
3128
+
3129
+ # Add class label in top-left corner
3130
+ ax.text(5, 25, str(predictions[i].item()), fontsize=12, color='white', weight='bold',
3131
+ bbox=dict(facecolor='black', alpha=0.7, boxstyle='round,pad=0.2'))
3132
+ ax.axis('off')
3133
+
3134
+ # Turn off unused axes
3135
+ for j in range(N, rows * 8):
3136
+ fig.delaxes(axs[j // 8, j % 8])
3137
+
3138
+ plt.tight_layout(pad=0)
3022
3139
  plt.show()
3023
3140
 
3024
3141
  def preprocess_image(image_path, normalize=True, image_size=224, channels=[1,2,3]):
@@ -4548,3 +4665,25 @@ def download_models(repo_id="einarolafsson/models", local_dir=None, retries=5, d
4548
4665
  time.sleep(delay)
4549
4666
 
4550
4667
  raise Exception("Failed to download model files after multiple attempts.")
4668
+
4669
+ def generate_cytoplasm_mask(nucleus_mask, cell_mask):
4670
+
4671
+ """
4672
+ Generates a cytoplasm mask from nucleus and cell masks.
4673
+
4674
+ Parameters:
4675
+ - nucleus_mask (np.array): Binary or segmented mask of the nucleus (non-zero values represent nucleus).
4676
+ - cell_mask (np.array): Binary or segmented mask of the whole cell (non-zero values represent cell).
4677
+
4678
+ Returns:
4679
+ - cytoplasm_mask (np.array): Mask for the cytoplasm (1 for cytoplasm, 0 for nucleus and pathogens).
4680
+ """
4681
+
4682
+ # Make sure the nucleus and cell masks are numpy arrays
4683
+ nucleus_mask = np.array(nucleus_mask)
4684
+ cell_mask = np.array(cell_mask)
4685
+
4686
+ # Generate cytoplasm mask
4687
+ cytoplasm_mask = np.where(np.logical_or(nucleus_mask != 0), 0, cell_mask)
4688
+
4689
+ return cytoplasm_mask
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: spacr
3
- Version: 0.3.2
3
+ Version: 0.3.22
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
@@ -10,34 +10,41 @@ Classifier: License :: OSI Approved :: MIT License
10
10
  Classifier: Operating System :: OS Independent
11
11
  Description-Content-Type: text/x-rst
12
12
  License-File: LICENSE
13
- Requires-Dist: torch<3.0,>=2.0
14
- Requires-Dist: torchvision<1.0,>=0.1
15
- Requires-Dist: torch-geometric<3.0,>=2.5
16
13
  Requires-Dist: numpy<2.0,>=1.26.4
17
- Requires-Dist: bottleneck<2.0,>=1.3.6
18
- Requires-Dist: numexpr<3.0,>=2.8.4
19
14
  Requires-Dist: pandas<3.0,>=2.2.1
20
- Requires-Dist: statsmodels<1.0,>=0.14.1
15
+ Requires-Dist: scipy<2.0,>=1.12.0
16
+ Requires-Dist: cellpose<4.0,>=3.0.6
21
17
  Requires-Dist: scikit-image<1.0,>=0.22.0
22
18
  Requires-Dist: scikit-learn<2.0,>=1.4.1
23
- Requires-Dist: seaborn<1.0,>=0.13.2
24
- Requires-Dist: matplotlib<4.0,>=3.8.3
25
- Requires-Dist: shap<1.0,>=0.45.0
26
- Requires-Dist: pillow<11.0,>=10.2.0
27
- Requires-Dist: imageio<3.0,>=2.34.0
28
- Requires-Dist: scipy<2.0,>=1.12.0
29
- Requires-Dist: ipywidgets<9.0,>=8.1.2
30
19
  Requires-Dist: mahotas<2.0,>=1.4.13
31
20
  Requires-Dist: btrack<1.0,>=0.6.5
32
21
  Requires-Dist: trackpy<1.0,>=0.6.2
33
- Requires-Dist: cellpose<4.0,>=3.0.6
34
- Requires-Dist: IPython<9.0,>=8.18.1
22
+ Requires-Dist: statsmodels<1.0,>=0.14.1
23
+ Requires-Dist: shap<1.0,>=0.45.0
24
+ Requires-Dist: torch<3.0,>=2.0
25
+ Requires-Dist: torchvision<1.0,>=0.1
26
+ Requires-Dist: torch-geometric<3.0,>=2.5
27
+ Requires-Dist: torchcam<1.0,>=0.4.0
28
+ Requires-Dist: transformers<5.0,>=4.45.2
29
+ Requires-Dist: segmentation-models-pytorch>=0.3.3
30
+ Requires-Dist: monai>=1.3.0
31
+ Requires-Dist: captum<1.0,>=0.7.0
32
+ Requires-Dist: seaborn<1.0,>=0.13.2
33
+ Requires-Dist: matplotlib<4.0,>=3.8.3
34
+ Requires-Dist: adjustText<2.0,>=1.2.0
35
+ Requires-Dist: bottleneck<2.0,>=1.3.6
36
+ Requires-Dist: numexpr<3.0,>=2.8.4
35
37
  Requires-Dist: opencv-python-headless<5.0,>=4.9.0.80
38
+ Requires-Dist: pillow<11.0,>=10.2.0
39
+ Requires-Dist: tifffile>=2023.4.12
40
+ Requires-Dist: nd2reader<4.0,>=3.3.0
41
+ Requires-Dist: czifile
42
+ Requires-Dist: imageio<3.0,>=2.34.0
43
+ Requires-Dist: pingouin<1.0,>=0.5.5
36
44
  Requires-Dist: umap-learn<1.0,>=0.5.6
37
45
  Requires-Dist: ttkthemes<4.0,>=3.2.2
38
46
  Requires-Dist: xgboost<3.0,>=2.0.3
39
47
  Requires-Dist: PyWavelets<2.0,>=1.6.0
40
- Requires-Dist: torchcam<1.0,>=0.4.0
41
48
  Requires-Dist: ttf-opensans>=2020.10.30
42
49
  Requires-Dist: customtkinter<6.0,>=5.2.2
43
50
  Requires-Dist: biopython<2.0,>=1.80
@@ -50,19 +57,15 @@ Requires-Dist: tables<4.0,>=3.8.0
50
57
  Requires-Dist: rapidfuzz<4.0,>=3.9
51
58
  Requires-Dist: keyring<16.0,>=15.1
52
59
  Requires-Dist: screeninfo<1.0,>=0.8.1
53
- Requires-Dist: ipykernel
54
- Requires-Dist: gdown
55
60
  Requires-Dist: fastremap>=1.14.1
56
- Requires-Dist: monai>=1.3.0
57
61
  Requires-Dist: pytz>=2023.3.post1
58
- Requires-Dist: segmentation-models-pytorch>=0.3.3
59
- Requires-Dist: tifffile>=2023.4.12
60
62
  Requires-Dist: tqdm>=4.65.0
61
63
  Requires-Dist: wandb>=0.16.2
62
64
  Requires-Dist: openai<2.0,>=1.50.2
63
- Requires-Dist: nd2reader<4.0,>=3.3.0
64
- Requires-Dist: czifile
65
- Requires-Dist: adjustText<2.0,>=1.2.0
65
+ Requires-Dist: gdown
66
+ Requires-Dist: IPython<9.0,>=8.18.1
67
+ Requires-Dist: ipykernel
68
+ Requires-Dist: ipywidgets<9.0,>=8.1.2
66
69
  Requires-Dist: huggingface-hub<0.25,>=0.24.0
67
70
  Provides-Extra: dev
68
71
  Requires-Dist: pytest<3.11,>=3.9; extra == "dev"
@@ -8,26 +8,26 @@ spacr/app_measure.py,sha256=_K7APYIeOKpV6e_LcqabBjvEi7mfq9Fch8175x1x0k8,162
8
8
  spacr/app_sequencing.py,sha256=DjG26jy4cpddnV8WOOAIiExtOe9MleVMY4MFa5uTo5w,157
9
9
  spacr/app_umap.py,sha256=ZWAmf_OsIKbYvolYuWPMYhdlVe-n2CADoJulAizMiEo,153
10
10
  spacr/cellpose.py,sha256=zv4BzhaP2O-mtQ-pUfYvpOyxgn1ke_bDWgdHD5UWm9I,13942
11
- spacr/core.py,sha256=KNsjpQR_L5mAABrJ4U_JMNsUMav81ILvnjL0Jf2ohU8,43858
12
- spacr/deep_spacr.py,sha256=HT7x_xHoM8s-AX6aSEHv4mf4wMld9PNDTgzsX-0FqO4,39416
11
+ spacr/core.py,sha256=G_x-w7FRIHNfSOoPaIZPSf_A7mVj7PA7o9HQZ4nIu5o,48231
12
+ spacr/deep_spacr.py,sha256=iPJhwhNQKF0_PmQ3RXi_gK7BKvIb5m54DeYZRlXBqMU,46081
13
13
  spacr/gui.py,sha256=ndmWP4F0QO5j6DM6MNzoGtzv_7Yj4LTW2SLi9URBZIQ,8055
14
14
  spacr/gui_core.py,sha256=OJQxzpehIyDzjSjIsvxSHat4NIjkqjX0VZAUQTnzEzg,40921
15
15
  spacr/gui_elements.py,sha256=3ru8FPZtXCZSj7167GJj18-Zo6TVebhAzkit-mmqmTI,135342
16
16
  spacr/gui_utils.py,sha256=76utRICvY0k_6X8CA1P_TmYBJARp4b87OkI9t39tldA,45822
17
- spacr/io.py,sha256=_P0Rb1ftBlheb9Yd0Bm8py_MeV2bh0ZxDlVRYOZAfBY,144579
17
+ spacr/io.py,sha256=Xy1Drm5NPhxvwE1nyJVd2SQu3yTynlnvSrjlRuFXwBw,143371
18
18
  spacr/logger.py,sha256=lJhTqt-_wfAunCPl93xE65Wr9Y1oIHJWaZMjunHUeIw,1538
19
19
  spacr/measure.py,sha256=8MRjQdB-2n8JVLjEpF3cxvfT-Udug27uJ2ErJJ5t1ic,56000
20
20
  spacr/mediar.py,sha256=FwLvbLQW5LQzPgvJZG8Lw7GniA2vbZx6Jv6vIKu7I5c,14743
21
- spacr/ml.py,sha256=uf43GIxxgSasq9OiWQYnQO0fV3d5yTPEHkV78jHb-i4,42540
21
+ spacr/ml.py,sha256=3XiQUfhhseCz9cZXhaVkCCv_qfqoZCdXGnO_p3ulwo4,47131
22
22
  spacr/openai.py,sha256=5vBZ3Jl2llYcW3oaTEXgdyCB2aJujMUIO5K038z7w_A,1246
23
- spacr/plot.py,sha256=kPVUlMaRSH2zZIm64o8FmhHILMCRRmzs-uFVPQEIupw,85281
23
+ spacr/plot.py,sha256=eZcs-CQrDTENXVeMY8y8N8VZnmPePO-kAWdoaweFmW8,105540
24
24
  spacr/sequencing.py,sha256=t18mgpK6rhWuB1LtFOsPxqgpFXxuUmrD06ecsaVQ0Gw,19655
25
- spacr/settings.py,sha256=IaRnHXRVrkOOfA0ymavXOJTjPE56_BdOPrbEHq7oONQ,73508
25
+ spacr/settings.py,sha256=YExChD7DWY_cJyaPGKDTpFajsXXi5ZQ8P0XR9ZQf8CE,73560
26
26
  spacr/sim.py,sha256=1xKhXimNU3ukzIw-3l9cF3Znc_brW8h20yv8fSTzvss,71173
27
- spacr/submodules.py,sha256=ojBFEnOZ_YTGcOvSFEAPP6J7-w08QIAFJLEPYjUCkMM,18337
27
+ spacr/submodules.py,sha256=AB7s6-cULsaqz-haAaCtXfGEIi8uPZGT4xoCslUJC3Y,18391
28
28
  spacr/timelapse.py,sha256=FSYpUtAVy6xc3lwprRYgyDTT9ysUhfRQ4zrP9_h2mvg,39465
29
- spacr/toxo.py,sha256=nkV8w1wvaEsDFoSIOVvU5UcIIaTngHfgKNhhZYzBDyY,9893
30
- spacr/utils.py,sha256=nW4s7wy4spk3T3yYTQGLvonDz5KX6t_d0NKiHcqMPN0,193044
29
+ spacr/toxo.py,sha256=us3pQyULtMTyfTq0MWPn4QJTTmQ6BwAJKChNf75jo3I,10082
30
+ spacr/utils.py,sha256=brlNXsDcsKyHjJ2IodB0KyMQkEpQfMBp5QZCCb0vdz8,198459
31
31
  spacr/version.py,sha256=axH5tnGwtgSnJHb5IDhiu4Zjk5GhLyAEDRe-rnaoFOA,409
32
32
  spacr/resources/MEDIAR/.gitignore,sha256=Ff1q9Nme14JUd-4Q3jZ65aeQ5X4uttptssVDgBVHYo8,152
33
33
  spacr/resources/MEDIAR/LICENSE,sha256=yEj_TRDLUfDpHDNM0StALXIt6mLqSgaV2hcCwa6_TcY,1065
@@ -150,9 +150,9 @@ spacr/resources/icons/umap.png,sha256=dOLF3DeLYy9k0nkUybiZMe1wzHQwLJFRmgccppw-8b
150
150
  spacr/resources/images/plate1_E01_T0001F001L01A01Z01C02.tif,sha256=Tl0ZUfZ_AYAbu0up_nO0tPRtF1BxXhWQ3T3pURBCCRo,7958528
151
151
  spacr/resources/images/plate1_E01_T0001F001L01A02Z01C01.tif,sha256=m8N-V71rA1TT4dFlENNg8s0Q0YEXXs8slIn7yObmZJQ,7958528
152
152
  spacr/resources/images/plate1_E01_T0001F001L01A03Z01C03.tif,sha256=Pbhk7xn-KUP6RSIhJsxQcrHFImBm3GEpLkzx7WOc-5M,7958528
153
- spacr-0.3.2.dist-info/LICENSE,sha256=SR-2MeGc6SCM1UORJYyarSWY_A-JaOMFDj7ReSs9tRM,1083
154
- spacr-0.3.2.dist-info/METADATA,sha256=T4leZtOLZyUy19ueD2g_TmAQdTRCbkS29QJXcVf6ciw,5837
155
- spacr-0.3.2.dist-info/WHEEL,sha256=HiCZjzuy6Dw0hdX5R3LCFPDmFS4BWl8H-8W39XfmgX4,91
156
- spacr-0.3.2.dist-info/entry_points.txt,sha256=BMC0ql9aNNpv8lUZ8sgDLQMsqaVnX5L535gEhKUP5ho,296
157
- spacr-0.3.2.dist-info/top_level.txt,sha256=GJPU8FgwRXGzKeut6JopsSRY2R8T3i9lDgya42tLInY,6
158
- spacr-0.3.2.dist-info/RECORD,,
153
+ spacr-0.3.22.dist-info/LICENSE,sha256=SR-2MeGc6SCM1UORJYyarSWY_A-JaOMFDj7ReSs9tRM,1083
154
+ spacr-0.3.22.dist-info/METADATA,sha256=wHP5zD5dSSsxLHNjlr3-OALEmhzL7gexG_uqX6M0OWc,5949
155
+ spacr-0.3.22.dist-info/WHEEL,sha256=HiCZjzuy6Dw0hdX5R3LCFPDmFS4BWl8H-8W39XfmgX4,91
156
+ spacr-0.3.22.dist-info/entry_points.txt,sha256=BMC0ql9aNNpv8lUZ8sgDLQMsqaVnX5L535gEhKUP5ho,296
157
+ spacr-0.3.22.dist-info/top_level.txt,sha256=GJPU8FgwRXGzKeut6JopsSRY2R8T3i9lDgya42tLInY,6
158
+ spacr-0.3.22.dist-info/RECORD,,
File without changes