mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-09-30 06:08:12 +08:00
Launch validation (#414)
* WIP * Cleanup * Validation * typo * Max category limit 100 -> 500
This commit is contained in:
+56
-56
@@ -1,26 +1,26 @@
|
||||
import click
|
||||
from os.path import expanduser, isdir, isfile, sep, splitext
|
||||
|
||||
from numpy import unique, ndarray
|
||||
import click
|
||||
from numpy import ndarray, unique
|
||||
from scipy.sparse.csc import csc_matrix
|
||||
from os.path import isfile, isdir, splitext, expanduser, sep
|
||||
|
||||
|
||||
@click.command()
|
||||
@click.argument('data', nargs=1, metavar='<dataset: file or path to data>', required=True)
|
||||
@click.option('--layout', '-l', default=['umap', 'tsne'], multiple=True, type=click.Choice(['umap', 'tsne']),
|
||||
help='Layout algorithm', show_default=True)
|
||||
@click.option('--recipe', '-r', default='none', type=click.Choice(['none', 'seurat', 'zheng17']),
|
||||
help='Preprocessing to run.', show_default=True)
|
||||
@click.option('--output', '-o', default='', help='Save a new file to filename.', metavar='<filename>')
|
||||
@click.option('--plotting', '-p', default=False, is_flag=True, help='Whether to generate plots.', show_default=True)
|
||||
@click.option('--sparse', default=False, is_flag=True, help='Whether to force sparsity.', show_default=True)
|
||||
@click.option('--overwrite', default=False, is_flag=True, help='Allow file overwriting.', show_default=True)
|
||||
@click.option('--set-obs-names', default='', help='Named field to set as index for obs.', metavar='<name>')
|
||||
@click.option('--set-var-names', default='', help='Named field to set as index for var.', metavar='<name>')
|
||||
@click.option('--make-obs-names-unique', default=True, is_flag=True,
|
||||
help='Ensure obs index is unique.', show_default=True)
|
||||
@click.option('--make-var-names-unique', default=True, is_flag=True,
|
||||
help='Ensure var index is unique.', show_default=True)
|
||||
@click.argument("data", nargs=1, metavar="<dataset: file or path to data>", required=True)
|
||||
@click.option("--layout", "-l", default=["umap", "tsne"], multiple=True, type=click.Choice(["umap", "tsne"]),
|
||||
help="Layout algorithm", show_default=True)
|
||||
@click.option("--recipe", "-r", default="none", type=click.Choice(["none", "seurat", "zheng17"]),
|
||||
help="Preprocessing to run.", show_default=True)
|
||||
@click.option("--output", "-o", default="", help="Save a new file to filename.", metavar="<filename>")
|
||||
@click.option("--plotting", "-p", default=False, is_flag=True, help="Whether to generate plots.", show_default=True)
|
||||
@click.option("--sparse", default=False, is_flag=True, help="Whether to force sparsity.", show_default=True)
|
||||
@click.option("--overwrite", default=False, is_flag=True, help="Allow file overwriting.", show_default=True)
|
||||
@click.option("--set-obs-names", default="", help="Named field to set as index for obs.", metavar="<name>")
|
||||
@click.option("--set-var-names", default="", help="Named field to set as index for var.", metavar="<name>")
|
||||
@click.option("--make-obs-names-unique", default=True, is_flag=True,
|
||||
help="Ensure obs index is unique.", show_default=True)
|
||||
@click.option("--make-var-names-unique", default=True, is_flag=True,
|
||||
help="Ensure var index is unique.", show_default=True)
|
||||
def prepare(data, layout, recipe, output, plotting, sparse, overwrite,
|
||||
set_obs_names, set_var_names, make_obs_names_unique, make_var_names_unique):
|
||||
"""Preprocesses data for use with cellxgene.
|
||||
@@ -33,9 +33,9 @@ def prepare(data, layout, recipe, output, plotting, sparse, overwrite,
|
||||
annotations, ensuring sparsity, and plotting results."""
|
||||
|
||||
# collect slow imports here to make CLI startup more responsive
|
||||
click.echo('[cellxgene] Starting CLI...')
|
||||
click.echo("[cellxgene] Starting CLI...")
|
||||
import matplotlib
|
||||
matplotlib.use('Agg')
|
||||
matplotlib.use("Agg")
|
||||
import scanpy.api as sc
|
||||
|
||||
# scanpy settings
|
||||
@@ -43,45 +43,45 @@ def prepare(data, layout, recipe, output, plotting, sparse, overwrite,
|
||||
sc.settings.autosave = True
|
||||
|
||||
# check args
|
||||
if sparse and not recipe == 'none':
|
||||
raise click.UsageError('Cannot use a recipe when forcing sparsity')
|
||||
if sparse and not recipe == "none":
|
||||
raise click.UsageError("Cannot use a recipe when forcing sparsity")
|
||||
|
||||
output = expanduser(output)
|
||||
if isfile(output) and not overwrite:
|
||||
raise click.UsageError(f'Cannot overwrite existing file {output}, try using the flag --overwrite')
|
||||
raise click.UsageError(f"Cannot overwrite existing file {output}, try using the flag --overwrite")
|
||||
|
||||
def load_data(data):
|
||||
if isfile(data):
|
||||
name, extension = splitext(data)
|
||||
if extension == '.h5ad':
|
||||
if extension == ".h5ad":
|
||||
adata = sc.read_h5ad(data)
|
||||
elif extension == '.loom':
|
||||
elif extension == ".loom":
|
||||
adata = sc.read_loom(data)
|
||||
else:
|
||||
raise click.FileError(data, hint='does not have a valid extension [.h5ad | .loom]')
|
||||
raise click.FileError(data, hint="does not have a valid extension [.h5ad | .loom]")
|
||||
elif isdir(data):
|
||||
if not data.endswith(sep):
|
||||
data += sep
|
||||
adata = sc.read_10x_mtx(data)
|
||||
else:
|
||||
raise click.FileError(data, hint='not a valid file or path')
|
||||
raise click.FileError(data, hint="not a valid file or path")
|
||||
|
||||
if not set_obs_names == '':
|
||||
if not set_obs_names == "":
|
||||
if set_obs_names not in adata.obs_keys():
|
||||
raise click.UsageError(f'obs {set_obs_names} not found, options are: {adata.obs_keys()}')
|
||||
raise click.UsageError(f"obs {set_obs_names} not found, options are: {adata.obs_keys()}")
|
||||
adata.obs_names = adata.obs[set_obs_names]
|
||||
if not set_var_names == '':
|
||||
if not set_var_names == "":
|
||||
if set_var_names not in adata.var_keys():
|
||||
raise click.UsageError(f'var {set_var_names} not found, options are: {adata.var_keys()}')
|
||||
raise click.UsageError(f"var {set_var_names} not found, options are: {adata.var_keys()}")
|
||||
adata.var_names = adata.var[set_var_names]
|
||||
if make_obs_names_unique:
|
||||
adata.obs_names_make_unique()
|
||||
if make_var_names_unique:
|
||||
adata.var_names_make_unique()
|
||||
if not adata._obs.index.is_unique:
|
||||
click.echo('Warning: obs index is not unique')
|
||||
click.echo("Warning: obs index is not unique")
|
||||
if not adata._var.index.is_unique:
|
||||
click.echo('Warning: var index is not unique')
|
||||
click.echo("Warning: var index is not unique")
|
||||
|
||||
return adata
|
||||
|
||||
@@ -90,9 +90,9 @@ def prepare(data, layout, recipe, output, plotting, sparse, overwrite,
|
||||
adata.X = csc_matrix(adata.X)
|
||||
|
||||
def run_recipe(adata):
|
||||
if recipe == 'seurat':
|
||||
if recipe == "seurat":
|
||||
sc.pp.recipe_seurat(adata)
|
||||
elif recipe == 'zheng17':
|
||||
elif recipe == "zheng17":
|
||||
sc.pp.recipe_zheng17(adata)
|
||||
else:
|
||||
sc.pp.filter_cells(adata, min_genes=5)
|
||||
@@ -104,9 +104,9 @@ def prepare(data, layout, recipe, output, plotting, sparse, overwrite,
|
||||
|
||||
def run_pca(adata):
|
||||
if sparse:
|
||||
sc.pp.pca(adata, svd_solver='arpack', zero_center=False)
|
||||
sc.pp.pca(adata, svd_solver="arpack", zero_center=False)
|
||||
else:
|
||||
sc.pp.pca(adata, svd_solver='arpack')
|
||||
sc.pp.pca(adata, svd_solver="arpack")
|
||||
|
||||
def run_neighbors(adata):
|
||||
sc.pp.neighbors(adata)
|
||||
@@ -115,46 +115,46 @@ def prepare(data, layout, recipe, output, plotting, sparse, overwrite,
|
||||
sc.tl.louvain(adata)
|
||||
|
||||
def run_layout(adata):
|
||||
if len(unique(adata.obs['louvain'].values)) < 10:
|
||||
palette = 'tab10'
|
||||
if len(unique(adata.obs["louvain"].values)) < 10:
|
||||
palette = "tab10"
|
||||
else:
|
||||
palette = 'tab20'
|
||||
palette = "tab20"
|
||||
|
||||
if 'umap' in layout:
|
||||
if "umap" in layout:
|
||||
sc.tl.umap(adata)
|
||||
if plotting:
|
||||
sc.pl.umap(adata, color='louvain', palette=palette, save='_louvain')
|
||||
sc.pl.umap(adata, color="louvain", palette=palette, save="_louvain")
|
||||
|
||||
if 'tsne' in layout:
|
||||
if "tsne" in layout:
|
||||
sc.tl.tsne(adata)
|
||||
if plotting:
|
||||
sc.pl.tsne(adata, color='louvain', palette=palette, save='_louvain')
|
||||
sc.pl.tsne(adata, color="louvain", palette=palette, save="_louvain")
|
||||
|
||||
def show_step(item):
|
||||
names = {
|
||||
'make_sparse': 'Ensuring sparsity',
|
||||
'run_recipe': 'Running preprocessing recipe "%s"' % recipe,
|
||||
'run_pca': 'Running PCA',
|
||||
'run_neighbors': 'Calculating neighbors',
|
||||
'run_louvain': 'Calculating clusters',
|
||||
'run_layout': 'Computing layout'
|
||||
"make_sparse": "Ensuring sparsity",
|
||||
"run_recipe": f"Running preprocessing recipe \"{recipe}\"",
|
||||
"run_pca": "Running PCA",
|
||||
"run_neighbors": "Calculating neighbors",
|
||||
"run_louvain": "Calculating clusters",
|
||||
"run_layout": "Computing layout"
|
||||
}
|
||||
if item is not None:
|
||||
return names[item.__name__]
|
||||
|
||||
steps = [make_sparse, run_recipe, run_pca, run_neighbors, run_louvain, run_layout]
|
||||
|
||||
click.echo(f'[cellxgene] Loading data from {data}, please wait...')
|
||||
click.echo(f"[cellxgene] Loading data from {data}, please wait...")
|
||||
adata = load_data(data)
|
||||
|
||||
click.echo('[cellxgene] Beginning preprocessing...')
|
||||
with click.progressbar(steps, label='[cellxgene] Progress', show_eta=False, item_show_func=show_step) as bar:
|
||||
click.echo("[cellxgene] Beginning preprocessing...")
|
||||
with click.progressbar(steps, label="[cellxgene] Progress", show_eta=False, item_show_func=show_step) as bar:
|
||||
for step in bar:
|
||||
step(adata)
|
||||
|
||||
# saving
|
||||
if not output == '':
|
||||
click.echo(f'[cellxgene] Saving results to {output}...')
|
||||
if not output == "":
|
||||
click.echo(f"[cellxgene] Saving results to {output}...")
|
||||
adata.write(output)
|
||||
|
||||
click.echo('[cellxgene] Success!')
|
||||
click.echo("[cellxgene] Success!")
|
||||
|
||||
Reference in New Issue
Block a user