spacr 0.1.12__tar.gz → 0.1.16__tar.gz

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 (57) hide show
  1. {spacr-0.1.12/spacr.egg-info → spacr-0.1.16}/PKG-INFO +12 -26
  2. {spacr-0.1.12 → spacr-0.1.16}/README.rst +10 -19
  3. {spacr-0.1.12 → spacr-0.1.16}/setup.py +39 -24
  4. {spacr-0.1.12 → spacr-0.1.16}/spacr/app_annotate.py +2 -3
  5. {spacr-0.1.12 → spacr-0.1.16}/spacr/app_classify.py +16 -11
  6. {spacr-0.1.12 → spacr-0.1.16}/spacr/app_make_masks.py +1 -2
  7. {spacr-0.1.12 → spacr-0.1.16}/spacr/app_make_masks_v2.py +1 -3
  8. {spacr-0.1.12 → spacr-0.1.16}/spacr/app_mask.py +25 -23
  9. {spacr-0.1.12 → spacr-0.1.16}/spacr/app_measure.py +20 -15
  10. {spacr-0.1.12 → spacr-0.1.16}/spacr/gui.py +6 -5
  11. {spacr-0.1.12 → spacr-0.1.16}/spacr/gui_utils.py +101 -81
  12. {spacr-0.1.12 → spacr-0.1.16/spacr.egg-info}/PKG-INFO +12 -26
  13. spacr-0.1.16/spacr.egg-info/entry_points.txt +8 -0
  14. {spacr-0.1.12 → spacr-0.1.16}/spacr.egg-info/requires.txt +1 -6
  15. spacr-0.1.12/spacr.egg-info/entry_points.txt +0 -9
  16. {spacr-0.1.12 → spacr-0.1.16}/LICENSE +0 -0
  17. {spacr-0.1.12 → spacr-0.1.16}/MANIFEST.in +0 -0
  18. {spacr-0.1.12 → spacr-0.1.16}/setup.cfg +0 -0
  19. {spacr-0.1.12 → spacr-0.1.16}/spacr/__init__.py +0 -0
  20. {spacr-0.1.12 → spacr-0.1.16}/spacr/__main__.py +0 -0
  21. {spacr-0.1.12 → spacr-0.1.16}/spacr/chris.py +0 -0
  22. {spacr-0.1.12 → spacr-0.1.16}/spacr/core.py +0 -0
  23. {spacr-0.1.12 → spacr-0.1.16}/spacr/deep_spacr.py +0 -0
  24. {spacr-0.1.12 → spacr-0.1.16}/spacr/graph_learning.py +0 -0
  25. {spacr-0.1.12 → spacr-0.1.16}/spacr/io.py +0 -0
  26. {spacr-0.1.12 → spacr-0.1.16}/spacr/logger.py +0 -0
  27. {spacr-0.1.12 → spacr-0.1.16}/spacr/measure.py +0 -0
  28. {spacr-0.1.12 → spacr-0.1.16}/spacr/models/cp/toxo_plaque_cyto_e25000_X1120_Y1120.CP_model +0 -0
  29. {spacr-0.1.12 → spacr-0.1.16}/spacr/models/cp/toxo_plaque_cyto_e25000_X1120_Y1120.CP_model_settings.csv +0 -0
  30. {spacr-0.1.12 → spacr-0.1.16}/spacr/models/cp/toxo_pv_lumen.CP_model +0 -0
  31. {spacr-0.1.12 → spacr-0.1.16}/spacr/plot.py +0 -0
  32. {spacr-0.1.12 → spacr-0.1.16}/spacr/sequencing.py +0 -0
  33. {spacr-0.1.12 → spacr-0.1.16}/spacr/settings.py +0 -0
  34. {spacr-0.1.12 → spacr-0.1.16}/spacr/sim.py +0 -0
  35. {spacr-0.1.12 → spacr-0.1.16}/spacr/sim_app.py +0 -0
  36. {spacr-0.1.12 → spacr-0.1.16}/spacr/timelapse.py +0 -0
  37. {spacr-0.1.12 → spacr-0.1.16}/spacr/utils.py +0 -0
  38. {spacr-0.1.12 → spacr-0.1.16}/spacr/version.py +0 -0
  39. {spacr-0.1.12 → spacr-0.1.16}/spacr.egg-info/SOURCES.txt +0 -0
  40. {spacr-0.1.12 → spacr-0.1.16}/spacr.egg-info/dependency_links.txt +0 -0
  41. {spacr-0.1.12 → spacr-0.1.16}/spacr.egg-info/top_level.txt +0 -0
  42. {spacr-0.1.12 → spacr-0.1.16}/tests/test_annotate_app.py +0 -0
  43. {spacr-0.1.12 → spacr-0.1.16}/tests/test_core.py +0 -0
  44. {spacr-0.1.12 → spacr-0.1.16}/tests/test_gui_classify_app.py +0 -0
  45. {spacr-0.1.12 → spacr-0.1.16}/tests/test_gui_mask_app.py +0 -0
  46. {spacr-0.1.12 → spacr-0.1.16}/tests/test_gui_measure_app.py +0 -0
  47. {spacr-0.1.12 → spacr-0.1.16}/tests/test_gui_sim_app.py +0 -0
  48. {spacr-0.1.12 → spacr-0.1.16}/tests/test_gui_utils.py +0 -0
  49. {spacr-0.1.12 → spacr-0.1.16}/tests/test_io.py +0 -0
  50. {spacr-0.1.12 → spacr-0.1.16}/tests/test_mask_app.py +0 -0
  51. {spacr-0.1.12 → spacr-0.1.16}/tests/test_measure.py +0 -0
  52. {spacr-0.1.12 → spacr-0.1.16}/tests/test_plot.py +0 -0
  53. {spacr-0.1.12 → spacr-0.1.16}/tests/test_sim.py +0 -0
  54. {spacr-0.1.12 → spacr-0.1.16}/tests/test_timelapse.py +0 -0
  55. {spacr-0.1.12 → spacr-0.1.16}/tests/test_train.py +0 -0
  56. {spacr-0.1.12 → spacr-0.1.16}/tests/test_umap.py +0 -0
  57. {spacr-0.1.12 → spacr-0.1.16}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: spacr
3
- Version: 0.1.12
3
+ Version: 0.1.16
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
@@ -9,7 +9,6 @@ Classifier: Programming Language :: Python :: 3
9
9
  Classifier: License :: OSI Approved :: MIT License
10
10
  Classifier: Operating System :: OS Independent
11
11
  License-File: LICENSE
12
- Requires-Dist: dgl==0.9.1
13
12
  Requires-Dist: torch<3.0,>=2.2.1
14
13
  Requires-Dist: torchvision<1.0,>=0.17.1
15
14
  Requires-Dist: torch-geometric<3.0,>=2.5.1
@@ -40,12 +39,8 @@ Requires-Dist: ttf_opensans>=2020.10.30
40
39
  Requires-Dist: customtkinter<6.0,>=5.2.2
41
40
  Requires-Dist: biopython<2.0,>=1.80
42
41
  Requires-Dist: lxml<6.0,>=5.1.0
43
- Requires-Dist: qtpy<2.5,>=2.4.1
44
- Requires-Dist: superqt<0.7,>=0.6.7
45
- Requires-Dist: pyqt6<6.8,>=6.7.1
46
- Requires-Dist: pyqtgraph<0.14,>=0.13.7
47
42
  Provides-Extra: dev
48
- Requires-Dist: pytest>=3.9; extra == "dev"
43
+ Requires-Dist: pytest<3.11,>=3.9; extra == "dev"
49
44
  Provides-Extra: headless
50
45
  Requires-Dist: opencv-python-headless; extra == "headless"
51
46
  Provides-Extra: full
@@ -67,7 +62,7 @@ Requires-Dist: opencv-python; extra == "full"
67
62
  SpaCr
68
63
  =====
69
64
 
70
- Spatial phenotype analysis of CRISPR-Cas9 screens (SpaCr). The spatial organization of organelles and proteins within cells constitutes a key level of functional regulation. In the context of infectious disease, the spatial relationships between host cell structures and intracellular pathogens are critical to understand host clearance mechanisms and how pathogens evade them. SpaCr is a Python-based software package for generating single-cell image data for deep-learning sub-cellular/cellular phenotypic classification from pooled genetic CRISPR-Cas9 screens. SpaCr provides a flexible toolset to extract single-cell images and measurements from high-content cell painting experiments, train deep-learning models to classify cellular/subcellular phenotypes, simulate, and analyze pooled CRISPR-Cas9 imaging screens.
65
+ Spatial phenotype analysis of CRISPR-Cas9 screens (SpaCr). The spatial organization of organelles and proteins within cells constitutes a key level of functional regulation. In the context of infectious disease, the spatial relationships between host cell structures and intracellular pathogens are critical to understanding host clearance mechanisms and how pathogens evade them. SpaCr is a Python-based software package for generating single-cell image data for deep-learning sub-cellular/cellular phenotypic classification from pooled genetic CRISPR-Cas9 screens. SpaCr provides a flexible toolset to extract single-cell images and measurements from high-content cell painting experiments, train deep-learning models to classify cellular/subcellular phenotypes, simulate, and analyze pooled CRISPR-Cas9 imaging screens.
71
66
 
72
67
  Features
73
68
  --------
@@ -76,9 +71,9 @@ Features
76
71
 
77
72
  - **Object Measurements:** Measurements for each object including scikit-image-regionprops, intensity percentiles, shannon-entropy, pearsons and manders correlations, homogeneity, and radial distribution. Measurements are saved to a SQL database in object-level tables.
78
73
 
79
- - **Crop Images:** Objects (e.g., cells) can be saved as PNGs from the object area or bounding box area of each object. Object paths are saved in a SQL database that can be annotated and used to train CNNs/Transformer models for classification tasks.
74
+ - **Crop Images:** Save objects (cells, nuclei, pathogen, cytoplasm) as images. Object image paths are saved in a SQL database.
80
75
 
81
- - **Train CNNs or Transformers:** Train Torch Convolutional Neural Networks (CNNs) or Transformers to classify single object images. Train Torch models with IRM/ERM, checkpointing.
76
+ - **Train CNNs or Transformers:** Train Torch models to classify single object images.
82
77
 
83
78
  - **Manual Annotation:** Supports manual annotation of single-cell images and segmentation to refine training datasets for training CNNs/Transformers or cellpose, respectively.
84
79
 
@@ -95,29 +90,20 @@ Features
95
90
  Installation
96
91
  ------------
97
92
 
98
- Requires Tkinter for graphical user interface features.
93
+ If using Windows, switch to Linux—it's free, open-source, and better.
99
94
 
100
- Ubuntu
101
- ~~~~~~
95
+ Before installing SpaCr on OSX ensure OpenMP is installed::
102
96
 
103
- Before installing SpaCr, ensure Tkinter is installed:
97
+ brew install libomp
104
98
 
105
- (Tkinter is included with the standard Python installation on macOS, and Windows)
106
-
107
- On Linux:
108
-
109
- ::
99
+ SpaCr GUI requires Tkinter. On Linux, ensure Tkinter is installed. (Tkinter is included with the standard Python installation on macOS and Windows)::
110
100
 
111
101
  sudo apt-get install python3-tk
112
102
 
113
- Install spacr with pip
114
-
115
- ::
103
+ Install SpaCr with pip::
116
104
 
117
105
  pip install spacr
118
106
 
119
- Run spacr GUI:
120
-
121
- ::
107
+ Run SpaCr GUI::
122
108
 
123
- gui
109
+ spacr
@@ -14,7 +14,7 @@
14
14
  SpaCr
15
15
  =====
16
16
 
17
- Spatial phenotype analysis of CRISPR-Cas9 screens (SpaCr). The spatial organization of organelles and proteins within cells constitutes a key level of functional regulation. In the context of infectious disease, the spatial relationships between host cell structures and intracellular pathogens are critical to understand host clearance mechanisms and how pathogens evade them. SpaCr is a Python-based software package for generating single-cell image data for deep-learning sub-cellular/cellular phenotypic classification from pooled genetic CRISPR-Cas9 screens. SpaCr provides a flexible toolset to extract single-cell images and measurements from high-content cell painting experiments, train deep-learning models to classify cellular/subcellular phenotypes, simulate, and analyze pooled CRISPR-Cas9 imaging screens.
17
+ Spatial phenotype analysis of CRISPR-Cas9 screens (SpaCr). The spatial organization of organelles and proteins within cells constitutes a key level of functional regulation. In the context of infectious disease, the spatial relationships between host cell structures and intracellular pathogens are critical to understanding host clearance mechanisms and how pathogens evade them. SpaCr is a Python-based software package for generating single-cell image data for deep-learning sub-cellular/cellular phenotypic classification from pooled genetic CRISPR-Cas9 screens. SpaCr provides a flexible toolset to extract single-cell images and measurements from high-content cell painting experiments, train deep-learning models to classify cellular/subcellular phenotypes, simulate, and analyze pooled CRISPR-Cas9 imaging screens.
18
18
 
19
19
  Features
20
20
  --------
@@ -23,9 +23,9 @@ Features
23
23
 
24
24
  - **Object Measurements:** Measurements for each object including scikit-image-regionprops, intensity percentiles, shannon-entropy, pearsons and manders correlations, homogeneity, and radial distribution. Measurements are saved to a SQL database in object-level tables.
25
25
 
26
- - **Crop Images:** Objects (e.g., cells) can be saved as PNGs from the object area or bounding box area of each object. Object paths are saved in a SQL database that can be annotated and used to train CNNs/Transformer models for classification tasks.
26
+ - **Crop Images:** Save objects (cells, nuclei, pathogen, cytoplasm) as images. Object image paths are saved in a SQL database.
27
27
 
28
- - **Train CNNs or Transformers:** Train Torch Convolutional Neural Networks (CNNs) or Transformers to classify single object images. Train Torch models with IRM/ERM, checkpointing.
28
+ - **Train CNNs or Transformers:** Train Torch models to classify single object images.
29
29
 
30
30
  - **Manual Annotation:** Supports manual annotation of single-cell images and segmentation to refine training datasets for training CNNs/Transformers or cellpose, respectively.
31
31
 
@@ -42,29 +42,20 @@ Features
42
42
  Installation
43
43
  ------------
44
44
 
45
- Requires Tkinter for graphical user interface features.
45
+ If using Windows, switch to Linux—it's free, open-source, and better.
46
46
 
47
- Ubuntu
48
- ~~~~~~
47
+ Before installing SpaCr on OSX ensure OpenMP is installed::
49
48
 
50
- Before installing SpaCr, ensure Tkinter is installed:
49
+ brew install libomp
51
50
 
52
- (Tkinter is included with the standard Python installation on macOS, and Windows)
53
-
54
- On Linux:
55
-
56
- ::
51
+ SpaCr GUI requires Tkinter. On Linux, ensure Tkinter is installed. (Tkinter is included with the standard Python installation on macOS and Windows)::
57
52
 
58
53
  sudo apt-get install python3-tk
59
54
 
60
- Install spacr with pip
61
-
62
- ::
55
+ Install SpaCr with pip::
63
56
 
64
57
  pip install spacr
65
58
 
66
- Run spacr GUI:
67
-
68
- ::
59
+ Run SpaCr GUI::
69
60
 
70
- gui
61
+ spacr
@@ -10,19 +10,11 @@ def get_cuda_version():
10
10
  except (subprocess.CalledProcessError, FileNotFoundError):
11
11
  return None
12
12
 
13
- cuda_version = get_cuda_version()
14
-
15
- if cuda_version:
16
- dgl_dependency = f'dgl-cu{cuda_version}==0.9.1' # Specify the version of DGL compatible with your setup
17
- else:
18
- dgl_dependency = 'dgl==0.9.1' # Fallback to CPU version if no CUDA is detected
19
-
20
13
  # Ensure you have read the README.rst content into a variable, e.g., `long_description`
21
14
  with open("README.rst", "r", encoding="utf-8") as fh:
22
15
  long_description = fh.read()
23
16
 
24
17
  dependencies = [
25
- dgl_dependency,
26
18
  'torch>=2.2.1,<3.0',
27
19
  'torchvision>=0.17.1,<1.0',
28
20
  'torch-geometric>=2.5.1,<3.0',
@@ -52,16 +44,12 @@ dependencies = [
52
44
  'ttf_opensans>=2020.10.30',
53
45
  'customtkinter>=5.2.2,<6.0',
54
46
  'biopython>=1.80,<2.0',
55
- 'lxml>=5.1.0,<6.0',
56
- 'qtpy>=2.4.1,<2.5',
57
- 'superqt>=0.6.7,<0.7',
58
- 'pyqt6>=6.7.1,<6.8',
59
- 'pyqtgraph>=0.13.7,<0.14'
47
+ 'lxml>=5.1.0,<6.0'
60
48
  ]
61
49
 
62
50
  setup(
63
51
  name="spacr",
64
- version="0.1.12",
52
+ version="0.1.16",
65
53
  author="Einar Birnir Olafsson",
66
54
  author_email="olafsson@med.umich.com",
67
55
  description="Spatial phenotype analysis of crisp screens (SpaCr)",
@@ -73,18 +61,17 @@ setup(
73
61
  install_requires=dependencies,
74
62
  entry_points={
75
63
  'console_scripts': [
76
- 'mask=spacr.gui_mask_app:gui_mask',
77
- 'measure=spacr.gui_measure_app:gui_measure',
78
- 'make_masks=spacr.gui_make_mask_app:gui_make_masks',
79
- 'make_masks2=spacr.gui_make_mask_app_v2:gui_make_masks',
80
- 'annotate=spacr.annotate_app_v2:gui_annotate',
81
- 'classify=spacr.gui_classify_app:gui_classify',
82
- 'sim=spacr.gui_sim_app:gui_sim',
83
- 'gui=spacr.gui:gui_app',
64
+ 'mask=spacr.app_mask:gui_mask',
65
+ 'measure=spacr.app_measure:gui_measure',
66
+ 'make_masks=spacr.app_make_mask:gui_make_masks',
67
+ 'annotate=spacr.app_annotate:gui_annotate',
68
+ 'classify=spacr.app_classify:gui_classify',
69
+ 'sim=spacr.app_sim:gui_sim',
70
+ 'spacr=spacr.gui:gui_app',
84
71
  ],
85
72
  },
86
73
  extras_require={
87
- 'dev': ['pytest>=3.9'],
74
+ 'dev': ['pytest>=3.9,<3.11'],
88
75
  'headless': ['opencv-python-headless'],
89
76
  'full': ['opencv-python'],
90
77
  },
@@ -93,4 +80,32 @@ setup(
93
80
  "License :: OSI Approved :: MIT License",
94
81
  "Operating System :: OS Independent",
95
82
  ]
96
- )
83
+ )
84
+
85
+ cuda_version = get_cuda_version()
86
+
87
+ if cuda_version:
88
+ dgl = f'dgl-cu{cuda_version}==0.9.1'
89
+ else:
90
+ dgl = 'dgl==0.9.1' # Fallback to CPU version if no CUDA is detected
91
+ try:
92
+ subprocess.run(['pip', 'install', dgl], check=True)
93
+ except subprocess.CalledProcessError:
94
+ subprocess.run(['pip', 'install', 'dgl'], check=True)
95
+
96
+ deps = ['pyqtgraph>=0.13.7,<0.14',
97
+ 'pyqt6>=6.7.1,<6.8',
98
+ 'pyqt6.sip',
99
+ 'qtpy>=2.4.1,<2.5',
100
+ 'superqt>=0.6.7,<0.7',
101
+ 'pyqtgraph',
102
+ 'pyqt6',
103
+ 'pyqt6.sip',
104
+ 'qtpy',
105
+ 'superqt']
106
+
107
+ for dep in deps:
108
+ try:
109
+ subprocess.run(['pip', 'install', dep], check=True)
110
+ except subprocess.CalledProcessError:
111
+ pass
@@ -13,7 +13,7 @@ from IPython.display import display, HTML
13
13
  from tkinter import font as tkFont
14
14
  from tkinter import TclError
15
15
 
16
- from .gui_utils import ScrollableFrame, CustomButton, set_dark_style, set_default_font, style_text_boxes, create_menu_bar
16
+ from .gui_utils import ScrollableFrame, CustomButton, set_dark_style, set_default_font, set_dark_style, create_menu_bar
17
17
 
18
18
  class ImageApp:
19
19
  def __init__(self, root, db_path, src, image_type=None, channels=None, grid_rows=None, grid_cols=None, image_size=(200, 200), annotation_column='annotate', normalize=False, percentiles=(1,99), measurement=None, threshold=None):
@@ -372,7 +372,6 @@ global_image_refs = []
372
372
  def initiate_annotation_app_root(parent_frame):
373
373
  style = ttk.Style(parent_frame)
374
374
  set_dark_style(style)
375
- style_text_boxes(style)
376
375
  set_default_font(parent_frame, font_name="Arial", size=8)
377
376
 
378
377
  parent_frame.configure(bg='black')
@@ -536,4 +535,4 @@ def gui_annotate():
536
535
  root.mainloop()
537
536
 
538
537
  if __name__ == "__main__":
539
- gui_annotate()
538
+ gui_annotate()
@@ -15,8 +15,9 @@ except AttributeError:
15
15
  pass
16
16
 
17
17
  from .logger import log_function_call
18
- from .gui_utils import ScrollableFrame, StdoutRedirector, CustomButton, set_dark_style, set_default_font, generate_fields, process_stdout_stderr, clear_canvas, main_thread_update_function
19
- from .gui_utils import classify_variables, check_classify_gui_settings, train_test_model_wrapper, read_settings_from_csv, update_settings_from_csv, style_text_boxes, create_menu_bar
18
+ from .settings import set_default_train_test_model
19
+ from .gui_utils import ScrollableFrame, StdoutRedirector, CustomButton, set_dark_style, set_default_font, generate_fields, process_stdout_stderr, clear_canvas, main_thread_update_function, convert_settings_dict_for_gui
20
+ from .gui_utils import check_classify_gui_settings, train_test_model_wrapper, read_settings_from_csv, update_settings_from_csv, set_dark_style, create_menu_bar
20
21
 
21
22
  thread_control = {"run_thread": None, "stop_requested": False}
22
23
 
@@ -64,7 +65,8 @@ def import_settings(scrollable_frame):
64
65
 
65
66
  csv_file_path = filedialog.askopenfilename(filetypes=[("CSV files", "*.csv")])
66
67
  csv_settings = read_settings_from_csv(csv_file_path)
67
- variables = classify_variables()
68
+ settings = set_default_train_test_model({})
69
+ variables = convert_settings_dict_for_gui(settings)
68
70
  new_settings = update_settings_from_csv(variables, csv_settings)
69
71
  vars_dict = generate_fields(new_settings, scrollable_frame)
70
72
 
@@ -74,7 +76,6 @@ def initiate_classify_root(parent_frame):
74
76
 
75
77
  style = ttk.Style(parent_frame)
76
78
  set_dark_style(style)
77
- style_text_boxes(style)
78
79
  set_default_font(parent_frame, font_name="Helvetica", size=8)
79
80
 
80
81
  parent_frame.configure(bg='black')
@@ -121,24 +122,28 @@ def initiate_classify_root(parent_frame):
121
122
  vertical_container.add(settings_frame, stretch="always")
122
123
  settings_label = ttk.Label(settings_frame, text="Settings", background="black", foreground="white")
123
124
  settings_label.grid(row=0, column=0, pady=10, padx=10)
124
- scrollable_frame = ScrollableFrame(settings_frame, width=500)
125
+ scrollable_frame = ScrollableFrame(settings_frame, bg='black')
125
126
  scrollable_frame.grid(row=1, column=0, sticky="nsew")
126
127
  settings_frame.grid_rowconfigure(1, weight=1)
127
128
  settings_frame.grid_columnconfigure(0, weight=1)
128
129
 
129
130
  # Setup for user input fields (variables)
130
- variables = classify_variables()
131
+ settings = set_default_train_test_model({})
132
+ variables = convert_settings_dict_for_gui(settings)
131
133
  vars_dict = generate_fields(variables, scrollable_frame)
132
134
 
133
135
  # Button section
134
- import_btn = CustomButton(scrollable_frame.scrollable_frame, text="Import", command=lambda: import_settings(scrollable_frame), font=('Helvetica', 10))
135
- import_btn.grid(row=47, column=0, pady=20, padx=20)
136
+ btn_row = 1
136
137
  run_button = CustomButton(scrollable_frame.scrollable_frame, text="Run", command=lambda: start_process(q, fig_queue), font=('Helvetica', 10))
137
- run_button.grid(row=45, column=0, pady=20, padx=20)
138
+ run_button.grid(row=btn_row, column=0, pady=20, padx=20)
138
139
  abort_button = CustomButton(scrollable_frame.scrollable_frame, text="Abort", command=initiate_abort, font=('Helvetica', 10))
139
- abort_button.grid(row=45, column=1, pady=20, padx=20)
140
+ abort_button.grid(row=btn_row, column=1, pady=20, padx=20)
141
+ btn_row += 1
142
+ import_btn = CustomButton(scrollable_frame.scrollable_frame, text="Import", command=lambda: import_settings(scrollable_frame), font=('Helvetica', 10))
143
+ import_btn.grid(row=btn_row, column=0, pady=20, padx=20)
144
+ btn_row += 1
140
145
  progress_label = ttk.Label(scrollable_frame.scrollable_frame, text="Processing: 0%", background="black", foreground="white") # Create progress field
141
- progress_label.grid(row=50, column=0, columnspan=2, sticky="ew", pady=(5, 0), padx=10)
146
+ progress_label.grid(row=btn_row, column=0, columnspan=2, sticky="ew", pady=(5, 0), padx=10)
142
147
 
143
148
  # Plot Canvas Section
144
149
  plot_frame = tk.PanedWindow(vertical_container, orient=tk.VERTICAL)
@@ -13,7 +13,7 @@ from ttkthemes import ThemedTk
13
13
 
14
14
  from .logger import log_function_call
15
15
 
16
- from .gui_utils import ScrollableFrame, CustomButton, set_dark_style, set_default_font, create_dark_mode, style_text_boxes, create_menu_bar
16
+ from .gui_utils import ScrollableFrame, CustomButton, set_dark_style, set_default_font, set_dark_style, create_menu_bar
17
17
 
18
18
  class modify_masks:
19
19
 
@@ -864,7 +864,6 @@ class modify_masks:
864
864
  def initiate_mask_app_root(parent_frame):
865
865
  style = ttk.Style(parent_frame)
866
866
  set_dark_style(style)
867
- style_text_boxes(style)
868
867
  set_default_font(parent_frame, font_name="Arial", size=8)
869
868
 
870
869
  container = tk.PanedWindow(parent_frame, orient=tk.HORIZONTAL)
@@ -13,7 +13,7 @@ from ttkthemes import ThemedTk
13
13
  from pyqtgraph import GraphicsLayoutWidget, ViewBox, ImageItem, mkQApp
14
14
 
15
15
  from .logger import log_function_call
16
- from .gui_utils import ScrollableFrame, CustomButton, set_dark_style, set_default_font, create_dark_mode, style_text_boxes, create_menu_bar
16
+ from .gui_utils import ScrollableFrame, CustomButton, set_dark_style, set_default_font, create_dark_mode, set_dark_style, create_menu_bar
17
17
 
18
18
  class ModifyMasks:
19
19
  def __init__(self, root, folder_path, scale_factor):
@@ -635,8 +635,6 @@ def initiate_mask_app_root(width, height):
635
635
  root = ThemedTk(theme=theme)
636
636
  style = ttk.Style(root)
637
637
  set_dark_style(style)
638
-
639
- style_text_boxes(style)
640
638
  set_default_font(root, font_name="Arial", size=8)
641
639
  root.geometry(f"{width}x{height}")
642
640
  root.title("Mask App")
@@ -16,9 +16,10 @@ except AttributeError:
16
16
  pass
17
17
 
18
18
  from .logger import log_function_call
19
+ from .settings import set_default_settings_preprocess_generate_masks
19
20
  from .gui_utils import ScrollableFrame, StdoutRedirector, ToggleSwitch, CustomButton, ToolTip
20
- from .gui_utils import clear_canvas, main_thread_update_function, set_dark_style, generate_fields, process_stdout_stderr, set_default_font, style_text_boxes
21
- from .gui_utils import mask_variables, check_mask_gui_settings, preprocess_generate_masks_wrapper, read_settings_from_csv, update_settings_from_csv, create_menu_bar
21
+ from .gui_utils import clear_canvas, main_thread_update_function, set_dark_style, generate_fields, process_stdout_stderr, set_default_font, set_dark_style, convert_settings_dict_for_gui
22
+ from .gui_utils import check_mask_gui_settings, preprocess_generate_masks_wrapper, read_settings_from_csv, update_settings_from_csv, create_menu_bar
22
23
 
23
24
  thread_control = {"run_thread": None, "stop_requested": False}
24
25
 
@@ -37,10 +38,9 @@ def toggle_test_mode():
37
38
  def toggle_advanced_settings():
38
39
  global vars_dict
39
40
 
40
- timelapse_settings = ['timelapse', 'timelapse_memory', 'timelapse_remove_transient', 'timelapse_mode', 'timelapse_objects', 'timelapse_displacement', 'timelapse_frame_limits', 'fps']
41
- misc_settings = ['examples_to_plot', 'all_to_mip', 'pick_slice', 'skip_mode']
42
- opperational_settings = ['preprocess', 'masks', 'randomize', 'batch_size', 'custom_regex', 'merge', 'normalize_plots', 'workers', 'plot', 'remove_background', 'lower_quantile']
43
-
41
+ timelapse_settings = ['timelapse','fps','timelapse_displacement','timelapse_memory','timelapse_frame_limits','timelapse_remove_transient','timelapse_mode','timelapse_objects']
42
+ misc_settings = ['all_to_mip','pick_slice','skip_mode','upscale','upscale_factor','adjust_cells','lower_percentile','filter','merge_pathogens','pathogen_model']
43
+ opperational_settings = ['examples_to_plot','normalize_plots','normalize','cmap','figuresize','plot','pathogen_FT','cell_FT','nucleus_FT','nucleus_CP_prob','nucleus_Signal_to_noise','nucleus_background','cell_CP_prob','cell_Signal_to_noise','cell_background','pathogen_CP_prob','pathogen_Signal_to_noise','pathogen_background','remove_background_pathogen','remove_background_nucleus','remove_background_cell','verbose','randomize','workers','metadata_type','custom_regex','test_images','batch_size','save','masks','preprocess']
44
44
  advanced_settings = timelapse_settings+misc_settings+opperational_settings
45
45
 
46
46
  # Toggle visibility of advanced settings
@@ -94,7 +94,8 @@ def import_settings(scrollable_frame):
94
94
 
95
95
  csv_file_path = filedialog.askopenfilename(filetypes=[("CSV files", "*.csv")])
96
96
  csv_settings = read_settings_from_csv(csv_file_path)
97
- variables = mask_variables()
97
+ settings = set_default_settings_preprocess_generate_masks({})
98
+ variables = convert_settings_dict_for_gui(settings)
98
99
  new_settings = update_settings_from_csv(variables, csv_settings)
99
100
  vars_dict = generate_fields(new_settings, scrollable_frame)
100
101
 
@@ -104,7 +105,6 @@ def initiate_mask_root(parent_frame):
104
105
 
105
106
  style = ttk.Style(parent_frame)
106
107
  set_dark_style(style)
107
- style_text_boxes(style)
108
108
  set_default_font(parent_frame, font_name="Helvetica", size=8)
109
109
  parent_frame.configure(bg='black')
110
110
  parent_frame.grid_rowconfigure(0, weight=1)
@@ -151,7 +151,7 @@ def initiate_mask_root(parent_frame):
151
151
  for widget in parent_frame.winfo_children():
152
152
  widget.destroy()
153
153
 
154
- vertical_container = tk.PanedWindow(parent_frame, orient=tk.HORIZONTAL)
154
+ vertical_container = tk.PanedWindow(parent_frame, orient=tk.HORIZONTAL, bg='black')
155
155
  vertical_container.grid(row=0, column=0, sticky=tk.NSEW)
156
156
  parent_frame.grid_rowconfigure(0, weight=1)
157
157
  parent_frame.grid_columnconfigure(0, weight=1)
@@ -159,9 +159,9 @@ def initiate_mask_root(parent_frame):
159
159
  # Settings Section
160
160
  settings_frame = tk.Frame(vertical_container, bg='black')
161
161
  vertical_container.add(settings_frame, stretch="always")
162
- settings_label = ttk.Label(settings_frame, text="Settings", style="Custom.TLabel")
162
+ settings_label = ttk.Label(settings_frame, text="Settings", style="Custom.TLabel", background="black", foreground="white")
163
163
  settings_label.grid(row=0, column=0, pady=10, padx=10)
164
- scrollable_frame = ScrollableFrame(settings_frame, width=600)
164
+ scrollable_frame = ScrollableFrame(settings_frame, bg='black')
165
165
  scrollable_frame.grid(row=1, column=0, sticky="nsew")
166
166
  settings_frame.grid_rowconfigure(1, weight=1)
167
167
  settings_frame.grid_columnconfigure(0, weight=1)
@@ -169,25 +169,27 @@ def initiate_mask_root(parent_frame):
169
169
  # Create advanced settings checkbox
170
170
  advanced_var = tk.BooleanVar(value=False)
171
171
  advanced_Toggle = ToggleSwitch(scrollable_frame.scrollable_frame, text="Advanced Settings", variable=advanced_var, command=toggle_advanced_settings)
172
- advanced_Toggle.grid(row=48, column=0, pady=10, padx=10)
173
- variables = mask_variables()
172
+ advanced_Toggle.grid(row=4, column=0, pady=10, padx=10)
173
+ settings = set_default_settings_preprocess_generate_masks({})
174
+ variables = convert_settings_dict_for_gui(settings)
174
175
  vars_dict = generate_fields(variables, scrollable_frame)
175
176
  toggle_advanced_settings()
176
177
  vars_dict['Test mode'] = (None, None, tk.BooleanVar(value=False))
177
-
178
- # Button section
179
- test_mode_button = CustomButton(scrollable_frame.scrollable_frame, text="Test Mode", command=toggle_test_mode, font=('Helvetica', 10))
180
- #CustomButton(buttons_frame, text=app_name, command=lambda app_name=app_name: self.load_app(app_name, app_func), font=('Helvetica', 12))
181
178
 
182
- test_mode_button.grid(row=47, column=1, pady=10, padx=10)
183
- import_btn = CustomButton(scrollable_frame.scrollable_frame, text="Import", command=lambda: import_settings(scrollable_frame), font=('Helvetica', 10))
184
- import_btn.grid(row=47, column=0, pady=10, padx=10)
179
+ # Button section
180
+ btn_row = 1
185
181
  run_button = CustomButton(scrollable_frame.scrollable_frame, text="Run", command=lambda: start_process(q, fig_queue))
186
- run_button.grid(row=45, column=0, pady=10, padx=10)
182
+ run_button.grid(row=btn_row, column=0, pady=5, padx=5)
187
183
  abort_button = CustomButton(scrollable_frame.scrollable_frame, text="Abort", command=initiate_abort, font=('Helvetica', 10))
188
- abort_button.grid(row=45, column=1, pady=10, padx=10)
184
+ abort_button.grid(row=btn_row, column=1, pady=5, padx=5)
185
+ btn_row += 1
186
+ test_mode_button = CustomButton(scrollable_frame.scrollable_frame, text="Test", command=toggle_test_mode, font=('Helvetica', 10))
187
+ test_mode_button.grid(row=btn_row, column=0, pady=5, padx=5)
188
+ import_btn = CustomButton(scrollable_frame.scrollable_frame, text="Import", command=lambda: import_settings(scrollable_frame), font=('Helvetica', 10))
189
+ import_btn.grid(row=btn_row, column=1, pady=5, padx=5)
190
+ btn_row += 1
189
191
  progress_label = ttk.Label(scrollable_frame.scrollable_frame, text="Processing: 0%", background="black", foreground="white")
190
- progress_label.grid(row=50, column=0, columnspan=2, sticky="ew", pady=(5, 0), padx=10)
192
+ progress_label.grid(row=btn_row, column=0, columnspan=2, sticky="ew", pady=(5, 0), padx=10)
191
193
 
192
194
  # Plot Canvas Section
193
195
  plot_frame = tk.PanedWindow(vertical_container, orient=tk.VERTICAL)
@@ -13,9 +13,10 @@ except AttributeError:
13
13
  pass
14
14
 
15
15
  from .logger import log_function_call
16
- from .gui_utils import ScrollableFrame, StdoutRedirector, CustomButton, ToggleSwitch, ToolTip
17
- from .gui_utils import process_stdout_stderr, set_dark_style, set_default_font, generate_fields, main_thread_update_function, create_menu_bar
18
- from .gui_utils import measure_variables, measure_crop_wrapper, clear_canvas, check_measure_gui_settings, read_settings_from_csv, update_settings_from_csv, style_text_boxes
16
+ from .settings import get_measure_crop_settings
17
+ from .gui_utils import ScrollableFrame, StdoutRedirector, CustomButton, ToggleSwitch
18
+ from .gui_utils import process_stdout_stderr, set_dark_style, set_default_font, generate_fields, main_thread_update_function, create_menu_bar, convert_settings_dict_for_gui
19
+ from .gui_utils import measure_crop_wrapper, clear_canvas, check_measure_gui_settings, read_settings_from_csv, update_settings_from_csv, set_dark_style
19
20
 
20
21
  thread_control = {"run_thread": None, "stop_requested": False}
21
22
 
@@ -24,7 +25,8 @@ def import_settings(scrollable_frame):
24
25
 
25
26
  csv_file_path = filedialog.askopenfilename(filetypes=[("CSV files", "*.csv")])
26
27
  csv_settings = read_settings_from_csv(csv_file_path)
27
- variables = measure_variables()
28
+ settings = get_measure_crop_settings({})
29
+ variables = convert_settings_dict_for_gui(settings)
28
30
  new_settings = update_settings_from_csv(variables, csv_settings)
29
31
  vars_dict = generate_fields(new_settings, scrollable_frame)
30
32
 
@@ -102,7 +104,6 @@ def initiate_measure_root(parent_frame):
102
104
 
103
105
  style = ttk.Style(parent_frame)
104
106
  set_dark_style(style)
105
- style_text_boxes(style)
106
107
  set_default_font(parent_frame, font_name="Helvetica", size=8)
107
108
 
108
109
  parent_frame.configure(bg='black')
@@ -160,7 +161,7 @@ def initiate_measure_root(parent_frame):
160
161
  vertical_container.add(settings_frame, stretch="always")
161
162
  settings_label = ttk.Label(settings_frame, text="Settings", background="black", foreground="white")
162
163
  settings_label.grid(row=0, column=0, pady=10, padx=10)
163
- scrollable_frame = ScrollableFrame(settings_frame, width=500)
164
+ scrollable_frame = ScrollableFrame(settings_frame, bg='black')
164
165
  scrollable_frame.grid(row=1, column=0, sticky="nsew")
165
166
  settings_frame.grid_rowconfigure(1, weight=1)
166
167
  settings_frame.grid_columnconfigure(0, weight=1)
@@ -168,23 +169,27 @@ def initiate_measure_root(parent_frame):
168
169
  # Create advanced settings checkbox
169
170
  advanced_var = tk.BooleanVar(value=False)
170
171
  advanced_Toggle = ToggleSwitch(scrollable_frame.scrollable_frame, text="Advanced Settings", variable=advanced_var, command=toggle_advanced_settings)
171
- advanced_Toggle.grid(row=48, column=0, pady=10, padx=10)
172
- variables = measure_variables()
172
+ advanced_Toggle.grid(row=4, column=0, pady=10, padx=10)
173
+ settings = get_measure_crop_settings({})
174
+ variables = convert_settings_dict_for_gui(settings)
173
175
  vars_dict = generate_fields(variables, scrollable_frame)
174
176
  toggle_advanced_settings()
175
177
  vars_dict['Test mode'] = (None, None, tk.BooleanVar(value=False))
176
178
 
177
179
  # Button section
178
- test_mode_button = CustomButton(scrollable_frame.scrollable_frame, text="Test Mode", command=toggle_test_mode)
179
- test_mode_button.grid(row=47, column=1, pady=10, padx=10)
180
- import_btn = CustomButton(scrollable_frame.scrollable_frame, text="Import", command=lambda: import_settings(scrollable_frame), font=('Helvetica', 10))
181
- import_btn.grid(row=47, column=0, pady=20, padx=20)
180
+ btn_row = 1
182
181
  run_button = CustomButton(scrollable_frame.scrollable_frame, text="Run", command=lambda: start_process(q, fig_queue), font=('Helvetica', 10))
183
- run_button.grid(row=45, column=0, pady=20, padx=20)
182
+ run_button.grid(row=btn_row, column=0, pady=5, padx=5)
184
183
  abort_button = CustomButton(scrollable_frame.scrollable_frame, text="Abort", command=initiate_abort, font=('Helvetica', 10))
185
- abort_button.grid(row=45, column=1, pady=20, padx=20)
184
+ abort_button.grid(row=btn_row, column=1, pady=5, padx=5)
185
+ btn_row += 1
186
+ test_mode_button = CustomButton(scrollable_frame.scrollable_frame, text="Test Mode", command=toggle_test_mode)
187
+ test_mode_button.grid(row=btn_row, column=0, pady=5, padx=5)
188
+ import_btn = CustomButton(scrollable_frame.scrollable_frame, text="Import", command=lambda: import_settings(scrollable_frame), font=('Helvetica', 10))
189
+ import_btn.grid(row=btn_row, column=1, pady=5, padx=5)
190
+ btn_row += 1
186
191
  progress_label = ttk.Label(scrollable_frame.scrollable_frame, text="Processing: 0%", background="black", foreground="white") # Create progress field
187
- progress_label.grid(row=50, column=0, columnspan=2, sticky="ew", pady=(5, 0), padx=10)
192
+ progress_label.grid(row=btn_row, column=0, columnspan=2, sticky="ew", pady=(5, 0), padx=10)
188
193
 
189
194
  # Plot Canvas Section
190
195
  plot_frame = tk.PanedWindow(vertical_container, orient=tk.VERTICAL)
@@ -11,7 +11,7 @@ from .app_measure import initiate_measure_root
11
11
  from .app_annotate import initiate_annotation_app_root
12
12
  from .app_make_masks import initiate_mask_app_root
13
13
  from .app_classify import initiate_classify_root
14
- from .gui_utils import CustomButton, style_text_boxes, create_menu_bar
14
+ from .gui_utils import CustomButton, set_dark_style, create_menu_bar
15
15
 
16
16
  class MainApp(tk.Tk):
17
17
  def __init__(self):
@@ -22,7 +22,7 @@ class MainApp(tk.Tk):
22
22
  self.title("SpaCr GUI Collection")
23
23
  self.configure(bg="black")
24
24
  style = ttk.Style()
25
- style_text_boxes(style)
25
+ set_dark_style(style)
26
26
 
27
27
  self.gui_apps = {
28
28
  "Mask": (initiate_mask_root, "Generate cellpose masks for cells, nuclei and pathogen images."),
@@ -74,7 +74,7 @@ class MainApp(tk.Tk):
74
74
  app_func, app_desc = app_data
75
75
 
76
76
  # Create custom button with text
77
- button = CustomButton(buttons_frame, text=app_name, command=lambda app_name=app_name: self.load_app(app_name, app_func), font=('Helvetica', 12))
77
+ button = CustomButton(buttons_frame, text=app_name, command=lambda app_name=app_name, app_func=app_func: self.load_app(app_name, app_func), font=('Helvetica', 12))
78
78
  button.grid(row=i, column=0, pady=10, padx=10, sticky="w")
79
79
 
80
80
  description_label = tk.Label(buttons_frame, text=app_desc, bg="black", fg="white", wraplength=800, justify="left", font=('Helvetica', 12))
@@ -100,7 +100,6 @@ class MainApp(tk.Tk):
100
100
 
101
101
  try:
102
102
  img_path = os.path.join(os.path.dirname(__file__), 'logo_spacr.png')
103
- print(f"Trying to load logo from {img_path}")
104
103
  logo_image = Image.open(img_path)
105
104
  except (FileNotFoundError, Image.UnidentifiedImageError):
106
105
  print(f"File {img_path} not found or is not a valid image. Attempting to download from GitHub.")
@@ -117,7 +116,9 @@ class MainApp(tk.Tk):
117
116
  print(f"An error occurred while loading the logo: {e}")
118
117
  return False
119
118
  try:
120
- logo_image = logo_image.resize((800, 800), Image.Resampling.LANCZOS)
119
+ screen_height = frame.winfo_screenheight()
120
+ new_height = int(screen_height // 4)
121
+ logo_image = logo_image.resize((new_height, new_height), Image.Resampling.LANCZOS)
121
122
  logo_photo = ImageTk.PhotoImage(logo_image)
122
123
  logo_label = tk.Label(frame, image=logo_photo, bg="black")
123
124
  logo_label.image = logo_photo # Keep a reference to avoid garbage collection
@@ -10,7 +10,6 @@ from torchvision import models
10
10
 
11
11
  from tkinter import font as tkFont
12
12
 
13
-
14
13
  from .logger import log_function_call
15
14
 
16
15
  try:
@@ -147,7 +146,6 @@ def load_app(root, app_name, app_func):
147
146
  else:
148
147
  proceed_with_app(root, app_name, app_func)
149
148
 
150
-
151
149
  def create_menu_bar(root):
152
150
  from .app_mask import initiate_mask_root
153
151
  from .app_measure import initiate_measure_root
@@ -188,14 +186,19 @@ class CustomButton(tk.Frame):
188
186
  self.text = text
189
187
  self.command = command
190
188
 
191
- self.canvas = tk.Canvas(self, width=150, height=50, highlightthickness=0, bg="black")
189
+ # Detect screen height and calculate button dimensions
190
+ screen_height = self.winfo_screenheight()
191
+ button_height = screen_height // 50
192
+ button_width = button_height * 3
193
+
194
+ self.canvas = tk.Canvas(self, width=button_width, height=button_height, highlightthickness=0, bg="black")
192
195
  self.canvas.grid(row=0, column=0)
193
196
 
194
- self.button_bg = self.create_rounded_rectangle(0, 0, 150, 50, radius=20, fill="#800080")
197
+ self.button_bg = self.create_rounded_rectangle(0, 0, button_width, button_height, radius=20, fill="#800080")
195
198
 
196
199
  # Use the passed font or default to Helvetica if not provided
197
200
  self.font_style = font if font else tkFont.Font(family="Helvetica", size=12, weight=tkFont.NORMAL)
198
- self.button_text = self.canvas.create_text(75, 25, text=self.text, fill="white", font=self.font_style)
201
+ self.button_text = self.canvas.create_text(button_width // 2, button_height // 2, text=self.text, fill="white", font=self.font_style)
199
202
 
200
203
  self.bind("<Enter>", self.on_enter)
201
204
  self.bind("<Leave>", self.on_leave)
@@ -333,38 +336,6 @@ def set_default_font(root, font_name="Helvetica", size=12):
333
336
  root.option_add("*TLabel.Font", default_font)
334
337
  root.option_add("*TEntry.Font", default_font)
335
338
 
336
- def check_and_download_font_v1():
337
- font_name = "Helvetica"
338
- font_dir = "fonts"
339
- font_path = os.path.join(font_dir, "OpenSans-Regular.ttf")
340
-
341
- # Check if the font is already available
342
- available_fonts = list(tkFont.families())
343
- if font_name not in available_fonts:
344
- print(f"Font '{font_name}' not found. Downloading...")
345
- if not os.path.exists(font_dir):
346
- os.makedirs(font_dir)
347
-
348
- if not os.path.exists(font_path):
349
- url = "https://github.com/google/fonts/blob/main/apache/opensans/OpenSans-Regular.ttf?raw=true"
350
- response = requests.get(url)
351
- with open(font_path, "wb") as f:
352
- f.write(response.content)
353
-
354
- # Load the font
355
- try:
356
- tkFont.nametofont("TkDefaultFont").configure(family=font_name, size=10)
357
- tkFont.nametofont("TkTextFont").configure(family=font_name, size=10)
358
- tkFont.nametofont("TkHeadingFont").configure(family=font_name, size=12)
359
- except tk.TclError:
360
- tkFont.nametofont("TkDefaultFont").configure(family="Helvetica", size=10)
361
- tkFont.nametofont("TkTextFont").configure(family="Helvetica", size=10)
362
- tkFont.nametofont("TkHeadingFont").configure(family="Helvetica", size=12)
363
- else:
364
- tkFont.nametofont("TkDefaultFont").configure(family=font_name, size=10)
365
- tkFont.nametofont("TkTextFont").configure(family=font_name, size=10)
366
- tkFont.nametofont("TkHeadingFont").configure(family=font_name, size=12)
367
-
368
339
  def check_and_download_font():
369
340
  font_name = "Helvetica"
370
341
  font_dir = "fonts"
@@ -382,8 +353,6 @@ def check_and_download_font():
382
353
  response = requests.get(url)
383
354
  with open(font_path, "wb") as f:
384
355
  f.write(response.content)
385
-
386
- # Load the font
387
356
  try:
388
357
  tkFont.nametofont("TkDefaultFont").configure(family=font_name, size=10)
389
358
  tkFont.nametofont("TkTextFont").configure(family=font_name, size=10)
@@ -397,32 +366,39 @@ def check_and_download_font():
397
366
  tkFont.nametofont("TkTextFont").configure(family=font_name, size=10)
398
367
  tkFont.nametofont("TkHeadingFont").configure(family=font_name, size=12)
399
368
 
400
- def style_text_boxes_v1(style):
401
- check_and_download_font()
402
- font_style = tkFont.Font(family="Helvetica", size=10) # Define the Helvetica font
403
- style.configure('TEntry', padding='5 5 5 5', borderwidth=1, relief='solid', fieldbackground='#000000', foreground='#ffffff', font=font_style)
404
- style.configure('TCombobox', fieldbackground='#000000', background='#000000', foreground='#ffffff', font=font_style)
369
+ def set_dark_style_v1(style):
370
+ font_style = tkFont.Font(family="Helvetica", size=10)
371
+ style.configure('TEntry', padding='5 5 5 5', borderwidth=1, relief='solid', fieldbackground='black', foreground='#ffffff', font=font_style)
372
+ style.configure('TCombobox', fieldbackground='black', background='black', foreground='#ffffff', font=font_style)
405
373
  style.configure('Custom.TButton', padding='10 10 10 10', borderwidth=1, relief='solid', background='#008080', foreground='#ffffff', font=font_style)
406
374
  style.map('Custom.TButton',
407
375
  background=[('active', '#66b2b2'), ('disabled', '#004d4d'), ('!disabled', '#008080')],
408
376
  foreground=[('active', '#ffffff'), ('disabled', '#888888')])
409
- style.configure('Custom.TLabel', padding='5 5 5 5', borderwidth=1, relief='flat', background='#000000', foreground='#ffffff', font=font_style)
377
+ style.configure('Custom.TLabel', padding='5 5 5 5', borderwidth=1, relief='flat', background='black', foreground='#ffffff', font=font_style)
410
378
  style.configure('TCheckbutton', background='black', foreground='#ffffff', indicatoron=False, relief='flat', font=font_style)
411
379
  style.map('TCheckbutton', background=[('selected', '#555555'), ('active', '#555555')])
412
380
 
413
- def style_text_boxes(style):
381
+ def set_dark_style(style):
414
382
  font_style = tkFont.Font(family="Helvetica", size=10)
415
- style.configure('TEntry', padding='5 5 5 5', borderwidth=1, relief='solid', fieldbackground='black', foreground='#ffffff', font=font_style)
416
- style.configure('TCombobox', fieldbackground='black', background='black', foreground='#ffffff', font=font_style)
417
- style.configure('Custom.TButton', padding='10 10 10 10', borderwidth=1, relief='solid', background='#008080', foreground='#ffffff', font=font_style)
383
+ style.configure('TEntry', padding='5 5 5 5', borderwidth=1, relief='solid', fieldbackground='black', foreground='#ffffff', font=font_style) # Entry
384
+ style.configure('TCombobox', fieldbackground='black', background='black', foreground='#ffffff', font=font_style) # Combobox
385
+ style.configure('Custom.TButton', padding='10 10 10 10', borderwidth=1, relief='solid', background='#008080', foreground='#ffffff', font=font_style) # Custom Button
418
386
  style.map('Custom.TButton',
419
387
  background=[('active', '#66b2b2'), ('disabled', '#004d4d'), ('!disabled', '#008080')],
420
388
  foreground=[('active', '#ffffff'), ('disabled', '#888888')])
421
- style.configure('Custom.TLabel', padding='5 5 5 5', borderwidth=1, relief='flat', background='#000000', foreground='#ffffff', font=font_style)
422
- style.configure('TCheckbutton', background='black', foreground='#ffffff', indicatoron=False, relief='flat', font=font_style)
389
+ style.configure('Custom.TLabel', padding='5 5 5 5', borderwidth=1, relief='flat', background='black', foreground='#ffffff', font=font_style) # Custom Label
390
+ style.configure('TCheckbutton', background='black', foreground='#ffffff', indicatoron=False, relief='flat', font=font_style) # Checkbutton
423
391
  style.map('TCheckbutton', background=[('selected', '#555555'), ('active', '#555555')])
424
-
425
-
392
+ style.configure('TLabel', background='black', foreground='#ffffff', font=font_style) # Label
393
+ style.configure('TFrame', background='black') # Frame
394
+ style.configure('TPanedwindow', background='black') # PanedWindow
395
+ style.configure('TNotebook', background='black', tabmargins=[2, 5, 2, 0]) # Notebook
396
+ style.configure('TNotebook.Tab', background='black', foreground='#ffffff', padding=[5, 5], font=font_style)
397
+ style.map('TNotebook.Tab', background=[('selected', '#555555'), ('active', '#555555')])
398
+ style.configure('TButton', background='black', foreground='#ffffff', padding='5 5 5 5', font=font_style) # Button (regular)
399
+ style.map('TButton', background=[('active', '#555555'), ('disabled', '#333333')])
400
+ style.configure('Vertical.TScrollbar', background='black', troughcolor='black', bordercolor='black') # Scrollbar
401
+ style.configure('Horizontal.TScrollbar', background='black', troughcolor='black', bordercolor='black')
426
402
 
427
403
  def read_settings_from_csv(csv_file_path):
428
404
  settings = {}
@@ -461,36 +437,45 @@ def disable_interactivity(fig):
461
437
  for handler_id in list(handlers.keys()):
462
438
  fig.canvas.mpl_disconnect(handler_id)
463
439
 
464
- class ScrollableFrame(ttk.Frame):
440
+ class ScrollableFrame_v1(ttk.Frame):
465
441
  def __init__(self, container, *args, bg='black', **kwargs):
466
442
  super().__init__(container, *args, **kwargs)
467
- self.configure(style='TFrame') # Ensure this uses the styled frame from dark mode
468
-
469
- canvas = tk.Canvas(self, bg=bg) # Set canvas background to match dark mode
443
+ self.configure(style='TFrame')
444
+ screen_width = self.winfo_screenwidth()
445
+ frame_width = screen_width // 4 # Set the frame width to 1/4th of the screen width
446
+ canvas = tk.Canvas(self, bg=bg, width=frame_width) # Set canvas background to match dark mode
470
447
  scrollbar = ttk.Scrollbar(self, orient="vertical", command=canvas.yview)
471
-
472
- self.scrollable_frame = ttk.Frame(canvas, style='TFrame') # Ensure it uses the styled frame
448
+ self.scrollable_frame = ttk.Frame(canvas, style='TFrame', padding=5) # Ensure it uses the styled frame
473
449
  self.scrollable_frame.bind(
474
450
  "<Configure>",
475
451
  lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
476
452
  )
477
-
478
453
  canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")
479
454
  canvas.configure(yscrollcommand=scrollbar.set)
480
-
481
455
  canvas.pack(side="left", fill="both", expand=True)
482
456
  scrollbar.pack(side="right", fill="y")
483
457
 
484
- class StdoutRedirector_v1(object):
485
- def __init__(self, text_widget):
486
- self.text_widget = text_widget
487
-
488
- def write(self, string):
489
- self.text_widget.insert(tk.END, string)
490
- self.text_widget.see(tk.END)
491
-
492
- def flush(self):
493
- pass
458
+ class ScrollableFrame(ttk.Frame):
459
+ def __init__(self, container, width=None, *args, bg='black', **kwargs):
460
+ super().__init__(container, *args, **kwargs)
461
+ self.configure(style='TFrame')
462
+ if width is None:
463
+ screen_width = self.winfo_screenwidth()
464
+ width = screen_width // 4
465
+ canvas = tk.Canvas(self, bg=bg, width=width)
466
+ scrollbar = ttk.Scrollbar(self, orient="vertical", command=canvas.yview)
467
+
468
+ self.scrollable_frame = ttk.Frame(canvas, style='TFrame')
469
+ self.scrollable_frame.bind(
470
+ "<Configure>",
471
+ lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
472
+ )
473
+ canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")
474
+ canvas.configure(yscrollcommand=scrollbar.set)
475
+ canvas.pack(side="left", fill="both", expand=True)
476
+ scrollbar.pack(side="right", fill="y")
477
+ for child in self.scrollable_frame.winfo_children():
478
+ child.configure(bg='black')
494
479
 
495
480
  class StdoutRedirector:
496
481
  def __init__(self, text_widget):
@@ -793,7 +778,7 @@ def create_input_field(frame, label_text, row, var_type='entry', options=None, d
793
778
  return (label, entry, var) # Return both the label and the entry, and the variable
794
779
  elif var_type == 'check':
795
780
  var = tk.BooleanVar(value=default_value) # Set default value (True/False)
796
- check = ToggleSwitch(frame, text=label_text, variable=var) # Use ToggleSwitch class
781
+ check = ToggleSwitch(frame, text="", variable=var) # Use ToggleSwitch class
797
782
  check.grid(column=1, row=row, sticky=tk.W, padx=5)
798
783
  return (label, check, var) # Return both the label and the checkbutton, and the variable
799
784
  elif var_type == 'combo':
@@ -806,10 +791,43 @@ def create_input_field(frame, label_text, row, var_type='entry', options=None, d
806
791
  else:
807
792
  var = None # Placeholder in case of an undefined var_type
808
793
  return (label, None, var)
794
+
795
+ def convert_settings_dict_for_gui(settings):
796
+ variables = {}
797
+ special_cases = {
798
+ 'metadata_type': ('combo', ['cellvoyager', 'cq1', 'nikon', 'zeis', 'custom'], 'cellvoyager'),
799
+ 'channels': ('combo', ['[0,1,2,3]', '[0,1,2]', '[0,1]', '[0]'], '[0,1,2,3]'),
800
+ 'magnification': ('combo', [20, 40, 60], 20),
801
+ 'nucleus_channel': ('combo', [0, 1, 2, 3, None], None),
802
+ 'cell_channel': ('combo', [0, 1, 2, 3, None], None),
803
+ 'pathogen_channel': ('combo', [0, 1, 2, 3, None], None),
804
+ 'timelapse_mode': ('combo', ['trackpy', 'btrack'], 'trackpy'),
805
+ 'timelapse_objects': ('combo', ['cell', 'nucleus', 'pathogen', 'cytoplasm', None], None),
806
+ 'model_type': ('combo', ['resnet50', 'other_model'], 'resnet50'),
807
+ 'optimizer_type': ('combo', ['adamw', 'adam'], 'adamw'),
808
+ 'schedule': ('combo', ['reduce_lr_on_plateau', 'step_lr'], 'reduce_lr_on_plateau'),
809
+ 'loss_type': ('combo', ['focal_loss', 'binary_cross_entropy_with_logits'], 'focal_loss'),
810
+ 'normalize_by': ('combo', ['fov', 'png'], 'png'),
811
+ }
812
+ for key, value in settings.items():
813
+ if key in special_cases:
814
+ variables[key] = special_cases[key]
815
+ elif isinstance(value, bool):
816
+ variables[key] = ('check', None, value)
817
+ elif isinstance(value, int) or isinstance(value, float):
818
+ variables[key] = ('entry', None, value)
819
+ elif isinstance(value, str):
820
+ variables[key] = ('entry', None, value)
821
+ elif value is None:
822
+ variables[key] = ('entry', None, value)
823
+ elif isinstance(value, list):
824
+ variables[key] = ('entry', None, str(value))
825
+ return variables
809
826
 
810
827
  def mask_variables():
811
828
  variables = {
812
- 'src': ('entry', None, '/mnt/data/CellVoyager/40x/einar/mitotrackerHeLaToxoDsRed_20240224_123156/test_gui'),
829
+ 'src': ('entry', None, 'path/to/images'),
830
+ 'pathogen_model': ('entry', None, 'path/to/model'),
813
831
  'metadata_type': ('combo', ['cellvoyager', 'cq1', 'nikon', 'zeis', 'custom'], 'cellvoyager'),
814
832
  'custom_regex': ('entry', None, None),
815
833
  'experiment': ('entry', None, 'exp'),
@@ -819,14 +837,17 @@ def mask_variables():
819
837
  'nucleus_background': ('entry', None, 100),
820
838
  'nucleus_Signal_to_noise': ('entry', None, 5),
821
839
  'nucleus_CP_prob': ('entry', None, 0),
840
+ 'remove_background_nucleus': ('check', None, False),
822
841
  'cell_channel': ('combo', [0,1,2,3, None], 3),
823
842
  'cell_background': ('entry', None, 100),
824
843
  'cell_Signal_to_noise': ('entry', None, 5),
825
844
  'cell_CP_prob': ('entry', None, 0),
845
+ 'remove_background_cell': ('check', None, False),
826
846
  'pathogen_channel': ('combo', [0,1,2,3, None], 2),
827
847
  'pathogen_background': ('entry', None, 100),
828
848
  'pathogen_Signal_to_noise': ('entry', None, 3),
829
849
  'pathogen_CP_prob': ('entry', None, 0),
850
+ 'remove_background_pathogen': ('check', None, False),
830
851
  'preprocess': ('check', None, True),
831
852
  'masks': ('check', None, True),
832
853
  'examples_to_plot': ('entry', None, 1),
@@ -842,7 +863,7 @@ def mask_variables():
842
863
  'fps': ('entry', None, 2),
843
864
  'remove_background': ('check', None, True),
844
865
  'lower_quantile': ('entry', None, 0.01),
845
- 'merge': ('check', None, False),
866
+ #'merge': ('check', None, False),
846
867
  'normalize_plots': ('check', None, True),
847
868
  'all_to_mip': ('check', None, False),
848
869
  'pick_slice': ('check', None, False),
@@ -851,6 +872,11 @@ def mask_variables():
851
872
  'plot': ('check', None, True),
852
873
  'workers': ('entry', None, 30),
853
874
  'verbose': ('check', None, True),
875
+ 'filter': ('check', None, True),
876
+ 'merge_pathogens': ('check', None, True),
877
+ 'adjust_cells': ('check', None, True),
878
+ 'test_images': ('entry', None, 10),
879
+ 'random_test': ('check', None, True),
854
880
  }
855
881
  return variables
856
882
 
@@ -871,7 +897,7 @@ def add_mask_gui_defaults(settings):
871
897
 
872
898
  def generate_fields(variables, scrollable_frame):
873
899
  vars_dict = {}
874
- row = 0
900
+ row = 5
875
901
  tooltips = {
876
902
  "src": "Path to the folder containing the images.",
877
903
  "metadata_type": "Type of metadata to expect in the images. This will determine how the images are processed. If 'custom' is selected, you can provide a custom regex pattern to extract metadata from the image names",
@@ -993,12 +1019,6 @@ def create_dark_mode(root, style, console_output):
993
1019
  if console_output != None:
994
1020
  console_output.config(bg=dark_bg, fg=light_text, insertbackground=light_text) #, font=("Helvetica", 12)
995
1021
  root.configure(bg=dark_bg)
996
-
997
- def set_dark_style(style):
998
- style.configure('TFrame', background='black')
999
- style.configure('TLabel', background='black', foreground='white')
1000
- style.configure('TEntry', background='black', foreground='white')
1001
- style.configure('TCheckbutton', background='black', foreground='white')
1002
1022
 
1003
1023
  ##@log_function_call
1004
1024
  def main_thread_update_function(root, q, fig_queue, canvas_widget, progress_label):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: spacr
3
- Version: 0.1.12
3
+ Version: 0.1.16
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
@@ -9,7 +9,6 @@ Classifier: Programming Language :: Python :: 3
9
9
  Classifier: License :: OSI Approved :: MIT License
10
10
  Classifier: Operating System :: OS Independent
11
11
  License-File: LICENSE
12
- Requires-Dist: dgl==0.9.1
13
12
  Requires-Dist: torch<3.0,>=2.2.1
14
13
  Requires-Dist: torchvision<1.0,>=0.17.1
15
14
  Requires-Dist: torch-geometric<3.0,>=2.5.1
@@ -40,12 +39,8 @@ Requires-Dist: ttf_opensans>=2020.10.30
40
39
  Requires-Dist: customtkinter<6.0,>=5.2.2
41
40
  Requires-Dist: biopython<2.0,>=1.80
42
41
  Requires-Dist: lxml<6.0,>=5.1.0
43
- Requires-Dist: qtpy<2.5,>=2.4.1
44
- Requires-Dist: superqt<0.7,>=0.6.7
45
- Requires-Dist: pyqt6<6.8,>=6.7.1
46
- Requires-Dist: pyqtgraph<0.14,>=0.13.7
47
42
  Provides-Extra: dev
48
- Requires-Dist: pytest>=3.9; extra == "dev"
43
+ Requires-Dist: pytest<3.11,>=3.9; extra == "dev"
49
44
  Provides-Extra: headless
50
45
  Requires-Dist: opencv-python-headless; extra == "headless"
51
46
  Provides-Extra: full
@@ -67,7 +62,7 @@ Requires-Dist: opencv-python; extra == "full"
67
62
  SpaCr
68
63
  =====
69
64
 
70
- Spatial phenotype analysis of CRISPR-Cas9 screens (SpaCr). The spatial organization of organelles and proteins within cells constitutes a key level of functional regulation. In the context of infectious disease, the spatial relationships between host cell structures and intracellular pathogens are critical to understand host clearance mechanisms and how pathogens evade them. SpaCr is a Python-based software package for generating single-cell image data for deep-learning sub-cellular/cellular phenotypic classification from pooled genetic CRISPR-Cas9 screens. SpaCr provides a flexible toolset to extract single-cell images and measurements from high-content cell painting experiments, train deep-learning models to classify cellular/subcellular phenotypes, simulate, and analyze pooled CRISPR-Cas9 imaging screens.
65
+ Spatial phenotype analysis of CRISPR-Cas9 screens (SpaCr). The spatial organization of organelles and proteins within cells constitutes a key level of functional regulation. In the context of infectious disease, the spatial relationships between host cell structures and intracellular pathogens are critical to understanding host clearance mechanisms and how pathogens evade them. SpaCr is a Python-based software package for generating single-cell image data for deep-learning sub-cellular/cellular phenotypic classification from pooled genetic CRISPR-Cas9 screens. SpaCr provides a flexible toolset to extract single-cell images and measurements from high-content cell painting experiments, train deep-learning models to classify cellular/subcellular phenotypes, simulate, and analyze pooled CRISPR-Cas9 imaging screens.
71
66
 
72
67
  Features
73
68
  --------
@@ -76,9 +71,9 @@ Features
76
71
 
77
72
  - **Object Measurements:** Measurements for each object including scikit-image-regionprops, intensity percentiles, shannon-entropy, pearsons and manders correlations, homogeneity, and radial distribution. Measurements are saved to a SQL database in object-level tables.
78
73
 
79
- - **Crop Images:** Objects (e.g., cells) can be saved as PNGs from the object area or bounding box area of each object. Object paths are saved in a SQL database that can be annotated and used to train CNNs/Transformer models for classification tasks.
74
+ - **Crop Images:** Save objects (cells, nuclei, pathogen, cytoplasm) as images. Object image paths are saved in a SQL database.
80
75
 
81
- - **Train CNNs or Transformers:** Train Torch Convolutional Neural Networks (CNNs) or Transformers to classify single object images. Train Torch models with IRM/ERM, checkpointing.
76
+ - **Train CNNs or Transformers:** Train Torch models to classify single object images.
82
77
 
83
78
  - **Manual Annotation:** Supports manual annotation of single-cell images and segmentation to refine training datasets for training CNNs/Transformers or cellpose, respectively.
84
79
 
@@ -95,29 +90,20 @@ Features
95
90
  Installation
96
91
  ------------
97
92
 
98
- Requires Tkinter for graphical user interface features.
93
+ If using Windows, switch to Linux—it's free, open-source, and better.
99
94
 
100
- Ubuntu
101
- ~~~~~~
95
+ Before installing SpaCr on OSX ensure OpenMP is installed::
102
96
 
103
- Before installing SpaCr, ensure Tkinter is installed:
97
+ brew install libomp
104
98
 
105
- (Tkinter is included with the standard Python installation on macOS, and Windows)
106
-
107
- On Linux:
108
-
109
- ::
99
+ SpaCr GUI requires Tkinter. On Linux, ensure Tkinter is installed. (Tkinter is included with the standard Python installation on macOS and Windows)::
110
100
 
111
101
  sudo apt-get install python3-tk
112
102
 
113
- Install spacr with pip
114
-
115
- ::
103
+ Install SpaCr with pip::
116
104
 
117
105
  pip install spacr
118
106
 
119
- Run spacr GUI:
120
-
121
- ::
107
+ Run SpaCr GUI::
122
108
 
123
- gui
109
+ spacr
@@ -0,0 +1,8 @@
1
+ [console_scripts]
2
+ annotate = spacr.app_annotate:gui_annotate
3
+ classify = spacr.app_classify:gui_classify
4
+ make_masks = spacr.app_make_mask:gui_make_masks
5
+ mask = spacr.app_mask:gui_mask
6
+ measure = spacr.app_measure:gui_measure
7
+ sim = spacr.app_sim:gui_sim
8
+ spacr = spacr.gui:gui_app
@@ -1,4 +1,3 @@
1
- dgl==0.9.1
2
1
  torch<3.0,>=2.2.1
3
2
  torchvision<1.0,>=0.17.1
4
3
  torch-geometric<3.0,>=2.5.1
@@ -29,13 +28,9 @@ ttf_opensans>=2020.10.30
29
28
  customtkinter<6.0,>=5.2.2
30
29
  biopython<2.0,>=1.80
31
30
  lxml<6.0,>=5.1.0
32
- qtpy<2.5,>=2.4.1
33
- superqt<0.7,>=0.6.7
34
- pyqt6<6.8,>=6.7.1
35
- pyqtgraph<0.14,>=0.13.7
36
31
 
37
32
  [dev]
38
- pytest>=3.9
33
+ pytest<3.11,>=3.9
39
34
 
40
35
  [full]
41
36
  opencv-python
@@ -1,9 +0,0 @@
1
- [console_scripts]
2
- annotate = spacr.annotate_app_v2:gui_annotate
3
- classify = spacr.gui_classify_app:gui_classify
4
- gui = spacr.gui:gui_app
5
- make_masks = spacr.gui_make_mask_app:gui_make_masks
6
- make_masks2 = spacr.gui_make_mask_app_v2:gui_make_masks
7
- mask = spacr.gui_mask_app:gui_mask
8
- measure = spacr.gui_measure_app:gui_measure
9
- sim = spacr.gui_sim_app:gui_sim
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes