spacr 0.3.47__py3-none-any.whl → 0.3.52__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/chat_bot.py +31 -0
- spacr/gui_elements.py +33 -7
- spacr/gui_utils.py +11 -12
- spacr/measure.py +4 -1
- spacr/ml.py +453 -141
- spacr/plot.py +612 -52
- spacr/sequencing.py +5 -2
- spacr/settings.py +15 -31
- spacr/toxo.py +447 -159
- spacr/utils.py +35 -4
- {spacr-0.3.47.dist-info → spacr-0.3.52.dist-info}/METADATA +3 -1
- {spacr-0.3.47.dist-info → spacr-0.3.52.dist-info}/RECORD +16 -15
- {spacr-0.3.47.dist-info → spacr-0.3.52.dist-info}/LICENSE +0 -0
- {spacr-0.3.47.dist-info → spacr-0.3.52.dist-info}/WHEEL +0 -0
- {spacr-0.3.47.dist-info → spacr-0.3.52.dist-info}/entry_points.txt +0 -0
- {spacr-0.3.47.dist-info → spacr-0.3.52.dist-info}/top_level.txt +0 -0
spacr/chat_bot.py
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
import os
|
2
|
+
import torch
|
3
|
+
from multiprocessing import Queue
|
4
|
+
from transformers import AutoTokenizer, AutoModelForCausalLM
|
5
|
+
|
6
|
+
# Disable parallelism warnings
|
7
|
+
os.environ["TOKENIZERS_PARALLELISM"] = "false"
|
8
|
+
|
9
|
+
def load_model(model_queue):
|
10
|
+
"""Load the Falcon-7B model and send the status via a queue."""
|
11
|
+
try:
|
12
|
+
print("Loading Falcon-7B model...")
|
13
|
+
tokenizer = AutoTokenizer.from_pretrained("tiiuae/falcon-7b")
|
14
|
+
|
15
|
+
# Set `pad_token` to `eos_token` if not already set
|
16
|
+
if tokenizer.pad_token is None:
|
17
|
+
tokenizer.pad_token = tokenizer.eos_token
|
18
|
+
|
19
|
+
model = AutoModelForCausalLM.from_pretrained("tiiuae/falcon-7b")
|
20
|
+
model.config.pad_token_id = tokenizer.pad_token_id
|
21
|
+
|
22
|
+
# Send the loaded model and tokenizer back via the queue
|
23
|
+
model_queue.put((model, tokenizer, "Model loaded successfully!"))
|
24
|
+
except Exception as e:
|
25
|
+
model_queue.put((None, None, f"Error loading model: {e}"))
|
26
|
+
|
27
|
+
def language_chat(tokenizer, model, user_input):
|
28
|
+
inputs = tokenizer(user_input, return_tensors="pt", padding=True, truncation=True)
|
29
|
+
outputs = model.generate(inputs.input_ids, max_length=256, pad_token_id=tokenizer.eos_token_id)
|
30
|
+
return tokenizer.decode(outputs[0], skip_special_tokens=True)
|
31
|
+
|
spacr/gui_elements.py
CHANGED
@@ -16,7 +16,8 @@ from collections import deque
|
|
16
16
|
from skimage.draw import polygon, line
|
17
17
|
from skimage.transform import resize
|
18
18
|
from scipy.ndimage import binary_fill_holes, label
|
19
|
-
from tkinter import ttk, scrolledtext
|
19
|
+
from tkinter import ttk, scrolledtext
|
20
|
+
from skimage.color import rgb2gray
|
20
21
|
|
21
22
|
fig = None
|
22
23
|
|
@@ -1534,20 +1535,45 @@ class ModifyMaskApp:
|
|
1534
1535
|
tk.Label(self.zoom_toolbar, text="Upper Percentile:", bg='black', fg='white').pack(side='left')
|
1535
1536
|
self.upper_entry = tk.Entry(self.zoom_toolbar, textvariable=self.upper_quantile, bg='black', fg='white')
|
1536
1537
|
self.upper_entry.pack(side='left')
|
1537
|
-
|
1538
|
-
|
1538
|
+
|
1539
1539
|
def load_image_and_mask(self, index):
|
1540
|
+
# Load the image
|
1540
1541
|
image_path = os.path.join(self.folder_path, self.image_filenames[index])
|
1541
|
-
image = imageio.imread(image_path)
|
1542
|
+
image = imageio.imread(image_path)
|
1543
|
+
print(f"Original Image shape: {image.shape}, dtype: {image.dtype}")
|
1544
|
+
|
1545
|
+
# Handle multi-channel or transparency issues
|
1546
|
+
if image.ndim == 3:
|
1547
|
+
if image.shape[2] == 4: # If the image has an alpha channel (RGBA)
|
1548
|
+
image = image[..., :3] # Remove the alpha channel
|
1549
|
+
|
1550
|
+
# Convert RGB to grayscale using weighted average
|
1551
|
+
image = np.dot(image[..., :3], [0.2989, 0.5870, 0.1140]).astype(np.uint8)
|
1552
|
+
print(f"Converted to grayscale: {image.shape}")
|
1553
|
+
|
1554
|
+
# Ensure the shape is (height, width) without extra channel
|
1555
|
+
if image.ndim == 3 and image.shape[2] == 1:
|
1556
|
+
image = np.squeeze(image, axis=-1)
|
1557
|
+
|
1558
|
+
if image.dtype != np.uint16:
|
1559
|
+
# Scale the image to fit the 16-bit range (0–65535)
|
1560
|
+
image = (image / image.max() * 65535).astype(np.uint16)
|
1561
|
+
# eventually remove this images should not have to be 16 bit look into downstream function (non 16bit images are jsut black)
|
1562
|
+
|
1563
|
+
# Load the corresponding mask
|
1542
1564
|
mask_path = os.path.join(self.masks_folder, self.image_filenames[index])
|
1543
1565
|
if os.path.exists(mask_path):
|
1544
|
-
print(f'
|
1566
|
+
print(f'Loading mask: {mask_path} for image: {image_path}')
|
1545
1567
|
mask = imageio.imread(mask_path)
|
1568
|
+
|
1569
|
+
# Ensure mask is uint8
|
1546
1570
|
if mask.dtype != np.uint8:
|
1547
|
-
mask = (mask /
|
1571
|
+
mask = (mask / mask.max() * 255).astype(np.uint8)
|
1548
1572
|
else:
|
1573
|
+
# Create a new mask with the same size as the image
|
1549
1574
|
mask = np.zeros(image.shape[:2], dtype=np.uint8)
|
1550
|
-
print(f'
|
1575
|
+
print(f'Loaded new mask for image: {image_path}')
|
1576
|
+
|
1551
1577
|
return image, mask
|
1552
1578
|
|
1553
1579
|
####################################################################################################
|
spacr/gui_utils.py
CHANGED
@@ -76,8 +76,8 @@ def load_app(root, app_name, app_func):
|
|
76
76
|
root.current_app_exit_func()
|
77
77
|
else:
|
78
78
|
proceed_with_app(root, app_name, app_func)
|
79
|
-
|
80
|
-
def
|
79
|
+
|
80
|
+
def parse_list(value):
|
81
81
|
"""
|
82
82
|
Parses a string representation of a list and returns the parsed list.
|
83
83
|
|
@@ -85,7 +85,7 @@ def parse_list_v1(value):
|
|
85
85
|
value (str): The string representation of the list.
|
86
86
|
|
87
87
|
Returns:
|
88
|
-
list: The parsed list.
|
88
|
+
list: The parsed list, which can contain integers, floats, or strings.
|
89
89
|
|
90
90
|
Raises:
|
91
91
|
ValueError: If the input value is not a valid list format or contains mixed types or unsupported types.
|
@@ -93,21 +93,20 @@ def parse_list_v1(value):
|
|
93
93
|
try:
|
94
94
|
parsed_value = ast.literal_eval(value)
|
95
95
|
if isinstance(parsed_value, list):
|
96
|
-
# Check if
|
97
|
-
if all(isinstance(item, int) for item in parsed_value):
|
98
|
-
return parsed_value
|
99
|
-
elif all(isinstance(item, str) for item in parsed_value):
|
100
|
-
return parsed_value
|
101
|
-
elif all(isinstance(item, float) for item in parsed_value):
|
96
|
+
# Check if all elements are homogeneous (either all int, float, or str)
|
97
|
+
if all(isinstance(item, (int, float, str)) for item in parsed_value):
|
102
98
|
return parsed_value
|
103
99
|
else:
|
104
100
|
raise ValueError("List contains mixed types or unsupported types")
|
101
|
+
elif isinstance(parsed_value, tuple):
|
102
|
+
# Convert tuple to list if it’s a single-element tuple
|
103
|
+
return list(parsed_value) if len(parsed_value) > 1 else [parsed_value[0]]
|
105
104
|
else:
|
106
105
|
raise ValueError(f"Expected a list but got {type(parsed_value).__name__}")
|
107
106
|
except (ValueError, SyntaxError) as e:
|
108
107
|
raise ValueError(f"Invalid format for list: {value}. Error: {e}")
|
109
|
-
|
110
|
-
def
|
108
|
+
|
109
|
+
def parse_list_v1(value):
|
111
110
|
"""
|
112
111
|
Parses a string representation of a list and returns the parsed list.
|
113
112
|
|
@@ -391,7 +390,7 @@ def convert_settings_dict_for_gui(settings):
|
|
391
390
|
'nucleus_chann_dim': ('combo', chans, None),
|
392
391
|
'pathogen_mask_dim': ('combo', chans, None),
|
393
392
|
'pathogen_chann_dim': ('combo', chans, None),
|
394
|
-
'crop_mode': ('combo', ['cell', 'nucleus', 'pathogen', '
|
393
|
+
'crop_mode': ('combo', [['cell'], ['nucleus'], ['pathogen'], ['cell', 'nucleus'], ['cell', 'pathogen'], ['nucleus', 'pathogen'], ['cell', 'nucleus', 'pathogen']], ['cell']),
|
395
394
|
'magnification': ('combo', [20, 40, 60], 20),
|
396
395
|
'nucleus_channel': ('combo', chans_v2, None),
|
397
396
|
'cell_channel': ('combo', chans_v2, None),
|
spacr/measure.py
CHANGED
@@ -1028,7 +1028,10 @@ def measure_crop(settings):
|
|
1028
1028
|
return
|
1029
1029
|
|
1030
1030
|
if not isinstance(settings['crop_mode'], list):
|
1031
|
-
print(f"WARNING: crop_mode should be a list with at least one element e.g. ['cell'] or ['cell','nucleus'] or [None]")
|
1031
|
+
print(f"WARNING: crop_mode should be a list with at least one element e.g. ['cell'] or ['cell','nucleus'] or [None] got: {settings['crop_mode']}")
|
1032
|
+
settings['crop_mode'] = [settings['crop_mode']]
|
1033
|
+
settings['crop_mode'] = [str(crop_mode) for crop_mode in settings['crop_mode']]
|
1034
|
+
print(f"Converted crop_mode to list: {settings['crop_mode']}")
|
1032
1035
|
return
|
1033
1036
|
|
1034
1037
|
_save_settings_to_db(settings)
|