spacr 0.4.12__tar.gz → 0.4.60__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 (267) hide show
  1. {spacr-0.4.12 → spacr-0.4.60}/MANIFEST.in +10 -0
  2. {spacr-0.4.12/spacr.egg-info → spacr-0.4.60}/PKG-INFO +2 -1
  3. {spacr-0.4.12 → spacr-0.4.60}/setup.py +2 -1
  4. {spacr-0.4.12 → spacr-0.4.60}/spacr/core.py +54 -8
  5. {spacr-0.4.12 → spacr-0.4.60}/spacr/deep_spacr.py +2 -3
  6. {spacr-0.4.12 → spacr-0.4.60}/spacr/gui_core.py +259 -75
  7. {spacr-0.4.12 → spacr-0.4.60}/spacr/gui_elements.py +133 -2
  8. {spacr-0.4.12 → spacr-0.4.60}/spacr/gui_utils.py +24 -20
  9. {spacr-0.4.12 → spacr-0.4.60}/spacr/io.py +553 -61
  10. {spacr-0.4.12 → spacr-0.4.60}/spacr/measure.py +11 -12
  11. {spacr-0.4.12 → spacr-0.4.60}/spacr/ml.py +141 -258
  12. {spacr-0.4.12 → spacr-0.4.60}/spacr/plot.py +76 -34
  13. {spacr-0.4.12 → spacr-0.4.60}/spacr/sequencing.py +73 -38
  14. {spacr-0.4.12 → spacr-0.4.60}/spacr/settings.py +160 -93
  15. {spacr-0.4.12 → spacr-0.4.60}/spacr/submodules.py +620 -214
  16. {spacr-0.4.12 → spacr-0.4.60}/spacr/timelapse.py +25 -25
  17. {spacr-0.4.12 → spacr-0.4.60}/spacr/toxo.py +23 -23
  18. {spacr-0.4.12 → spacr-0.4.60}/spacr/utils.py +249 -95
  19. {spacr-0.4.12 → spacr-0.4.60/spacr.egg-info}/PKG-INFO +2 -1
  20. {spacr-0.4.12 → spacr-0.4.60}/spacr.egg-info/requires.txt +1 -0
  21. {spacr-0.4.12 → spacr-0.4.60}/.readthedocs.yaml +0 -0
  22. {spacr-0.4.12 → spacr-0.4.60}/LICENSE +0 -0
  23. {spacr-0.4.12 → spacr-0.4.60}/README.rst +0 -0
  24. {spacr-0.4.12 → spacr-0.4.60}/deploy_docs.sh +0 -0
  25. {spacr-0.4.12 → spacr-0.4.60}/docs/requirements.txt +0 -0
  26. {spacr-0.4.12 → spacr-0.4.60}/docs/source/Makefile +0 -0
  27. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/doctrees/environment.pickle +0 -0
  28. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_sources/index.rst.txt +0 -0
  29. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/_sphinx_javascript_frameworks_compat.js +0 -0
  30. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/basic.css +0 -0
  31. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/css/badge_only.css +0 -0
  32. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/css/fonts/Roboto-Slab-Bold.woff +0 -0
  33. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/css/fonts/Roboto-Slab-Bold.woff2 +0 -0
  34. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/css/fonts/Roboto-Slab-Regular.woff +0 -0
  35. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/css/fonts/Roboto-Slab-Regular.woff2 +0 -0
  36. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/css/fonts/fontawesome-webfont.eot +0 -0
  37. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/css/fonts/fontawesome-webfont.svg +0 -0
  38. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/css/fonts/fontawesome-webfont.ttf +0 -0
  39. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/css/fonts/fontawesome-webfont.woff +0 -0
  40. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/css/fonts/fontawesome-webfont.woff2 +0 -0
  41. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/css/fonts/lato-bold-italic.woff +0 -0
  42. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/css/fonts/lato-bold-italic.woff2 +0 -0
  43. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/css/fonts/lato-bold.woff +0 -0
  44. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/css/fonts/lato-bold.woff2 +0 -0
  45. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/css/fonts/lato-normal-italic.woff +0 -0
  46. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/css/fonts/lato-normal-italic.woff2 +0 -0
  47. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/css/fonts/lato-normal.woff +0 -0
  48. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/css/fonts/lato-normal.woff2 +0 -0
  49. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/css/theme.css +0 -0
  50. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/doctools.js +0 -0
  51. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/documentation_options.js +0 -0
  52. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/file.png +0 -0
  53. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/fonts/Lato/lato-bold.eot +0 -0
  54. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/fonts/Lato/lato-bold.ttf +0 -0
  55. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/fonts/Lato/lato-bold.woff +0 -0
  56. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/fonts/Lato/lato-bold.woff2 +0 -0
  57. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/fonts/Lato/lato-bolditalic.eot +0 -0
  58. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/fonts/Lato/lato-bolditalic.ttf +0 -0
  59. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/fonts/Lato/lato-bolditalic.woff +0 -0
  60. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/fonts/Lato/lato-bolditalic.woff2 +0 -0
  61. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/fonts/Lato/lato-italic.eot +0 -0
  62. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/fonts/Lato/lato-italic.ttf +0 -0
  63. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/fonts/Lato/lato-italic.woff +0 -0
  64. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/fonts/Lato/lato-italic.woff2 +0 -0
  65. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/fonts/Lato/lato-regular.eot +0 -0
  66. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/fonts/Lato/lato-regular.ttf +0 -0
  67. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/fonts/Lato/lato-regular.woff +0 -0
  68. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/fonts/Lato/lato-regular.woff2 +0 -0
  69. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot +0 -0
  70. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf +0 -0
  71. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff +0 -0
  72. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2 +0 -0
  73. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot +0 -0
  74. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf +0 -0
  75. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff +0 -0
  76. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2 +0 -0
  77. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/jquery.js +0 -0
  78. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/js/badge_only.js +0 -0
  79. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/js/theme.js +0 -0
  80. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/js/versions.js +0 -0
  81. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/language_data.js +0 -0
  82. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/minus.png +0 -0
  83. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/plus.png +0 -0
  84. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/pygments.css +0 -0
  85. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/searchtools.js +0 -0
  86. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/_static/sphinx_highlight.js +0 -0
  87. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/genindex.html +0 -0
  88. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/index.html +0 -0
  89. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/objects.inv +0 -0
  90. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/search.html +0 -0
  91. {spacr-0.4.12 → spacr-0.4.60}/docs/source/_build/html/searchindex.js +0 -0
  92. {spacr-0.4.12 → spacr-0.4.60}/docs/source/conf.py +0 -0
  93. {spacr-0.4.12 → spacr-0.4.60}/docs/source/index.rst +0 -0
  94. {spacr-0.4.12 → spacr-0.4.60}/docs/source/make.bat +0 -0
  95. {spacr-0.4.12 → spacr-0.4.60}/environment.yaml +0 -0
  96. {spacr-0.4.12 → spacr-0.4.60}/fonts/OpenSans-Regular.ttf +0 -0
  97. {spacr-0.4.12 → spacr-0.4.60}/path/home/carruthers/datasets/plate1/measurements/measurements.db +0 -0
  98. {spacr-0.4.12 → spacr-0.4.60}/path/home/carruthers/datasets/plate1/settings/measure_crop_settings.csv +0 -0
  99. {spacr-0.4.12 → spacr-0.4.60}/path/settings/preprocess_generate_masks_settings.csv +0 -0
  100. {spacr-0.4.12 → spacr-0.4.60}/requirements.txt +0 -0
  101. {spacr-0.4.12 → spacr-0.4.60}/settings/measure_crop_settings.csv +0 -0
  102. {spacr-0.4.12 → spacr-0.4.60}/setup.cfg +0 -0
  103. {spacr-0.4.12 → spacr-0.4.60}/setup_docs.sh +0 -0
  104. {spacr-0.4.12 → spacr-0.4.60}/source/conf.py +0 -0
  105. {spacr-0.4.12 → spacr-0.4.60}/source/index.rst +0 -0
  106. {spacr-0.4.12 → spacr-0.4.60}/source/modules.rst +0 -0
  107. {spacr-0.4.12 → spacr-0.4.60}/source/setup.rst +0 -0
  108. {spacr-0.4.12 → spacr-0.4.60}/source/spacr.rst +0 -0
  109. {spacr-0.4.12 → spacr-0.4.60}/spacr/__init__.py +0 -0
  110. {spacr-0.4.12 → spacr-0.4.60}/spacr/__main__.py +0 -0
  111. {spacr-0.4.12 → spacr-0.4.60}/spacr/app_annotate.py +0 -0
  112. {spacr-0.4.12 → spacr-0.4.60}/spacr/app_classify.py +0 -0
  113. {spacr-0.4.12 → spacr-0.4.60}/spacr/app_make_masks.py +0 -0
  114. {spacr-0.4.12 → spacr-0.4.60}/spacr/app_mask.py +0 -0
  115. {spacr-0.4.12 → spacr-0.4.60}/spacr/app_measure.py +0 -0
  116. {spacr-0.4.12 → spacr-0.4.60}/spacr/app_sequencing.py +0 -0
  117. {spacr-0.4.12 → spacr-0.4.60}/spacr/app_umap.py +0 -0
  118. {spacr-0.4.12 → spacr-0.4.60}/spacr/cellpose.py +0 -0
  119. {spacr-0.4.12 → spacr-0.4.60}/spacr/chat_bot.py +0 -0
  120. {spacr-0.4.12 → spacr-0.4.60}/spacr/gui.py +0 -0
  121. {spacr-0.4.12 → spacr-0.4.60}/spacr/logger.py +0 -0
  122. {spacr-0.4.12 → spacr-0.4.60}/spacr/mediar.py +0 -0
  123. {spacr-0.4.12 → spacr-0.4.60}/spacr/openai.py +0 -0
  124. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/.gitignore +0 -0
  125. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/LICENSE +0 -0
  126. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/README.md +0 -0
  127. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/SetupDict.py +0 -0
  128. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/config/baseline.json +0 -0
  129. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/config/mediar_example.json +0 -0
  130. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/config/pred/pred_mediar.json +0 -0
  131. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/config/step1_pretraining/phase1.json +0 -0
  132. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/config/step1_pretraining/phase2.json +0 -0
  133. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/config/step2_finetuning/finetuning1.json +0 -0
  134. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/config/step2_finetuning/finetuning2.json +0 -0
  135. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/config/step3_prediction/base_prediction.json +0 -0
  136. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/config/step3_prediction/ensemble_tta.json +0 -0
  137. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/core/BasePredictor.py +0 -0
  138. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/core/BaseTrainer.py +0 -0
  139. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/core/Baseline/Predictor.py +0 -0
  140. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/core/Baseline/Trainer.py +0 -0
  141. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/core/Baseline/__init__.py +0 -0
  142. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/core/Baseline/utils.py +0 -0
  143. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/core/MEDIAR/EnsemblePredictor.py +0 -0
  144. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/core/MEDIAR/Predictor.py +0 -0
  145. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/core/MEDIAR/Trainer.py +0 -0
  146. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/core/MEDIAR/__init__.py +0 -0
  147. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/core/MEDIAR/utils.py +0 -0
  148. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/core/__init__.py +0 -0
  149. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/core/utils.py +0 -0
  150. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/evaluate.py +0 -0
  151. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/generate_mapping.py +0 -0
  152. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/image/examples/img1.tiff +0 -0
  153. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/image/examples/img2.tif +0 -0
  154. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/image/failure_cases.png +0 -0
  155. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/image/mediar_framework.png +0 -0
  156. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/image/mediar_model.PNG +0 -0
  157. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/image/mediar_results.png +0 -0
  158. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/main.py +0 -0
  159. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/predict.py +0 -0
  160. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/requirements.txt +0 -0
  161. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/train_tools/__init__.py +0 -0
  162. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/train_tools/data_utils/__init__.py +0 -0
  163. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/train_tools/data_utils/custom/CellAware.py +0 -0
  164. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/train_tools/data_utils/custom/LoadImage.py +0 -0
  165. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/train_tools/data_utils/custom/NormalizeImage.py +0 -0
  166. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/train_tools/data_utils/custom/__init__.py +0 -0
  167. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/train_tools/data_utils/custom/modalities.pkl +0 -0
  168. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/train_tools/data_utils/datasetter.py +0 -0
  169. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/train_tools/data_utils/transforms.py +0 -0
  170. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/train_tools/data_utils/utils.py +0 -0
  171. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/train_tools/measures.py +0 -0
  172. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/train_tools/models/MEDIARFormer.py +0 -0
  173. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/train_tools/models/__init__.py +0 -0
  174. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/MEDIAR/train_tools/utils.py +0 -0
  175. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/data/lopit.csv +0 -0
  176. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/data/toxoplasma_metadata.csv +0 -0
  177. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/font/open_sans/OFL.txt +0 -0
  178. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/font/open_sans/OpenSans-Italic-VariableFont_wdth,wght.ttf +0 -0
  179. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/font/open_sans/OpenSans-VariableFont_wdth,wght.ttf +0 -0
  180. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/font/open_sans/README.txt +0 -0
  181. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/font/open_sans/static/OpenSans-Bold.ttf +0 -0
  182. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/font/open_sans/static/OpenSans-BoldItalic.ttf +0 -0
  183. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/font/open_sans/static/OpenSans-ExtraBold.ttf +0 -0
  184. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/font/open_sans/static/OpenSans-ExtraBoldItalic.ttf +0 -0
  185. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/font/open_sans/static/OpenSans-Italic.ttf +0 -0
  186. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/font/open_sans/static/OpenSans-Light.ttf +0 -0
  187. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/font/open_sans/static/OpenSans-LightItalic.ttf +0 -0
  188. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/font/open_sans/static/OpenSans-Medium.ttf +0 -0
  189. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/font/open_sans/static/OpenSans-MediumItalic.ttf +0 -0
  190. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/font/open_sans/static/OpenSans-Regular.ttf +0 -0
  191. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/font/open_sans/static/OpenSans-SemiBold.ttf +0 -0
  192. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/font/open_sans/static/OpenSans-SemiBoldItalic.ttf +0 -0
  193. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/font/open_sans/static/OpenSans_Condensed-Bold.ttf +0 -0
  194. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/font/open_sans/static/OpenSans_Condensed-BoldItalic.ttf +0 -0
  195. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/font/open_sans/static/OpenSans_Condensed-ExtraBold.ttf +0 -0
  196. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/font/open_sans/static/OpenSans_Condensed-ExtraBoldItalic.ttf +0 -0
  197. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/font/open_sans/static/OpenSans_Condensed-Italic.ttf +0 -0
  198. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/font/open_sans/static/OpenSans_Condensed-Light.ttf +0 -0
  199. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/font/open_sans/static/OpenSans_Condensed-LightItalic.ttf +0 -0
  200. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/font/open_sans/static/OpenSans_Condensed-Medium.ttf +0 -0
  201. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/font/open_sans/static/OpenSans_Condensed-MediumItalic.ttf +0 -0
  202. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/font/open_sans/static/OpenSans_Condensed-Regular.ttf +0 -0
  203. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/font/open_sans/static/OpenSans_Condensed-SemiBold.ttf +0 -0
  204. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/font/open_sans/static/OpenSans_Condensed-SemiBoldItalic.ttf +0 -0
  205. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-Bold.ttf +0 -0
  206. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-BoldItalic.ttf +0 -0
  207. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-ExtraBold.ttf +0 -0
  208. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-ExtraBoldItalic.ttf +0 -0
  209. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-Italic.ttf +0 -0
  210. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-Light.ttf +0 -0
  211. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-LightItalic.ttf +0 -0
  212. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-Medium.ttf +0 -0
  213. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-MediumItalic.ttf +0 -0
  214. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-Regular.ttf +0 -0
  215. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-SemiBold.ttf +0 -0
  216. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/font/open_sans/static/OpenSans_SemiCondensed-SemiBoldItalic.ttf +0 -0
  217. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/icons/abort.png +0 -0
  218. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/icons/annotate.png +0 -0
  219. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/icons/cellpose_all.png +0 -0
  220. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/icons/cellpose_masks.png +0 -0
  221. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/icons/classify.png +0 -0
  222. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/icons/convert.png +0 -0
  223. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/icons/default.png +0 -0
  224. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/icons/dna_matrix.mp4 +0 -0
  225. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/icons/download.png +0 -0
  226. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/icons/logo.pdf +0 -0
  227. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/icons/logo_spacr.png +0 -0
  228. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/icons/logo_spacr_1.png +0 -0
  229. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/icons/make_masks.png +0 -0
  230. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/icons/map_barcodes.png +0 -0
  231. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/icons/mask.png +0 -0
  232. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/icons/measure.png +0 -0
  233. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/icons/ml_analyze.png +0 -0
  234. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/icons/plaque.png +0 -0
  235. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/icons/recruitment.png +0 -0
  236. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/icons/regression.png +0 -0
  237. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/icons/run.png +0 -0
  238. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/icons/sequencing.png +0 -0
  239. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/icons/settings.png +0 -0
  240. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/icons/train_cellpose.png +0 -0
  241. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/icons/umap.png +0 -0
  242. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/images/plate1_E01_T0001F001L01A01Z01C02.tif +0 -0
  243. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/images/plate1_E01_T0001F001L01A02Z01C01.tif +0 -0
  244. {spacr-0.4.12 → spacr-0.4.60}/spacr/resources/images/plate1_E01_T0001F001L01A03Z01C03.tif +0 -0
  245. {spacr-0.4.12 → spacr-0.4.60}/spacr/sim.py +0 -0
  246. {spacr-0.4.12 → spacr-0.4.60}/spacr/sp_stats.py +0 -0
  247. {spacr-0.4.12 → spacr-0.4.60}/spacr/version.py +0 -0
  248. {spacr-0.4.12 → spacr-0.4.60}/spacr.egg-info/SOURCES.txt +0 -0
  249. {spacr-0.4.12 → spacr-0.4.60}/spacr.egg-info/dependency_links.txt +0 -0
  250. {spacr-0.4.12 → spacr-0.4.60}/spacr.egg-info/entry_points.txt +0 -0
  251. {spacr-0.4.12 → spacr-0.4.60}/spacr.egg-info/top_level.txt +0 -0
  252. {spacr-0.4.12 → spacr-0.4.60}/tests/test_annotate_app.py +0 -0
  253. {spacr-0.4.12 → spacr-0.4.60}/tests/test_core.py +0 -0
  254. {spacr-0.4.12 → spacr-0.4.60}/tests/test_gui_classify_app.py +0 -0
  255. {spacr-0.4.12 → spacr-0.4.60}/tests/test_gui_mask_app.py +0 -0
  256. {spacr-0.4.12 → spacr-0.4.60}/tests/test_gui_measure_app.py +0 -0
  257. {spacr-0.4.12 → spacr-0.4.60}/tests/test_gui_sim_app.py +0 -0
  258. {spacr-0.4.12 → spacr-0.4.60}/tests/test_gui_utils.py +0 -0
  259. {spacr-0.4.12 → spacr-0.4.60}/tests/test_io.py +0 -0
  260. {spacr-0.4.12 → spacr-0.4.60}/tests/test_mask_app.py +0 -0
  261. {spacr-0.4.12 → spacr-0.4.60}/tests/test_measure.py +0 -0
  262. {spacr-0.4.12 → spacr-0.4.60}/tests/test_plot.py +0 -0
  263. {spacr-0.4.12 → spacr-0.4.60}/tests/test_sim.py +0 -0
  264. {spacr-0.4.12 → spacr-0.4.60}/tests/test_timelapse.py +0 -0
  265. {spacr-0.4.12 → spacr-0.4.60}/tests/test_train.py +0 -0
  266. {spacr-0.4.12 → spacr-0.4.60}/tests/test_umap.py +0 -0
  267. {spacr-0.4.12 → spacr-0.4.60}/tests/test_utils.py +0 -0
@@ -35,3 +35,13 @@ prune notebooks
35
35
  prune spacr/notebooks
36
36
  prune spacr/datasets
37
37
 
38
+ # Exclude model files from distribution
39
+ #exclude spacr/resources/models/cp/*
40
+ #prune spacr/resources/models/cp
41
+
42
+ # Exclude all notebooks (including old ones)
43
+ prune notebooks
44
+ prune spacr/notebooks
45
+ prune spacr/notebooks/submodules
46
+ prune spacr/notebooks/old
47
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: spacr
3
- Version: 0.4.12
3
+ Version: 0.4.60
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
@@ -37,6 +37,7 @@ dependencies = [
37
37
  'tifffile>=2023.4.12',
38
38
  'nd2reader>=3.3.0, <4.0',
39
39
  'czifile',
40
+ 'readlif',
40
41
  'imageio>=2.34.0,<3.0',
41
42
  'pingouin>=0.5.5,<1.0',
42
43
  'umap-learn>=0.5.6,<1.0',
@@ -70,7 +71,7 @@ dependencies = [
70
71
 
71
72
  setup(
72
73
  name="spacr",
73
- version="0.4.12",
74
+ version="0.4.60",
74
75
  author="Einar Birnir Olafsson",
75
76
  author_email="olafsson@med.umich.com",
76
77
  description="Spatial phenotype analysis of crisp screens (SpaCr)",
@@ -9,12 +9,11 @@ warnings.filterwarnings("ignore", message="3D stack used, but stitch_threshold=0
9
9
 
10
10
  def preprocess_generate_masks(settings):
11
11
 
12
- from .io import preprocess_img_data, _load_and_concatenate_arrays
12
+ from .io import preprocess_img_data, _load_and_concatenate_arrays, convert_to_yokogawa, convert_separate_files_to_yokogawa
13
13
  from .plot import plot_image_mask_overlay, plot_arrays
14
- from .utils import _pivot_counts_table, check_mask_folder, adjust_cell_masks, print_progress, save_settings, delete_intermedeate_files
14
+ from .utils import _pivot_counts_table, check_mask_folder, adjust_cell_masks, print_progress, save_settings, delete_intermedeate_files, format_path_for_system, normalize_src_path, generate_image_path_map, copy_images_to_consolidated
15
15
  from .settings import set_default_settings_preprocess_generate_masks
16
-
17
-
16
+
18
17
  if 'src' in settings:
19
18
  if not isinstance(settings['src'], (str, list)):
20
19
  ValueError(f'src must be a string or a list of strings')
@@ -23,18 +22,53 @@ def preprocess_generate_masks(settings):
23
22
  ValueError(f'src is a required parameter')
24
23
  return
25
24
 
25
+ settings['src'] = normalize_src_path(settings['src'])
26
+
27
+ if settings['consolidate']:
28
+ image_map = generate_image_path_map(settings['src'])
29
+ copy_images_to_consolidated(image_map, settings['src'])
30
+ settings['src'] = os.path.join(settings['src'], 'consolidated')
31
+
26
32
  if isinstance(settings['src'], str):
27
33
  settings['src'] = [settings['src']]
28
34
 
29
35
  if isinstance(settings['src'], list):
30
36
  source_folders = settings['src']
31
37
  for source_folder in source_folders:
38
+
32
39
  print(f'Processing folder: {source_folder}')
40
+
41
+ source_folder = format_path_for_system(source_folder)
33
42
  settings['src'] = source_folder
34
43
  src = source_folder
35
44
  settings = set_default_settings_preprocess_generate_masks(settings)
45
+
46
+ if settings['metadata_type'] == 'auto':
47
+ if settings['custom_regex'] != None:
48
+ try:
49
+ print(f"using regex: {settings['custom_regex']}")
50
+ convert_separate_files_to_yokogawa(folder=source_folder, regex=settings['custom_regex'])
51
+ except:
52
+ try:
53
+ convert_to_yokogawa(folder=source_folder)
54
+ except Exception as e:
55
+ print(f"Error: Tried to convert image files and image file name metadata with regex {settings['custom_regex']} then without regex but failed both.")
56
+ print(f'Error: {e}')
57
+ return
58
+ else:
59
+ try:
60
+ convert_to_yokogawa(folder=source_folder)
61
+ except Exception as e:
62
+ print(f"Error: Tried to convert image files and image file name metadata without regex but failed.")
63
+ print(f'Error: {e}')
64
+ return
65
+
66
+ if settings['cell_channel'] is None and settings['nucleus_channel'] is None and settings['pathogen_channel'] is None:
67
+ print(f'Error: At least one of cell_channel, nucleus_channel or pathogen_channel must be defined')
68
+ return
69
+
36
70
  save_settings(settings, name='gen_mask_settings')
37
-
71
+
38
72
  if not settings['pathogen_channel'] is None:
39
73
  custom_model_ls = ['toxo_pv_lumen','toxo_cyto']
40
74
  if settings['pathogen_model'] not in custom_model_ls:
@@ -54,7 +88,7 @@ def preprocess_generate_masks(settings):
54
88
  settings_df = pd.DataFrame(list(settings.items()), columns=['setting_key', 'setting_value'])
55
89
  settings_df['setting_value'] = settings_df['setting_value'].apply(str)
56
90
  display(settings_df)
57
-
91
+
58
92
  if settings['test_mode']:
59
93
  print(f'Starting Test mode ...')
60
94
 
@@ -164,6 +198,7 @@ def preprocess_generate_masks(settings):
164
198
  gc.collect()
165
199
 
166
200
  if settings['delete_intermediate']:
201
+ print(f"deleting intermediate files")
167
202
  delete_intermedeate_files(settings)
168
203
 
169
204
  print("Successfully completed run")
@@ -285,6 +320,17 @@ def generate_cellpose_masks(src, settings, object_type):
285
320
  continue
286
321
 
287
322
  batch = prepare_batch_for_segmentation(batch)
323
+
324
+
325
+ #if settings['denoise']:
326
+ # if object_type == 'cell':
327
+ # model_type = "denoise_cyto3"
328
+ # elif object_type == 'nucleus':
329
+ # model_type = "denoise_nucleus"
330
+ # else:
331
+ # raise ValueError(f"No denoise model for object_type: {object_type}")
332
+ # dn = denoise.DenoiseModel(model_type=model_type, gpu=device)
333
+ # batch = dn.eval(imgs=batch, channels=chans, diameter=object_settings['diameter'])
288
334
 
289
335
  if timelapse:
290
336
  movie_path = os.path.join(os.path.dirname(src), 'movies')
@@ -486,7 +532,7 @@ def generate_image_umap(settings={}):
486
532
  all_df = pd.concat([all_df, df], axis=0)
487
533
  #image_paths.extend(image_paths_tmp)
488
534
 
489
- all_df['cond'] = all_df['column_name'].apply(map_condition, neg=settings['neg'], pos=settings['pos'], mix=settings['mix'])
535
+ all_df['cond'] = all_df['columnID'].apply(map_condition, neg=settings['neg'], pos=settings['pos'], mix=settings['mix'])
490
536
 
491
537
  if settings['exclude_conditions']:
492
538
  if isinstance(settings['exclude_conditions'], str):
@@ -670,7 +716,7 @@ def reducer_hyperparameter_search(settings={}, reduction_params=None, dbscan_par
670
716
  df = _read_and_join_tables(db_path, table_names=tables)
671
717
  all_df = pd.concat([all_df, df], axis=0)
672
718
 
673
- all_df['cond'] = all_df['column_name'].apply(map_condition, neg=settings['neg'], pos=settings['pos'], mix=settings['mix'])
719
+ all_df['cond'] = all_df['columnID'].apply(map_condition, neg=settings['neg'], pos=settings['pos'], mix=settings['mix'])
674
720
 
675
721
  if settings['exclude_conditions']:
676
722
  if isinstance(settings['exclude_conditions'], str):
@@ -1144,7 +1144,7 @@ def model_fusion(model_paths,save_path,device='cpu',model_name='maxvit_t',pretra
1144
1144
 
1145
1145
  def annotate_filter_vision(settings):
1146
1146
 
1147
- from .utils import annotate_conditions
1147
+ from .utils import annotate_conditions, correct_metadata
1148
1148
 
1149
1149
  def filter_csv_by_png(csv_file):
1150
1150
  """
@@ -1188,8 +1188,7 @@ def annotate_filter_vision(settings):
1188
1188
 
1189
1189
  df = pd.read_csv(src)
1190
1190
 
1191
- if 'column_name' not in df.columns:
1192
- df['column_name'] = df['column']
1191
+ df = correct_metadata(df)
1193
1192
 
1194
1193
  df = annotate_conditions(df,
1195
1194
  cells=settings['cells'],
@@ -170,68 +170,11 @@ def display_figure(fig):
170
170
  #flash_feedback("right")
171
171
  show_next_figure()
172
172
 
173
- def zoom_v1(event):
174
- nonlocal scale_factor
175
-
176
- zoom_speed = 0.1 # Adjust the zoom speed for smoother experience
177
-
178
- # Determine the zoom direction based on the scroll event
179
- if event.num == 4 or event.delta > 0: # Scroll up (zoom in)
180
- scale_factor /= (1 + zoom_speed) # Divide to zoom in
181
- elif event.num == 5 or event.delta < 0: # Scroll down (zoom out)
182
- scale_factor *= (1 + zoom_speed) # Multiply to zoom out
183
-
184
- # Adjust the axes limits based on the new scale factor
185
- for ax in canvas.figure.get_axes():
186
- xlim = ax.get_xlim()
187
- ylim = ax.get_ylim()
188
-
189
- x_center = (xlim[1] + xlim[0]) / 2
190
- y_center = (ylim[1] + ylim[0]) / 2
191
-
192
- x_range = (xlim[1] - xlim[0]) * scale_factor
193
- y_range = (ylim[1] - ylim[0]) * scale_factor
194
-
195
- # Set the new limits
196
- ax.set_xlim([x_center - x_range / 2, x_center + x_range / 2])
197
- ax.set_ylim([y_center - y_range / 2, y_center + y_range / 2])
198
-
199
- # Redraw the figure efficiently
200
- canvas.draw_idle()
201
-
202
173
  def zoom_test(event):
203
174
  if event.num == 4: # Scroll up
204
175
  print("zoom in")
205
176
  elif event.num == 5: # Scroll down
206
177
  print("zoom out")
207
-
208
- def zoom_2(event):
209
- zoom_speed = 0.1 # Change this to control how fast you zoom
210
-
211
- # Determine the zoom direction based on the scroll event
212
- if event.num == 4 or (hasattr(event, 'delta') and event.delta > 0): # Scroll up = zoom in
213
- factor = 1 - zoom_speed
214
- elif event.num == 5 or (hasattr(event, 'delta') and event.delta < 0): # Scroll down = zoom out
215
- factor = 1 + zoom_speed
216
- else:
217
- return # No recognized scroll direction
218
-
219
- for ax in canvas.figure.get_axes():
220
- xlim = ax.get_xlim()
221
- ylim = ax.get_ylim()
222
-
223
- x_center = (xlim[1] + xlim[0]) / 2
224
- y_center = (ylim[1] + ylim[0]) / 2
225
-
226
- x_range = (xlim[1] - xlim[0]) * factor
227
- y_range = (ylim[1] - ylim[0]) * factor
228
-
229
- # Set the new limits
230
- ax.set_xlim([x_center - x_range / 2, x_center + x_range / 2])
231
- ax.set_ylim([y_center - y_range / 2, y_center + y_range / 2])
232
-
233
- # Redraw the figure efficiently
234
- canvas.draw_idle()
235
178
 
236
179
  def zoom(event):
237
180
  # Fixed zoom factors (adjust these if you want faster or slower zoom)
@@ -247,23 +190,28 @@ def display_figure(fig):
247
190
  return # No recognized scroll direction
248
191
 
249
192
  for ax in canvas.figure.get_axes():
193
+ # Get the current mouse position in pixel coordinates
194
+ mouse_x, mouse_y = event.x, event.y
195
+
196
+ # Convert pixel coordinates to data coordinates
197
+ inv = ax.transData.inverted()
198
+ data_x, data_y = inv.transform((mouse_x, mouse_y))
199
+
200
+ # Get the current axis limits
250
201
  xlim = ax.get_xlim()
251
202
  ylim = ax.get_ylim()
252
203
 
253
- x_center = (xlim[1] + xlim[0]) / 2
254
- y_center = (ylim[1] + ylim[0]) / 2
255
-
204
+ # Calculate the zooming range around the cursor position
256
205
  x_range = (xlim[1] - xlim[0]) * factor
257
206
  y_range = (ylim[1] - ylim[0]) * factor
258
207
 
259
- # Set the new limits
260
- ax.set_xlim([x_center - x_range / 2, x_center + x_range / 2])
261
- ax.set_ylim([y_center - y_range / 2, y_center + y_range / 2])
208
+ # Adjust the limits while keeping the mouse position fixed
209
+ ax.set_xlim([data_x - (data_x - xlim[0]) * factor, data_x + (xlim[1] - data_x) * factor])
210
+ ax.set_ylim([data_y - (data_y - ylim[0]) * factor, data_y + (ylim[1] - data_y) * factor])
262
211
 
263
212
  # Redraw the figure efficiently
264
213
  canvas.draw_idle()
265
214
 
266
-
267
215
  # Bind events for hover, click interactions, and zoom
268
216
  canvas_widget.bind("<Motion>", on_hover)
269
217
  canvas_widget.bind("<Leave>", on_leave)
@@ -854,7 +802,7 @@ def initiate_abort():
854
802
  global thread_control, q, parent_frame
855
803
  if thread_control.get("run_thread") is not None:
856
804
  try:
857
- q.put("Aborting processes...")
805
+ #q.put("Aborting processes...")
858
806
  thread_control.get("run_thread").terminate()
859
807
  thread_control["run_thread"] = None
860
808
  q.put("Processes aborted.")
@@ -862,22 +810,164 @@ def initiate_abort():
862
810
  q.put(f"Error aborting process: {e}")
863
811
 
864
812
  thread_control = {"run_thread": None, "stop_requested": False}
813
+
814
+ def check_src_folders_files(settings, settings_type, q):
815
+ """
816
+ Checks if 'src' is a key in the settings dictionary and if it exists as a valid path.
817
+ If 'src' is a list, iterates through the list and checks each path.
818
+ If any path is missing, prompts the user to edit or remove invalid paths.
819
+ """
820
+
821
+ request_stop = False
822
+
823
+ def _folder_has_images(folder_path, image_extensions = {".png", ".jpg", ".jpeg", ".bmp", ".gif", ".tiff", ".tif", ".webp", ".npy", ".npz", "nd2", "czi", "lif"}):
824
+ """Check if a folder contains any image files."""
825
+ return any(file.lower().endswith(tuple(image_extensions)) for file in os.listdir(folder_path))
826
+
827
+ def _has_folder(parent_folder, sub_folder="measure"):
828
+ """Check if a specific sub-folder exists inside the given folder."""
829
+ return os.path.isdir(os.path.join(parent_folder, sub_folder))
830
+
831
+ from .utils import normalize_src_path, generate_image_path_map
832
+
833
+ settings['src'] = normalize_src_path(settings['src'])
834
+
835
+ src_value = settings.get("src")
836
+
837
+ # **Skip if 'src' is missing**
838
+ if src_value is None:
839
+ return request_stop
840
+
841
+ # Convert single string src to a list for uniform handling
842
+ if isinstance(src_value, str):
843
+ src_list = [src_value]
844
+ elif isinstance(src_value, list):
845
+ src_list = src_value
846
+ else:
847
+ request_stop = True
848
+ return request_stop # Ensure early exit
849
+
850
+ # Identify missing paths
851
+ missing_paths = {i: path for i, path in enumerate(src_list) if not os.path.exists(path)}
852
+
853
+ if missing_paths:
854
+ q.put(f'Error: The following paths are missing: {missing_paths}')
855
+ request_stop = True
856
+ return request_stop # Ensure early exit
857
+
858
+ conditions = [True] # Initialize conditions list
859
+
860
+ for path in src_list: # Fixed: Use src_list instead of src_value
861
+ if settings_type == 'mask':
862
+ if settings['consolidate']:
863
+ image_map = generate_image_path_map(path)
864
+ if len(image_map) > 0:
865
+ request_stop = False
866
+ return request_stop
867
+ else:
868
+ q.put(f"Error: Missing subfolders with images for: {path}")
869
+ request_stop = True
870
+ return request_stop
871
+ else:
872
+ pictures_continue = _folder_has_images(path)
873
+ folder_chan_continue = _has_folder(path, "1")
874
+ folder_stack_continue = _has_folder(path, "stack")
875
+ folder_npz_continue = _has_folder(path, "norm_channel_stack")
876
+
877
+ if not pictures_continue:
878
+ if not any([folder_chan_continue, folder_stack_continue, folder_npz_continue]):
879
+ if not folder_chan_continue:
880
+ q.put(f"Error: Missing channel folder in folder: {path}")
881
+
882
+ if not folder_stack_continue:
883
+ q.put(f"Error: Missing stack folder in folder: {path}")
884
+
885
+ if not folder_npz_continue:
886
+ q.put(f"Error: Missing norm_channel_stack folder in folder: {path}")
887
+ else:
888
+ q.put(f"Error: No images in folder: {path}")
889
+
890
+ #q.put(f"path:{path}")
891
+ #q.put(f"pictures_continue:{pictures_continue}, folder_chan_continue:{folder_chan_continue}, folder_stack_continue:{folder_stack_continue}, folder_npz_continue:{folder_npz_continue}")
892
+
893
+ conditions = [pictures_continue, folder_chan_continue, folder_stack_continue, folder_npz_continue]
894
+
895
+ if settings_type == 'measure':
896
+ if not os.path.basename(path) == 'merged':
897
+ path = os.path.join(path, "merged")
898
+ npy_continue = _folder_has_images(path, image_extensions={".npy"})
899
+ conditions = [npy_continue]
900
+
901
+ #if settings_type == 'recruitment':
902
+ # if not os.path.basename(path) == 'measurements':
903
+ # path = os.path.join(path, "measurements")
904
+ # db_continue = _folder_has_images(path, image_extensions={".db"})
905
+ # conditions = [db_continue]
906
+
907
+ #if settings_type == 'umap':
908
+ # if not os.path.basename(path) == 'measurements':
909
+ # path = os.path.join(path, "measurements")
910
+ # db_continue = _folder_has_images(path, image_extensions={".db"})
911
+ # conditions = [db_continue]
912
+
913
+ #if settings_type == 'analyze_plaques':
914
+ # if not os.path.basename(path) == 'measurements':
915
+ # path = os.path.join(path, "measurements")
916
+ # db_continue = _folder_has_images(path, image_extensions={".db"})
917
+ # conditions = [db_continue]
918
+
919
+ #if settings_type == 'map_barcodes':
920
+ # if not os.path.basename(path) == 'measurements':
921
+ # path = os.path.join(path, "measurements")
922
+ # db_continue = _folder_has_images(path, image_extensions={".db"})
923
+ # conditions = [db_continue]
924
+
925
+ #if settings_type == 'regression':
926
+ # if not os.path.basename(path) == 'measurements':
927
+ # path = os.path.join(path, "measurements")
928
+ # db_continue = _folder_has_images(path, image_extensions={".db"})
929
+ # conditions = [db_continue]
930
+
931
+ #if settings_type == 'classify':
932
+ # if not os.path.basename(path) == 'measurements':
933
+ # path = os.path.join(path, "measurements")
934
+ # db_continue = _folder_has_images(path, image_extensions={".db"})
935
+ # conditions = [db_continue]
936
+
937
+ #if settings_type == 'analyze_plaques':
938
+ # if not os.path.basename(path) == 'measurements':
939
+ # path = os.path.join(path, "measurements")
940
+ # db_continue = _folder_has_images(path, image_extensions={".db"})
941
+ # conditions = [db_continue]
942
+
943
+ if not any(conditions):
944
+ q.put(f"Error: The following path(s) is missing images or folders: {path}")
945
+ request_stop = True
946
+
947
+ return request_stop
865
948
 
866
949
  def start_process(q=None, fig_queue=None, settings_type='mask'):
867
950
  global thread_control, vars_dict, parent_frame
868
951
  from .settings import check_settings, expected_types
869
952
  from .gui_utils import run_function_gui, set_cpu_affinity, initialize_cuda, display_gif_in_plot_frame, print_widget_structure
870
-
953
+
871
954
  if q is None:
872
955
  q = Queue()
873
956
  if fig_queue is None:
874
957
  fig_queue = Queue()
875
958
  try:
876
- settings = check_settings(vars_dict, expected_types, q)
959
+ settings, errors = check_settings(vars_dict, expected_types, q)
960
+
961
+ if len(errors) > 0:
962
+ return
963
+
964
+ if check_src_folders_files(settings, settings_type, q):
965
+ return
966
+
877
967
  except ValueError as e:
878
968
  q.put(f"Error: {e}")
879
969
  return
880
-
970
+
881
971
  if isinstance(thread_control, dict) and thread_control.get("run_thread") is not None:
882
972
  initiate_abort()
883
973
 
@@ -902,10 +992,11 @@ def start_process(q=None, fig_queue=None, settings_type='mask'):
902
992
 
903
993
  # Store the process in thread_control for future reference
904
994
  thread_control["run_thread"] = process
995
+
905
996
  else:
906
997
  q.put(f"Error: Unknown settings type '{settings_type}'")
907
998
  return
908
-
999
+
909
1000
  def process_console_queue():
910
1001
  global q, console_output, parent_frame, progress_bar, process_console_queue
911
1002
 
@@ -916,13 +1007,105 @@ def process_console_queue():
916
1007
  process_console_queue.current_maximum = None
917
1008
 
918
1009
  ansi_escape_pattern = re.compile(r'\x1B\[[0-?]*[ -/]*[@-~]')
1010
+
1011
+ spacing = 5
1012
+
1013
+ # **Configure styles for different message types**
1014
+ console_output.tag_configure("error", foreground="red", spacing3 = spacing)
1015
+ console_output.tag_configure("warning", foreground="orange", spacing3 = spacing)
1016
+ console_output.tag_configure("normal", foreground="white", spacing3 = spacing)
919
1017
 
920
1018
  while not q.empty():
921
1019
  message = q.get_nowait()
922
1020
  clean_message = ansi_escape_pattern.sub('', message)
923
- #console_output.insert(tk.END, clean_message + "\n")
924
- #console_output.see(tk.END)
1021
+
1022
+ # **Detect Error Messages (Red)**
1023
+ if clean_message.startswith("Error:"):
1024
+ console_output.insert(tk.END, clean_message + "\n", "error")
1025
+ console_output.see(tk.END)
1026
+ #print("Run aborted due to error:", clean_message) # Debug message
1027
+ #return # **Exit immediately to stop further execution**
1028
+
1029
+ # **Detect Warning Messages (Orange)**
1030
+ elif clean_message.startswith("Warning:"):
1031
+ console_output.insert(tk.END, clean_message + "\n", "warning")
925
1032
 
1033
+ # **Process Progress Messages Normally**
1034
+ elif clean_message.startswith("Progress:"):
1035
+ try:
1036
+ # Extract the progress information
1037
+ match = re.search(r'Progress: (\d+)/(\d+), operation_type: ([\w\s]*),(.*)', clean_message)
1038
+
1039
+ if match:
1040
+ current_progress = int(match.group(1))
1041
+ total_progress = int(match.group(2))
1042
+ operation_type = match.group(3).strip()
1043
+ additional_info = match.group(4).strip() # Capture everything after operation_type
1044
+
1045
+ # Check if the maximum value has changed
1046
+ if process_console_queue.current_maximum != total_progress:
1047
+ process_console_queue.current_maximum = total_progress
1048
+ process_console_queue.completed_tasks = []
1049
+
1050
+ # Add the task to the completed set
1051
+ process_console_queue.completed_tasks.append(current_progress)
1052
+
1053
+ # Calculate the unique progress count
1054
+ unique_progress_count = len(np.unique(process_console_queue.completed_tasks))
1055
+
1056
+ # Update the progress bar
1057
+ if progress_bar:
1058
+ progress_bar['maximum'] = total_progress
1059
+ progress_bar['value'] = unique_progress_count
1060
+
1061
+ # Store operation type and additional info
1062
+ if operation_type:
1063
+ progress_bar.operation_type = operation_type
1064
+ progress_bar.additional_info = additional_info
1065
+
1066
+ # Update the progress label
1067
+ if progress_bar.progress_label:
1068
+ progress_bar.update_label()
1069
+
1070
+ # Clear completed tasks when progress is complete
1071
+ if unique_progress_count >= total_progress:
1072
+ process_console_queue.completed_tasks.clear()
1073
+
1074
+ except Exception as e:
1075
+ print(f"Error parsing progress message: {e}")
1076
+
1077
+ # **Insert Normal Messages with Extra Line Spacing**
1078
+ else:
1079
+ console_output.insert(tk.END, clean_message + "\n", "normal")
1080
+
1081
+ console_output.see(tk.END)
1082
+
1083
+ # **Continue processing if no error was detected**
1084
+ after_id = console_output.after(uppdate_frequency, process_console_queue)
1085
+ parent_frame.after_tasks.append(after_id)
1086
+
1087
+ def process_console_queue_v2():
1088
+ global q, console_output, parent_frame, progress_bar, process_console_queue
1089
+
1090
+ # Initialize function attribute if it doesn't exist
1091
+ if not hasattr(process_console_queue, "completed_tasks"):
1092
+ process_console_queue.completed_tasks = []
1093
+ if not hasattr(process_console_queue, "current_maximum"):
1094
+ process_console_queue.current_maximum = None
1095
+
1096
+ ansi_escape_pattern = re.compile(r'\x1B\[[0-?]*[ -/]*[@-~]')
1097
+
1098
+ while not q.empty():
1099
+ message = q.get_nowait()
1100
+ clean_message = ansi_escape_pattern.sub('', message)
1101
+
1102
+ # **Abort Execution if an Error Message is Detected**
1103
+ if clean_message.startswith("Error:"):
1104
+ console_output.insert(tk.END, clean_message + "\n", "error")
1105
+ console_output.see(tk.END)
1106
+ print("Run aborted due to error:", clean_message) # Debug message
1107
+ return # **Exit immediately to stop further execution**
1108
+
926
1109
  # Check if the message contains progress information
927
1110
  if clean_message.startswith("Progress:"):
928
1111
  try:
@@ -950,8 +1133,7 @@ def process_console_queue():
950
1133
  if progress_bar:
951
1134
  progress_bar['maximum'] = total_progress
952
1135
  progress_bar['value'] = unique_progress_count
953
- #print("Current progress bar value:", progress_bar['value']) # Debugg
954
-
1136
+
955
1137
  # Store operation type and additional info
956
1138
  if operation_type:
957
1139
  progress_bar.operation_type = operation_type
@@ -967,11 +1149,13 @@ def process_console_queue():
967
1149
 
968
1150
  except Exception as e:
969
1151
  print(f"Error parsing progress message: {e}")
1152
+
970
1153
  else:
971
- # Only insert messages that do not start with "Progress:"
1154
+ # Insert non-progress messages into the console
972
1155
  console_output.insert(tk.END, clean_message + "\n")
973
1156
  console_output.see(tk.END)
974
-
1157
+
1158
+ # **Continue processing if no error was detected**
975
1159
  after_id = console_output.after(uppdate_frequency, process_console_queue)
976
1160
  parent_frame.after_tasks.append(after_id)
977
1161