Mercurial > repos > goeckslab > vitessce_spatial
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) |