comparison vitessce_spatial.py @ 4:068da7f7cd83 draft default tip

planemo upload for repository https://github.com/goeckslab/tools-mti/tree/main/tools/vitessce commit bc4c0bb6784a55399241f99a29b176541a164a18
author goeckslab
date Thu, 20 Feb 2025 19:47:16 +0000
parents 9f60ef2d586e
children
comparison
equal deleted inserted replaced
3:7cc457aa78b1 4:068da7f7cd83
1 import argparse 1 import argparse
2 import json 2 import json
3 import warnings 3 import warnings
4 from os.path import isdir, join
4 from pathlib import Path 5 from pathlib import Path
5 6
6 import scanpy as sc 7 import scanpy as sc
7 from anndata import read_h5ad 8 from anndata import read_h5ad
8 from vitessce import ( 9 from vitessce import (
10 Component as cm, 11 Component as cm,
11 MultiImageWrapper, 12 MultiImageWrapper,
12 OmeTiffWrapper, 13 OmeTiffWrapper,
13 VitessceConfig, 14 VitessceConfig,
14 ) 15 )
15 16 from vitessce.data_utils import (
16 17 optimize_adata,
17 def main(inputs, output, image, anndata=None, masks=None): 18 VAR_CHUNK_SIZE,
19 )
20
21
22 def main(inputs, output, image, offsets=None, anndata=None, masks=None):
18 """ 23 """
19 Parameter 24 Parameter
20 --------- 25 ---------
21 inputs : str 26 inputs : str
22 File path to galaxy tool parameter. 27 File path to galaxy inputs config file.
23 output : str 28 output : str
24 Output folder for saving web content. 29 Output folder for saving web content.
25 image : str 30 image : str
26 File path to the OME Tiff image. 31 File path to the OME Tiff image.
27 anndata : str 32 anndata : str
32 warnings.simplefilter('ignore') 37 warnings.simplefilter('ignore')
33 38
34 with open(inputs, 'r') as param_handler: 39 with open(inputs, 'r') as param_handler:
35 params = json.load(param_handler) 40 params = json.load(param_handler)
36 41
37 vc = VitessceConfig(name=None, description=None) 42 # initialize vitessce config and add OME-TIFF image, and masks if specified
43 vc = VitessceConfig(schema_version="1.0.17", name=None, description=None)
38 dataset = vc.add_dataset() 44 dataset = vc.add_dataset()
39 image_wrappers = [OmeTiffWrapper(img_path=image, name='OMETIFF')] 45
46 # FIXME: grab offsets file for faster display. NEED TO TEST
47 image_wrappers = [OmeTiffWrapper(img_path=image, offsets_path=offsets, name='OMETIFF')]
40 if masks: 48 if masks:
41 image_wrappers.append( 49 image_wrappers.append(
42 OmeTiffWrapper(img_path=masks, name='MASKS', is_bitmask=True) 50 OmeTiffWrapper(img_path=masks, name='MASKS', is_bitmask=True)
43 ) 51 )
44 dataset.add_object(MultiImageWrapper(image_wrappers)) 52 dataset.add_object(MultiImageWrapper(image_wrappers))
45 53
46 status = vc.add_view(dataset, cm.STATUS) 54 # set relative view sizes (w,h), full window dims are 12x12
47 spatial = vc.add_view(dataset, cm.SPATIAL) 55 # if no anndata file, image and layer view can take up whole window
48 lc = vc.add_view(dataset, cm.LAYER_CONTROLLER)
49
50 if not anndata: 56 if not anndata:
51 vc.layout(status / lc | spatial) 57 spatial_dims = (9, 12)
52 config_dict = vc.export(to='files', base_url='http://localhost', out_dir=output) 58 lc_dims = (3, 12)
59 else:
60 spatial_dims = (6, 6)
61 lc_dims = (3, 6)
62
63 # add views for the images, and the layer/channels selector
64 spatial = vc.add_view(
65 view_type=cm.SPATIAL,
66 dataset=dataset,
67 w=spatial_dims[0],
68 h=spatial_dims[1])
69
70 lc = vc.add_view(
71 view_type=cm.LAYER_CONTROLLER,
72 dataset=dataset,
73 w=lc_dims[0],
74 h=lc_dims[1])
75
76 # if no anndata file, export the config with these minimal components
77 if not anndata:
78 vc.layout(lc | spatial)
79 config_dict = vc.export(
80 to='files',
81 base_url='http://localhost',
82 out_dir=output)
53 with open(Path(output).joinpath('config.json'), 'w') as f: 83 with open(Path(output).joinpath('config.json'), 'w') as f:
54 json.dump(config_dict, f, indent=4) 84 json.dump(config_dict, f, indent=4)
55 return 85 return
56 86
87 # read anndata file, compute embeddings
57 adata = read_h5ad(anndata) 88 adata = read_h5ad(anndata)
58 89
59 params = params['do_phenotyping'] 90 params = params['do_phenotyping']
60 embedding = params['scatterplot_embeddings']['embedding'] 91 embedding = params['scatterplot_embeddings']['embedding']
61 embedding_options = params['scatterplot_embeddings']['options'] 92 embedding_options = params['scatterplot_embeddings']['options']
66 mappings_obsm_name = "UMAP" 97 mappings_obsm_name = "UMAP"
67 elif embedding == 'tsne': 98 elif embedding == 'tsne':
68 sc.tl.tsne(adata, **embedding_options) 99 sc.tl.tsne(adata, **embedding_options)
69 mappings_obsm = 'X_tsne' 100 mappings_obsm = 'X_tsne'
70 mappings_obsm_name = "tSNE" 101 mappings_obsm_name = "tSNE"
71 else: # pca 102 else:
72 sc.tl.pca(adata, **embedding_options) 103 sc.tl.pca(adata, **embedding_options)
73 mappings_obsm = 'X_pca' 104 mappings_obsm = 'X_pca'
74 mappings_obsm_name = "PCA" 105 mappings_obsm_name = "PCA"
75 106
76 adata.obsm['XY_centroid'] = adata.obs[['X_centroid', 'Y_centroid']].values 107 # Add spatial coords to obsm, although uncertain if this is needed
77 108 # FIXME: provide options for alternative coordinate colnames
109 adata.obsm['spatial'] = adata.obs[['X_centroid', 'Y_centroid']].values
110
111 # parse list of obs columns to use as cell type labels
78 cell_set_obs = params['phenotype_factory']['phenotypes'] 112 cell_set_obs = params['phenotype_factory']['phenotypes']
79 if not isinstance(cell_set_obs, list): 113 if not isinstance(cell_set_obs, list):
80 cell_set_obs = [x.strip() for x in cell_set_obs.split(',')] 114 cell_set_obs = [x.strip() for x in cell_set_obs.split(',')]
115
116 # write anndata out as zarr hierarchy
117 zarr_filepath = join("data", "adata.zarr")
118 if not isdir(zarr_filepath):
119 adata = optimize_adata(
120 adata,
121 obs_cols=cell_set_obs,
122 obsm_keys=[mappings_obsm, 'spatial'],
123 optimize_X=True
124 )
125 adata.write_zarr(
126 zarr_filepath,
127 chunks=[adata.shape[0], VAR_CHUNK_SIZE]
128 )
129
130 # create a nicer label for the cell types to be displayed on the dashboard
81 cell_set_obs_names = [obj[0].upper() + obj[1:] for obj in cell_set_obs] 131 cell_set_obs_names = [obj[0].upper() + obj[1:] for obj in cell_set_obs]
132
133 # add anndata zarr to vitessce config
82 dataset.add_object( 134 dataset.add_object(
83 AnnDataWrapper( 135 AnnDataWrapper(
84 adata, 136 adata_path=zarr_filepath,
85 mappings_obsm=[mappings_obsm], 137 obs_feature_matrix_path="X", # FIXME: provide rep options
86 mappings_obsm_names=[mappings_obsm_name], 138 obs_set_paths=['obs/' + x for x in cell_set_obs],
87 spatial_centroid_obsm='XY_centroid', 139 obs_set_names=cell_set_obs_names,
88 cell_set_obs=cell_set_obs, 140 obs_locations_path='spatial',
89 cell_set_obs_names=cell_set_obs_names, 141 obs_embedding_paths=['obsm/' + mappings_obsm],
90 expression_matrix="X" 142 obs_embedding_names=[mappings_obsm_name]
91 ) 143 )
92 ) 144 )
93 145
94 cellsets = vc.add_view(dataset, cm.CELL_SETS) 146 # add views
95 scattorplot = vc.add_view(dataset, cm.SCATTERPLOT, mapping=mappings_obsm_name) 147 cellsets = vc.add_view(
96 heatmap = vc.add_view(dataset, cm.HEATMAP) 148 view_type=cm.OBS_SETS,
97 genes = vc.add_view(dataset, cm.GENES) 149 dataset=dataset,
98 cell_set_sizes = vc.add_view(dataset, cm.CELL_SET_SIZES) 150 w=3,
99 cell_set_expression = vc.add_view(dataset, cm.CELL_SET_EXPRESSION) 151 h=3)
152
153 scatterplot = vc.add_view(
154 view_type=cm.SCATTERPLOT,
155 dataset=dataset,
156 mapping=mappings_obsm_name,
157 w=3,
158 h=6)
159
160 heatmap = vc.add_view(
161 view_type=cm.HEATMAP,
162 dataset=dataset,
163 w=3,
164 h=3)
165
166 genes = vc.add_view(
167 view_type=cm.FEATURE_LIST,
168 dataset=dataset,
169 w=3,
170 h=3)
171
172 cell_set_sizes = vc.add_view(
173 view_type=cm.OBS_SET_SIZES,
174 dataset=dataset,
175 w=3,
176 h=3)
177
178 cell_set_expression = vc.add_view(
179 view_type=cm.OBS_SET_FEATURE_VALUE_DISTRIBUTION,
180 dataset=dataset,
181 w=3,
182 h=6)
183
184 # define the dashboard layout
100 vc.layout( 185 vc.layout(
101 (status / genes / cell_set_expression) 186 (cellsets / genes / cell_set_expression)
102 | (cellsets / lc / scattorplot) 187 | (lc / scatterplot)
103 | (cell_set_sizes / heatmap / spatial) 188 | (cell_set_sizes / heatmap / spatial)
104 ) 189 )
105 config_dict = vc.export(to='files', base_url='http://localhost', out_dir=output) 190
191 # export the config file
192 config_dict = vc.export(
193 to='files',
194 base_url='http://localhost',
195 out_dir=output)
106 196
107 with open(Path(output).joinpath('config.json'), 'w') as f: 197 with open(Path(output).joinpath('config.json'), 'w') as f:
108 json.dump(config_dict, f, indent=4) 198 json.dump(config_dict, f, indent=4)
109 199
110 200
111 if __name__ == '__main__': 201 if __name__ == '__main__':
112 aparser = argparse.ArgumentParser() 202 aparser = argparse.ArgumentParser()
113 aparser.add_argument("-i", "--inputs", dest="inputs", required=True) 203 aparser.add_argument("-i", "--inputs", dest="inputs", required=True)
114 aparser.add_argument("-e", "--output", dest="output", required=True) 204 aparser.add_argument("-e", "--output", dest="output", required=True)
115 aparser.add_argument("-g", "--image", dest="image", required=True) 205 aparser.add_argument("-g", "--image", dest="image", required=True)
206 aparser.add_argument("-f", "--offsets", dest="offsets", required=False)
116 aparser.add_argument("-a", "--anndata", dest="anndata", required=False) 207 aparser.add_argument("-a", "--anndata", dest="anndata", required=False)
117 aparser.add_argument("-m", "--masks", dest="masks", required=False) 208 aparser.add_argument("-m", "--masks", dest="masks", required=False)
118 209
119 args = aparser.parse_args() 210 args = aparser.parse_args()
120 211
121 main(args.inputs, args.output, args.image, args.anndata, args.masks) 212 main(args.inputs, args.output, args.image, args.offsets, args.anndata, args.masks)