fusion-tools 3.3.2__tar.gz → 3.3.4__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 (78) hide show
  1. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/PKG-INFO +1 -1
  2. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/setup.py +1 -1
  3. fusion_tools-3.3.4/src/fusion_tools/fusion/data_types.py +503 -0
  4. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/src/fusion_tools/fusion/vis.py +19 -9
  5. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/src/fusion_tools/handler/dataset_builder.py +53 -17
  6. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/src/fusion_tools/handler/dataset_uploader.py +13 -2
  7. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/src/fusion_tools/utils/shapes.py +2 -2
  8. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/src/fusion_tools.egg-info/PKG-INFO +1 -1
  9. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/src/fusion_tools.egg-info/SOURCES.txt +1 -0
  10. fusion_tools-3.3.4/tests/test_fusion_layout.py +39 -0
  11. fusion_tools-3.3.2/src/fusion_tools/fusion/data_types.py +0 -62
  12. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/LICENSE +0 -0
  13. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/README.md +0 -0
  14. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/pyproject.toml +0 -0
  15. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/setup.cfg +0 -0
  16. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/src/fusion_tools/__init__.py +0 -0
  17. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/src/fusion_tools/components/__init__.py +0 -0
  18. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/src/fusion_tools/components/maps.py +0 -0
  19. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/src/fusion_tools/components/segmentation.py +0 -0
  20. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/src/fusion_tools/components/tools.py +0 -0
  21. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/src/fusion_tools/dataset.py +0 -0
  22. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/src/fusion_tools/feature_extraction.py +0 -0
  23. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/src/fusion_tools/fusion/__init__.py +0 -0
  24. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/src/fusion_tools/fusion/surveys.py +0 -0
  25. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/src/fusion_tools/handler/__init__.py +0 -0
  26. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/src/fusion_tools/handler/dsa_handler.py +0 -0
  27. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/src/fusion_tools/handler/login.py +0 -0
  28. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/src/fusion_tools/handler/plugin.py +0 -0
  29. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/src/fusion_tools/handler/resource_selector.py +0 -0
  30. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/src/fusion_tools/handler/survey.py +0 -0
  31. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/src/fusion_tools/tileserver.py +0 -0
  32. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/src/fusion_tools/utils/__init__.py +0 -0
  33. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/src/fusion_tools/utils/images.py +0 -0
  34. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/src/fusion_tools/utils/omics.py +0 -0
  35. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/src/fusion_tools/utils/stats.py +0 -0
  36. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/src/fusion_tools/visualization/__init__.py +0 -0
  37. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/src/fusion_tools/visualization/components.py +0 -0
  38. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/src/fusion_tools/visualization/vis_utils.py +0 -0
  39. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/src/fusion_tools.egg-info/dependency_links.txt +0 -0
  40. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/src/fusion_tools.egg-info/requires.txt +0 -0
  41. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/src/fusion_tools.egg-info/top_level.txt +0 -0
  42. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/tests/test_classification_model.py +0 -0
  43. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/tests/test_custom_component.py +0 -0
  44. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/tests/test_dash_table_dropdowns.py +0 -0
  45. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/tests/test_data_extractor.py +0 -0
  46. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/tests/test_dataset_classes.py +0 -0
  47. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/tests/test_dsa_components.py +0 -0
  48. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/tests/test_extract_nested_prop.py +0 -0
  49. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/tests/test_extract_recursive.py +0 -0
  50. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/tests/test_feature_annotation.py +0 -0
  51. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/tests/test_feature_extraction.py +0 -0
  52. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/tests/test_file_selector.py +0 -0
  53. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/tests/test_generate_property_dict.py +0 -0
  54. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/tests/test_get_gene_info.py +0 -0
  55. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/tests/test_global_property_plotter.py +0 -0
  56. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/tests/test_hra_viewer.py +0 -0
  57. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/tests/test_image_overlay.py +0 -0
  58. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/tests/test_large_slide_maps.py +0 -0
  59. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/tests/test_load_visium_csv.py +0 -0
  60. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/tests/test_meta_embed.py +0 -0
  61. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/tests/test_model_train.py +0 -0
  62. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/tests/test_multiframe_rgb.py +0 -0
  63. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/tests/test_multiframeslidemap.py +0 -0
  64. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/tests/test_multipage_layout.py +0 -0
  65. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/tests/test_parse_cli_xml.py +0 -0
  66. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/tests/test_path_extraction.py +0 -0
  67. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/tests/test_plugin_runner.py +0 -0
  68. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/tests/test_plugins.py +0 -0
  69. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/tests/test_process.py +0 -0
  70. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/tests/test_property_plotter.py +0 -0
  71. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/tests/test_read_anndata.py +0 -0
  72. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/tests/test_remote_slide_annotations.py +0 -0
  73. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/tests/test_remote_tileserver.py +0 -0
  74. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/tests/test_segmentation.py +0 -0
  75. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/tests/test_slide_annotations.py +0 -0
  76. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/tests/test_spatial_aggregation.py +0 -0
  77. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/tests/test_tile_server.py +0 -0
  78. {fusion_tools-3.3.2 → fusion_tools-3.3.4}/tests/test_visualization_component.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: fusion-tools
3
- Version: 3.3.2
3
+ Version: 3.3.4
4
4
  Summary: Modular visualization and analysis dashboard creation for high-resolution microscopy images
5
5
  Home-page: https://github.com/spborder/fusion-tools
6
6
  Author: Sam Border
@@ -5,7 +5,7 @@ with open("README.md", "r") as fh:
5
5
 
6
6
  setuptools.setup(
7
7
  name="fusion-tools",
8
- version="3.3.2",
8
+ version="3.3.4",
9
9
  author="Sam Border",
10
10
  author_email="sam.border2256@gmail.com",
11
11
  description="Modular visualization and analysis dashboard creation for high-resolution microscopy images",
@@ -0,0 +1,503 @@
1
+ """Defining UploadTypes which are accepted in FUSION
2
+ """
3
+
4
+ from fusion_tools.handler.dataset_uploader import DSAUploadType, WSI_TYPES, ANN_TYPES
5
+
6
+ def get_upload_types():
7
+
8
+ # Basic Type:
9
+ kidney_basic_type = DSAUploadType(
10
+ name = "Kidney Histology Image",
11
+ description= 'This is a kidney histology image upload with the option to add annotations. Glomeruli, sclerotic glomeruli, tubules, and cortical and medullary interstitium are first segmented using DL and then pathomic features are calculated.',
12
+ input_files = [
13
+ {
14
+ 'name': 'Image',
15
+ 'description': 'This is any kidney histology image you would like to upload.',
16
+ 'accepted_types': WSI_TYPES,
17
+ 'preprocessing_plugins': None,
18
+ 'type': 'item',
19
+ 'required': True
20
+ },
21
+ {
22
+ 'name': 'Annotation',
23
+ 'description': 'This is an annotation file that is processed and added to the uploaded image.',
24
+ 'accepted_types': ANN_TYPES,
25
+ 'preprocessing_plugins': None,
26
+ 'type': 'annotation',
27
+ 'parent': 'Image',
28
+ 'required': False
29
+ }
30
+ ],
31
+ processing_plugins=[
32
+ [
33
+ {
34
+ 'name': 'MultiCompartmentSegment',
35
+ 'image': 'samborder2256/multicomp:latest',
36
+ 'input_args': [
37
+ {
38
+ 'name': 'files',
39
+ 'default': {
40
+ 'type': 'upload_file',
41
+ 'name': 'Image'
42
+ },
43
+ 'disabled': True
44
+ },
45
+ {
46
+ 'name': 'base_dir',
47
+ 'default': {
48
+ 'type': 'upload_folder',
49
+ 'name': 'Image'
50
+ },
51
+ 'disabled': True
52
+ },
53
+ {
54
+ 'name': 'modelfile',
55
+ 'default': {
56
+ 'value': '648123761019450486d13dce'
57
+ }
58
+ }
59
+ ]
60
+ },
61
+ {
62
+ 'name': 'FeatureExtraction',
63
+ 'image': 'fusionplugins/general:latest',
64
+ 'input_args': [
65
+ {
66
+ 'name': 'input_image',
67
+ 'default': {
68
+ 'type': 'upload_file',
69
+ 'name': 'Image'
70
+ }
71
+ },
72
+ {
73
+ 'name': 'extract_sub_compartments',
74
+ 'default': {
75
+ 'value': True
76
+ },
77
+ 'disabled': True
78
+ },
79
+ 'hematoxylin_threshold',
80
+ 'eosinophilic_threshold',
81
+ 'hematoxylin_min_size',
82
+ 'eosinophilic_min_size'
83
+ ]
84
+ }
85
+ ]
86
+ ],
87
+ required_metadata=[]
88
+ )
89
+
90
+ # Basic Type:
91
+ basic_type = DSAUploadType(
92
+ name = "General Histology Image",
93
+ description= 'This is a histology image upload with the option to add annotations. Glomeruli, sclerotic glomeruli, tubules, and cortical and medullary interstitium are first segmented using DL and then pathomic features are calculated.',
94
+ input_files = [
95
+ {
96
+ 'name': 'Image',
97
+ 'description': 'This is any histology image you would like to upload.',
98
+ 'accepted_types': WSI_TYPES,
99
+ 'preprocessing_plugins': None,
100
+ 'type': 'item',
101
+ 'required': True
102
+ },
103
+ {
104
+ 'name': 'Annotation',
105
+ 'description': 'This is an annotation file that is processed and added to the uploaded image.',
106
+ 'accepted_types': ANN_TYPES,
107
+ 'preprocessing_plugins': None,
108
+ 'type': 'annotation',
109
+ 'parent': 'Image',
110
+ 'required': False
111
+ }
112
+ ],
113
+ processing_plugins=[
114
+ {
115
+ 'name': 'FeatureExtraction',
116
+ 'image': 'fusionplugins/general:latest',
117
+ 'input_args': [
118
+ {
119
+ 'name': 'input_image',
120
+ 'default': {
121
+ 'type': 'upload_file',
122
+ 'name': 'Image'
123
+ }
124
+ },
125
+ {
126
+ 'name': 'extract_sub_compartments',
127
+ 'default': {
128
+ 'value': True
129
+ }
130
+ },
131
+ {
132
+ 'name': 'hematoxylin_threshold',
133
+ 'default': {
134
+ 'value': 150
135
+ }
136
+ },
137
+ {
138
+ 'name': 'eosinophilic_threshold',
139
+ 'default': {
140
+ 'value': 30
141
+ }
142
+ },
143
+ {
144
+ 'name': 'hematoxylin_min_size',
145
+ 'default': {
146
+ 'value': 40
147
+ }
148
+ },
149
+ {
150
+ 'name': 'eosinophilic_min_size',
151
+ 'default': {
152
+ 'value': 20
153
+ }
154
+ },
155
+ ]
156
+ }
157
+ ],
158
+ required_metadata=[
159
+ {
160
+ 'name': 'Organ',
161
+ 'required': True,
162
+ 'item': 'Image'
163
+ }
164
+ ]
165
+ )
166
+
167
+ # 10x Types:
168
+ visium_type = DSAUploadType(
169
+ name = '10x Visium',
170
+ description = 'This upload type is for 10x Visium spatial transcriptomics samples. It includes one histology image and information related to the transcript counts per-"spot".',
171
+ input_files = [
172
+ {
173
+ 'name': 'Image',
174
+ 'description': 'This is the full-resolution image associated with this upload. If the full-resolution image is not available, upload the "hires_image" and the "scalefactors_json.json" file to appropriately scale coordinates.',
175
+ 'accepted_types': WSI_TYPES,
176
+ 'preprocessing_plugins': None,
177
+ 'type': 'item',
178
+ 'required': True
179
+ },
180
+ {
181
+ 'name': 'Counts',
182
+ 'description': 'This is the file containing per-spot gene counts',
183
+ 'accepted_types': ['h5','h5ad','csv','rds','RDS'],
184
+ 'preprocessing_plugins': None,
185
+ 'type': 'file',
186
+ 'parent': 'Image',
187
+ 'required': True
188
+ },
189
+ {
190
+ 'name': 'Structures',
191
+ 'description': 'If you have annotated any additional structures on the histology image, upload those annotations here.',
192
+ 'accepted_types': ANN_TYPES,
193
+ 'preprocessing_plugins': None,
194
+ 'type': 'annotation',
195
+ 'parent': 'Image',
196
+ 'required': False
197
+ },
198
+ {
199
+ 'name': 'Scale Factors',
200
+ 'description': 'If using the "hires" image, upload the "scalefactors_json.json" file here.',
201
+ 'accepted_types': ['json'],
202
+ 'preprocessing_plugins': None,
203
+ 'type': 'file',
204
+ 'parent': 'Image',
205
+ 'required': False
206
+ },
207
+ {
208
+ 'name': 'Genes List File',
209
+ 'description': 'If you want to include specific genes which are not included in the "most variable" genes, upload CSV file containing one column with those gene IDs.',
210
+ 'accepted_types': ['csv'],
211
+ 'preprocessing_plugins': None,
212
+ 'type': 'file',
213
+ 'parent': 'Image',
214
+ 'required': False
215
+ }
216
+ ],
217
+ processing_plugins=[
218
+ [
219
+ {
220
+ 'name': 'CellDeconvolution',
221
+ 'image': 'fusionplugins/visium:latest',
222
+ 'input_args': [
223
+ {
224
+ 'name': 'counts_file',
225
+ 'default': {
226
+ 'type': 'upload_file',
227
+ 'name': 'Counts File'
228
+ },
229
+ 'disabled': False
230
+ },
231
+ 'organ'
232
+ ]
233
+ },
234
+ {
235
+ 'name': 'SpotAnnotation',
236
+ 'image': 'fusionplugins/visium:latest',
237
+ 'input_args': [
238
+ {
239
+ 'name': 'counts_file',
240
+ 'default': {
241
+ 'type': 'upload_file',
242
+ 'name': 'Counts File',
243
+ },
244
+ 'disabled': True
245
+ },
246
+ {
247
+ 'name': 'input_files',
248
+ 'default': {
249
+ 'type': 'upload_file',
250
+ 'name': 'Image'
251
+ },
252
+ 'disabled': False
253
+ },
254
+ 'use_gene_selection',
255
+ 'gene_selection_method',
256
+ 'n'
257
+ ]
258
+ }
259
+ ]
260
+ ],
261
+ required_metadata=[
262
+ {
263
+ 'name': 'Organ',
264
+ 'required': True,
265
+ 'item': 'Image'
266
+ }
267
+ ]
268
+ )
269
+
270
+ xenium_type = DSAUploadType(
271
+ name = '10x Xenium',
272
+ description='This is for 10x Xenium samples. It includes a morphology (DAPI) image and, optionally, a histology image as well as cell centroids/boundaries and assigned "group" labels or other information for each segmented cell.',
273
+ input_files = [
274
+ {
275
+ 'name': 'Morphology Image',
276
+ 'description': 'This is the morphology image showing the location of nuclei in the sample at different levels.',
277
+ 'accepted_types': ['tif','tiff'],
278
+ 'preprocessing_plugins': None,
279
+ 'type': 'item',
280
+ 'required': True
281
+ },
282
+ {
283
+ 'name': 'Histology Image',
284
+ 'description': 'This is a histology image from the same section used for alignment of derived cell segmentations.',
285
+ 'accepted_types': WSI_TYPES,
286
+ 'preprocessing_plugins': None,
287
+ 'type': 'item',
288
+ 'required': False
289
+ },
290
+ {
291
+ 'name': 'Cell Segmentations',
292
+ 'description': 'This is a file containing either cell centroids and areas or the boundaries of segmented cells.',
293
+ 'accepted_types': ['csv'],
294
+ 'preprocessing_plugins': None,
295
+ 'type': 'annotation',
296
+ 'parent': 'Morphology Image',
297
+ 'required': True
298
+ },
299
+ {
300
+ 'name': 'Cell Groups',
301
+ 'description': 'This is a csv file containing one column with "cell_id" and then other columns which are added to per-cell properties (could be cell group labels or any other measurement).',
302
+ 'accepted_types': ['csv'],
303
+ 'preprocessing_plugins': None,
304
+ 'type': 'file',
305
+ 'parent': 'Morphology Image',
306
+ 'required': False
307
+ }
308
+ ],
309
+ processing_plugins=[
310
+ {
311
+ 'name': '',
312
+ 'image': '',
313
+ 'input_args': [
314
+ {
315
+
316
+ }
317
+ ]
318
+ }
319
+ ],
320
+ required_metadata=[
321
+ {
322
+ 'name': 'Organ',
323
+ 'required': True,
324
+ 'item': 'Image'
325
+ }
326
+ ]
327
+ )
328
+
329
+ hd_type = DSAUploadType(
330
+ name = "10x Visium HD",
331
+ description = 'This is for the 10x Visium HD data type.',
332
+ input_files = [
333
+ {
334
+ 'name': 'Image',
335
+ 'description': '',
336
+ 'accepted_types': WSI_TYPES,
337
+ 'preprocessing_plugins': None,
338
+ 'type': 'item',
339
+ 'required': True
340
+ }
341
+ ],
342
+ processing_plugins=[],
343
+ required_metadata=[
344
+ {
345
+ 'name': 'Organ',
346
+ 'required': True,
347
+ 'item': 'Image'
348
+ }
349
+ ]
350
+ )
351
+
352
+ # MxIF/PhenoCycler
353
+ mxif_type = DSAUploadType(
354
+ name = "MxIF / PhenoCycler",
355
+ description = 'This is for a multiplexed - immunofluorescence (mxIF) type image containing several different fluorescence channels for different markers. If available, you may also choose to align this image with a same-section histology image.',
356
+ input_files = [
357
+ {
358
+ 'name': 'IF Image',
359
+ 'description': 'This is a single multi-frame immunofluorescence image containing aligned channels.',
360
+ 'accepted_types': ['tif','tiff'],
361
+ 'preprocessing_plugins': None,
362
+ 'type': 'item',
363
+ 'required': True
364
+ },
365
+ {
366
+ 'name': 'Histology Image',
367
+ 'description': 'This is a same-section histology image which the IF image is aligned to during processing.',
368
+ 'accepted_types': WSI_TYPES,
369
+ 'preprocessing_plugins': None,
370
+ 'type': 'item',
371
+ 'required': False
372
+ },
373
+ {
374
+ 'name': 'IF Annotations',
375
+ 'description': 'If any structures have been segmented from the IF image, upload them here.',
376
+ 'accepted_types': ANN_TYPES,
377
+ 'preprocessing_plugins': None,
378
+ 'type': 'annotation',
379
+ 'parent': 'IF Image',
380
+ 'required': False
381
+ },
382
+ {
383
+ 'name': 'Histology Annotations',
384
+ 'description': 'If any structures were segmented from the histology image, upload them here.',
385
+ 'accepted_types': ANN_TYPES,
386
+ 'preprocessing_plugins': None,
387
+ 'type': 'annotation',
388
+ 'parent': 'Histology Image',
389
+ 'required': False
390
+ }
391
+ ],
392
+ processing_plugins = [
393
+ [
394
+ {
395
+ 'image': 'fusionplugins/codex:latest',
396
+ 'name': 'CellSegmentation',
397
+ 'input_args': [
398
+ {
399
+ 'name': 'input_image',
400
+ 'default': {
401
+ 'type': 'upload_file',
402
+ 'name': 'IF Image'
403
+ }
404
+ }
405
+ ]
406
+ },
407
+ {
408
+ 'image': 'fusionplugins/general:latest',
409
+ 'name': 'FeatureExtraction',
410
+ 'input_args': [
411
+ {
412
+ 'name': 'input_image',
413
+ 'default': {
414
+ 'type': 'upload_file',
415
+ 'name': 'IF Image'
416
+ }
417
+ }
418
+ ]
419
+ }
420
+ ],
421
+ {
422
+ 'image': 'fusionplugins/general:latest',
423
+ 'name': 'FeatureExtraction',
424
+ 'input_args': [
425
+ {
426
+ 'name': 'input_image',
427
+ 'default': {
428
+ 'type': 'upload_file',
429
+ 'name': 'Histology Image'
430
+ }
431
+ },
432
+ {
433
+ 'name': 'extract_sub_compartments',
434
+ 'default': {
435
+ 'value': True
436
+ }
437
+ },
438
+ 'hematoxylin_threshold',
439
+ 'eosinophilic_threshold',
440
+ 'hematoxylin_min_size',
441
+ 'eosinophilic_min_size'
442
+ ]
443
+ }
444
+ ],
445
+ required_metadata = [
446
+ {
447
+ 'name': 'Organ',
448
+ 'required': True,
449
+ 'item': 'Image'
450
+ }
451
+ ]
452
+ )
453
+
454
+ # HuBMAP Processed Dataset
455
+ hubmap_type = DSAUploadType(
456
+ name = "HuBMAP Processed",
457
+ description='This is for a dataset which has been processed by the Human Biomolecular Atlas Program (HuBMAP).',
458
+ input_files = [
459
+ {
460
+ 'name': 'Image',
461
+ 'description': '',
462
+ 'accepted_types': WSI_TYPES,
463
+ 'preprocessing_plugins': None,
464
+ 'type': 'item',
465
+ 'required': True
466
+ }
467
+ ],
468
+ processing_plugins= [
469
+ {
470
+ 'name': '',
471
+ 'image': '',
472
+ 'input_args': []
473
+ }
474
+ ],
475
+ required_metadata=[
476
+ {
477
+ 'name': 'Organ',
478
+ 'required': True,
479
+ 'item': 'Image'
480
+ },
481
+ {
482
+ 'name': 'Sample ID',
483
+ 'required': True,
484
+ 'item': 'Image'
485
+ },
486
+ {
487
+ 'name': 'Assay Type',
488
+ 'required': True,
489
+ 'item': 'Image'
490
+ }
491
+ ]
492
+ )
493
+
494
+ return [
495
+ basic_type,
496
+ kidney_basic_type,
497
+ visium_type,
498
+ xenium_type,
499
+ hd_type,
500
+ mxif_type,
501
+ hubmap_type
502
+ ]
503
+
@@ -3,16 +3,18 @@
3
3
  from fusion_tools.visualization import Visualization
4
4
  from fusion_tools.handler.dsa_handler import DSAHandler
5
5
  from fusion_tools.components import (
6
+ SlideMap,
6
7
  MultiFrameSlideMap,
7
8
  ChannelMixer,
8
9
  OverlayOptions,
9
10
  PropertyViewer,
10
11
  GlobalPropertyPlotter,
11
12
  HRAViewer,
12
- FeatureAnnotation,
13
13
  BulkLabels
14
14
  )
15
15
 
16
+ from fusion_tools.fusion.data_types import get_upload_types
17
+
16
18
 
17
19
  def get_layout(args):
18
20
 
@@ -27,12 +29,10 @@ def get_layout(args):
27
29
 
28
30
  dsa_plugin_progress = dsa_handler.create_plugin_progress()
29
31
 
30
- dsa_dataset_builder = dsa_handler.create_dataset_builder(
31
- include = args['dataset_builder_include']
32
- )
32
+ dsa_dataset_builder = dsa_handler.create_dataset_builder()
33
33
 
34
34
  dsa_dataset_uploader = dsa_handler.create_uploader(
35
- uploader_types = []
35
+ upload_types = get_upload_types()
36
36
  )
37
37
 
38
38
  user_surveys = []
@@ -51,12 +51,9 @@ def get_layout(args):
51
51
  components = {
52
52
  "Visualization": [
53
53
  [
54
- MultiFrameSlideMap()
55
- ],
56
- [
54
+ SlideMap(),
57
55
  [
58
56
  OverlayOptions(),
59
- ChannelMixer(),
60
57
  PropertyViewer(ignore_list=['_id','_index']),
61
58
  GlobalPropertyPlotter(ignore_list = ['_id','_index']),
62
59
  HRAViewer(),
@@ -64,6 +61,19 @@ def get_layout(args):
64
61
  ]
65
62
  ]
66
63
  ],
64
+ "MultiFrame Visualization": [
65
+ [
66
+ MultiFrameSlideMap(),
67
+ [
68
+ ChannelMixer(),
69
+ OverlayOptions(),
70
+ PropertyViewer(ignore_list = ['_id','_index']),
71
+ GlobalPropertyPlotter(ignore_list = ['_id','_index']),
72
+ HRAViewer(),
73
+ BulkLabels()
74
+ ]
75
+ ]
76
+ ],
67
77
  "Dataset Builder": [
68
78
  dsa_dataset_builder
69
79
  ],
@@ -82,7 +82,8 @@ class DatasetBuilder(DSATool):
82
82
  'Collection Name': f'User: {session_data["current_user"]["login"]}',
83
83
  'Collection ID': session_data["current_user"]['_id'],
84
84
  'Number of Folder': 2,
85
- 'Last Updated': '-'
85
+ 'Last Updated': '-',
86
+ 'token': session_data['current_user']['token']
86
87
  })
87
88
 
88
89
  collections_df = pd.DataFrame.from_records(collections_info)
@@ -146,7 +147,10 @@ class DatasetBuilder(DSATool):
146
147
  dcc.Store(
147
148
  id = {'type':'dataset-builder-data-store','index': 0},
148
149
  storage_type='memory',
149
- data = json.dumps({'selected_slides':starting_slides, 'selected_collections': [], 'available_collections': collections_df.to_dict("records")})
150
+ data = json.dumps({
151
+ 'selected_slides':starting_slides,
152
+ 'selected_collections': [],
153
+ 'available_collections': collections_df.to_dict("records")})
150
154
  )
151
155
  ),
152
156
  dbc.Row([
@@ -238,7 +242,8 @@ class DatasetBuilder(DSATool):
238
242
  ],
239
243
  [
240
244
  State({'type':'dataset-builder-data-store','index': ALL},'data'),
241
- State({'type':'dataset-builder-collection-contents-div','index': ALL},'children')
245
+ State({'type':'dataset-builder-collection-contents-div','index': ALL},'children'),
246
+ State('anchor-vis-store','data')
242
247
  ],
243
248
  [
244
249
  Output({'type':'dataset-builder-collection-contents-div','index': ALL},'children'),
@@ -323,7 +328,7 @@ class DatasetBuilder(DSATool):
323
328
  dataframe = pd.json_normalize(dataframe.to_dict('records'))
324
329
  selectable_table = dash_table.DataTable(
325
330
  id = id,
326
- columns = [{'name':i,'id':i,'deletable':False} for i in dataframe.columns],
331
+ columns = [{'name':i,'id':i,'deletable':False} for i in dataframe.columns if not i=='token'],
327
332
  data = dataframe.to_dict('records'),
328
333
  editable = False,
329
334
  filter_action='native',
@@ -352,13 +357,15 @@ class DatasetBuilder(DSATool):
352
357
 
353
358
  return selectable_table
354
359
 
355
- def organize_folder_contents(self, folder_info:dict, show_empty:bool=True, ignore_histoqc:bool=True)->list:
360
+ def organize_folder_contents(self, folder_info:dict, show_empty:bool=True, ignore_histoqc:bool=True,session_data:dict = {})->list:
356
361
  """For a given folder selection, return a list of slides(0th) and folders (1th)
357
362
 
358
363
  :param folder_info: Folder info dict returned by self.handler.get_path_info(path)
359
364
  :type folder_info: dict
360
365
  :param show_empty: Whether or not to display folders which contain 0 slides, defaults to False
361
366
  :type show_empty: bool, optional
367
+ :param session_data: Current session information
368
+ :type session_data: dict
362
369
  :return: List of slides within the current folder as well as folders within that folder
363
370
  :rtype: list
364
371
  """
@@ -371,7 +378,8 @@ class DatasetBuilder(DSATool):
371
378
  all_folder_slides = self.handler.get_folder_slides(
372
379
  folder_path = folder_info['_id'],
373
380
  folder_type = folder_info['_modelType'],
374
- ignore_histoqc=ignore_histoqc
381
+ ignore_histoqc=ignore_histoqc,
382
+ user_token = session_data['current_user']['token'] if 'current_user' in session_data else None
375
383
  )
376
384
 
377
385
  folder_slides_folders = [i['folderId'] for i in all_folder_slides]
@@ -381,8 +389,14 @@ class DatasetBuilder(DSATool):
381
389
  if not u==folder_info['_id'] and not u in folders_in_folder:
382
390
  # This is for all folders in this folder
383
391
  # This grabs parent folders of this folder
384
- u_folder_info = self.handler.get_folder_info(folder_id=u)
385
- u_folder_rootpath = self.handler.get_folder_rootpath(u)
392
+ u_folder_info = self.handler.get_folder_info(
393
+ folder_id=u,
394
+ user_token = session_data['current_user']['token'] if 'current_user' in session_data else None
395
+ )
396
+ u_folder_rootpath = self.handler.get_folder_rootpath(
397
+ u,
398
+ user_token = session_data['current_user']['token'] if 'current_user' in session_data else None
399
+ )
386
400
  # Folders in order from collection-->child folder-->etc.
387
401
  folder_ids = [i['object']['_id'] for i in u_folder_rootpath]
388
402
 
@@ -400,7 +414,8 @@ class DatasetBuilder(DSATool):
400
414
 
401
415
 
402
416
  child_folder_path_info = self.handler.get_path_info(
403
- path = child_folder_path
417
+ path = child_folder_path,
418
+ user_token = session_data['current_user']['token'] if 'current_user' in session_data else None
404
419
  )
405
420
  if not child_folder_path_info['_id'] in folders_in_folder:
406
421
  folders_in_folder.append(child_folder_path_info['_id'])
@@ -429,10 +444,13 @@ class DatasetBuilder(DSATool):
429
444
 
430
445
  else:
431
446
 
447
+ folders_in_folder = []
448
+ unique_folders = []
432
449
  user_folders = ['Private','Public']
433
450
  for u_f in user_folders:
434
451
  user_folder_info = self.handler.get_path_info(
435
- path = f'/user/{folder_info["login"]}/{u_f}'
452
+ path = f'/user/{folder_info["login"]}/{u_f}',
453
+ user_token = session_data['current_user']['token'] if 'current_user' in session_data else None
436
454
  )
437
455
 
438
456
  folder_folders.append({
@@ -443,16 +461,23 @@ class DatasetBuilder(DSATool):
443
461
  'Last Updated': user_folder_info['updated']
444
462
  })
445
463
 
464
+ unique_folders.append(user_folder_info['_id'])
465
+
466
+
446
467
  if show_empty:
447
468
  # This is how you get all the empty folders within a folder (does not get child empty folders)
448
469
  empty_folders = self.handler.get_folder_folders(
449
470
  folder_id = folder_info['_id'],
450
- folder_type = folder_info['_modelType']
471
+ folder_type = folder_info['_modelType'],
472
+ user_token = session_data['current_user']['token'] if 'current_user' in session_data else None
451
473
  )
452
474
 
453
475
  for f in empty_folders:
454
476
  if not f['_id'] in folders_in_folder and not f['_id'] in unique_folders:
455
- folder_info = self.handler.gc.get(f'/folder/{f["_id"]}/details')
477
+ if not 'current_user' in session_data:
478
+ folder_info = self.handler.gc.get(f'/folder/{f["_id"]}/details')
479
+ else:
480
+ folder_info = self.handler.gc.get(f'/folder/{f["_id"]}/details?token={session_data["current_user"]["token"]}')
456
481
  folder_folders.append(
457
482
  {
458
483
  'Folder Name': f['name'],
@@ -528,20 +553,23 @@ class DatasetBuilder(DSATool):
528
553
 
529
554
  return slide_card
530
555
 
531
- def collection_selection(self, collection_rows, builder_data, collection_div_children):
556
+ def collection_selection(self, collection_rows, builder_data, collection_div_children,session_data):
532
557
  """Callback for when one/multiple collections are selected from the collections table
533
558
 
534
559
  :param collection_rows: Row indices of selected collections
535
560
  :type collection_rows: list
536
561
  :param builder_data: Data store on available collections and currently included slides
537
562
  :type builder_data: list
538
- :param colleciton_div_children: Child cards created by collection_selection
539
- :type colleciton_div_children: list
563
+ :param collection_div_children: Child cards created by collection_selection
564
+ :type collection_div_children: list
565
+ :param session_data: Current session information
566
+ :type session_data: dict
540
567
  :return: Children of collection-contents-div (items/folders within selected collections)
541
568
  :rtype: list
542
569
  """
543
570
  selected_collections = get_pattern_matching_value(collection_rows)
544
571
  builder_data = json.loads(get_pattern_matching_value(builder_data))
572
+ session_data = json.loads(session_data)
545
573
 
546
574
  collection_card_indices = self.get_component_indices(collection_div_children)
547
575
 
@@ -559,11 +587,19 @@ class DatasetBuilder(DSATool):
559
587
  # For each collection, grab all items and unique folders (as well as those that are not nested in a folder)
560
588
  if not 'User: ' in collection_info["Collection Name"]:
561
589
  folder_slides, folder_folders = self.organize_folder_contents(
562
- folder_info = self.handler.get_path_info(f'/collection/{collection_info["Collection Name"]}')
590
+ folder_info = self.handler.get_path_info(
591
+ f'/collection/{collection_info["Collection Name"]}',
592
+ user_token = session_data['current_user']['token'] if 'current_user' in session_data else None
593
+ ),
594
+ session_data = session_data
563
595
  )
564
596
  else:
565
597
  folder_slides, folder_folders = self.organize_folder_contents(
566
- folder_info=self.handler.get_path_info(f'/user/{collection_info["Collection Name"].replace("User: ","")}')
598
+ folder_info=self.handler.get_path_info(
599
+ f'/user/{collection_info["Collection Name"].replace("User: ","")}',
600
+ user_token = session_data['current_user']['token'] if 'current_user' in session_data else None
601
+ ),
602
+ session_data = session_data
567
603
  )
568
604
 
569
605
  if len(folder_slides)>0:
@@ -32,12 +32,17 @@ from fusion_tools.handler.resource_selector import DSAResourceSelector
32
32
  from girder_job_sequence import Job, Sequence
33
33
  from girder_job_sequence.utils import from_list, from_dict
34
34
  import threading
35
+ import large_image
36
+
35
37
 
36
38
  # Maximum allowed size of uploads (Mb)
37
39
  MAX_UPLOAD_SIZE = 1e4
38
40
  # Minimum chunk size (Mb)
39
41
  MIN_UPLOAD_SIZE = 6
40
42
 
43
+ WSI_TYPES = [i for i in list(large_image.listSources()['extensions'].keys()) if not i in ['json','yaml','yml']]
44
+ ANN_TYPES = ['json','geojson','xml','csv']
45
+
41
46
 
42
47
  class DSAUploadType:
43
48
  """Formatted upload type for a DSAUploader Component.
@@ -305,7 +310,8 @@ class DSAUploadHandler:
305
310
  upload_info
306
311
  )
307
312
  post_response = {
308
- 'n_annotations': post_response
313
+ 'n_annotations': post_response,
314
+ '_modelType': 'annotation'
309
315
  }
310
316
  else:
311
317
  post_response = r.filename
@@ -1719,7 +1725,7 @@ class DSAUploader(DSATool):
1719
1725
  file_uploads = html.Div([
1720
1726
  dbc.Stack([
1721
1727
  html.Div([
1722
- html.H5(f'{f["name"]}, ({",".join(f["accepted_types"])})',style={'textTransform':'none'}),
1728
+ html.H5(f'{f["name"]}',style={'textTransform':'none'}),
1723
1729
  html.Div(
1724
1730
  self.create_upload_component(
1725
1731
  file_info = f | {'parentId': folder_info["_id"],'parentType': 'folder', 'fusion_upload_name': f['name'], 'fusion_upload_type': f['type']},
@@ -1730,6 +1736,11 @@ class DSAUploader(DSATool):
1730
1736
  id = {'type': f'{self.component_prefix}-dsa-uploader-file-upload-div','index': f_idx},
1731
1737
  style = {'width': '100%'}
1732
1738
  ),
1739
+ dbc.Tooltip(
1740
+ target = {'type': f'{self.component_prefix}-dsa-uploader-file-upload-div','index': f_idx},
1741
+ placement='top',
1742
+ children = ','.join(f['accepted_types'])
1743
+ ),
1733
1744
  html.Div(
1734
1745
  id = {'type': f'{self.component_prefix}-dsa-uploader-file-upload-status-div','index': f_idx},
1735
1746
  children = []
@@ -584,7 +584,7 @@ def geojson_to_histomics(geojson_anns: Union[list,dict]):
584
584
  {
585
585
  'type': 'polyline',
586
586
  'user': f['properties'],
587
- 'points': [i+[0] for i in f['geometry']['coordinates'][0]]
587
+ 'points': [list(i)+[0] if type(i)==tuple else i+[0] for i in f['geometry']['coordinates'][0]]
588
588
  }
589
589
  for f in g['features']
590
590
  ]
@@ -841,7 +841,7 @@ def spatially_aggregate(child_geo:dict, parent_geos: list, separate: bool = True
841
841
  a_shape = shape(a['geometry'])
842
842
  agg_props = {}
843
843
  for b_idx,b in enumerate(base_gdf):
844
- b_intersect = b.sindex.query(a_shape,predicate='overlaps')
844
+ b_intersect = b.sindex.query(a_shape,predicate='intersects')
845
845
  if len(b_intersect)>0:
846
846
  agg_props[base_names[b_idx]] = []
847
847
  for c in b_intersect:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: fusion-tools
3
- Version: 3.3.2
3
+ Version: 3.3.4
4
4
  Summary: Modular visualization and analysis dashboard creation for high-resolution microscopy images
5
5
  Home-page: https://github.com/spborder/fusion-tools
6
6
  Author: Sam Border
@@ -46,6 +46,7 @@ tests/test_extract_recursive.py
46
46
  tests/test_feature_annotation.py
47
47
  tests/test_feature_extraction.py
48
48
  tests/test_file_selector.py
49
+ tests/test_fusion_layout.py
49
50
  tests/test_generate_property_dict.py
50
51
  tests/test_get_gene_info.py
51
52
  tests/test_global_property_plotter.py
@@ -0,0 +1,39 @@
1
+ """Testing FUSION layout
2
+ """
3
+
4
+ import os
5
+ import sys
6
+ sys.path.append('./src/')
7
+
8
+ from fusion_tools.fusion.vis import get_layout
9
+
10
+ def main():
11
+
12
+ dsa_url = os.environ.get('DSA_URL')
13
+ dsa_user = os.environ.get('DSA_USER')
14
+ dsa_pword = os.environ.get('DSA_PWORD')
15
+
16
+ if all([i is None for i in [dsa_url,dsa_user,dsa_pword]]):
17
+ raise Exception('Need to initialize with at least the environment variable: DSA_URL')
18
+
19
+ initial_items = [
20
+ '6495a4e03e6ae3107da10dc5',
21
+ '6495a4df3e6ae3107da10dc2'
22
+ ]
23
+
24
+ args_dict = {
25
+ 'girderApiUrl': dsa_url,
26
+ 'user': dsa_user,
27
+ 'pword': dsa_pword,
28
+ 'initialItems': initial_items,
29
+ 'app_options': {
30
+ 'port': 8050
31
+ }
32
+ }
33
+
34
+ fusion_vis = get_layout(args_dict)
35
+
36
+ fusion_vis.start()
37
+
38
+ if __name__=='__main__':
39
+ main()
@@ -1,62 +0,0 @@
1
- """Defining UploadTypes which are accepted in FUSION
2
- """
3
-
4
- from fusion_tools.handler.dataset_uploader import DSAUploadType
5
-
6
- def get_upload_types(args):
7
-
8
- # Basic Type:
9
- basic_type = DSAUploadType(
10
- name = "Histology Image",
11
- input_files = [],
12
- processing_plugins=[],
13
- required_metadata=[]
14
- )
15
-
16
- # 10x Types:
17
- visium_type = DSAUploadType(
18
- name = '10x Visium',
19
- input_files = [],
20
- processing_plugins=[],
21
- required_metadata=[]
22
- )
23
-
24
- xenium_type = DSAUploadType(
25
- name = '10x Xenium',
26
- input_files = [],
27
- processing_plugins=[],
28
- required_metadata=[]
29
- )
30
-
31
- hd_type = DSAUploadType(
32
- name = "10x Visium HD",
33
- input_files = [],
34
- processing_plugins=[],
35
- required_metadata=[]
36
- )
37
-
38
- # MxIF/CODEX
39
- mxif_type = DSAUploadType(
40
- name = "MxIF / CODEX",
41
- input_files = [],
42
- processing_plugins = [],
43
- required_metadata = []
44
- )
45
-
46
- # HuBMAP Processed Dataset
47
- hubmap_type = DSAUploadType(
48
- name = "HuBMAP Processed",
49
- input_files = [],
50
- processing_plugins= [],
51
- required_metadata=[]
52
- )
53
-
54
- return [
55
- basic_type,
56
- visium_type,
57
- xenium_type,
58
- hd_type,
59
- mxif_type,
60
- hubmap_type
61
- ]
62
-
File without changes
File without changes
File without changes