diff --git a/server/cli/cli.py b/server/cli/cli.py index 0a6022ad..870c6b9d 100644 --- a/server/cli/cli.py +++ b/server/cli/cli.py @@ -1,6 +1,7 @@ import click from .launch import launch +from .prepare import prepare @click.group(name='cellxgene', context_settings=dict(max_content_width=85)) @@ -10,3 +11,4 @@ def cli(): cli.add_command(launch) +cli.add_command(prepare) diff --git a/prepare/cli.py b/server/cli/prepare.py similarity index 59% rename from prepare/cli.py rename to server/cli/prepare.py index 6ee7b722..8d5bd64e 100644 --- a/prepare/cli.py +++ b/server/cli/prepare.py @@ -4,28 +4,33 @@ from numpy import unique, ndarray from scipy.sparse.csc import csc_matrix from os.path import isfile, isdir, splitext, expanduser, sep -settings = dict(help_option_names=['-h', '--help']) - @click.command() -@click.argument('dataset', nargs=1, metavar='', required=True) +@click.argument('data', nargs=1, metavar='', required=True) @click.option('--layout', '-l', default=['umap', 'tsne'], multiple=True, type=click.Choice(['umap', 'tsne']), - help='layout algorithm', show_default=True) + 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='') -@click.option('--set-obs-names', default='', help='named field to set as index for obs', metavar='') -@click.option('--set-var-names', default='', help='named field to set as index for var', metavar='') -@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.option('--sparse', default=False, is_flag=True, help='whether to force sparsity', show_default=True) -@click.option('--overwriting', default=False, is_flag=True, help='whether to allow file overwriting', show_default=True) -@click.option('--plotting', '-p', default=False, is_flag=True, help='whether to generate plots', show_default=True) -def cli(dataset, layout, recipe, output, set_obs_names, set_var_names, - make_obs_names_unique, make_var_names_unique, sparse, overwriting, plotting): - """ - preprocesses data for use with cellxgene - """ + help='Preprocessing to run.', show_default=True) +@click.option('--output', '-o', default='', help='Save a new file to filename.', metavar='') +@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='') +@click.option('--set-var-names', default='', help='Named field to set as index for var.', metavar='') +@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. + + This tool runs a series of scanpy routines for preparing a dataset + for use with cellxgene. It loads data from different formats + (h5ad, loom, or a 10x directory), runs dimensionality reduction, + computes nearest neighbors, computes a layout, performs clustering, + and saves the results. Includes additional options for naming + annotations, ensuring sparsity, and plotting results.""" # collect slow imports here to make CLI startup more responsive click.echo('[cellxgene] Starting CLI...') @@ -43,31 +48,31 @@ def cli(dataset, layout, recipe, output, set_obs_names, set_var_names, output = expanduser(output) if isfile(output) and not overwrite: - raise click.UsageError('Cannot overwrite existing file %s, try using the flag --overwrite' % output) + raise click.UsageError(f'Cannot overwrite existing file {output}, try using the flag --overwrite') - def load_data(dataset): - if isfile(dataset): - name, extension = splitext(dataset) + def load_data(data): + if isfile(data): + name, extension = splitext(data) if extension == '.h5ad': - adata = sc.read_h5ad(dataset) + adata = sc.read_h5ad(data) elif extension == '.loom': - adata = sc.read_loom(dataset) + adata = sc.read_loom(data) else: - raise click.FileError(dataset, hint='does not have a valid extension [.h5ad | .loom]') - elif isdir(dataset): - if not dataset.endswith(sep): - dataset += sep - adata = sc.read_10x_mtx(dataset) + 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(dataset, hint='not a valid file or path') + raise click.FileError(data, hint='not a valid file or path') if not set_obs_names == '': if set_obs_names not in adata.obs_keys(): - raise click.UsageError('obs %s not found, options are: %s' % (set_obs_names, 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 set_var_names not in adata.var_keys(): - raise click.UsageError('var %s not found, options are: %s' % (set_var_names, 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() @@ -115,12 +120,12 @@ def cli(dataset, layout, recipe, output, set_obs_names, set_var_names, else: palette = 'tab20' - if layout == 'umap' or layout == 'umap+tsne': + if 'umap' in layout: sc.tl.umap(adata) if plotting: sc.pl.umap(adata, color='louvain', palette=palette, save='_louvain') - if layout == 'tsne' or layout == 'umap+tsne': + if 'tsne' in layout: sc.tl.tsne(adata) if plotting: sc.pl.tsne(adata, color='louvain', palette=palette, save='_louvain') @@ -139,8 +144,8 @@ def cli(dataset, layout, recipe, output, set_obs_names, set_var_names, steps = [make_sparse, run_recipe, run_pca, run_neighbors, run_louvain, run_layout] - click.echo('[cellxgene] Loading data from %s, please wait...' % dataset) - adata = load_data(dataset) + 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: @@ -149,11 +154,7 @@ def cli(dataset, layout, recipe, output, set_obs_names, set_var_names, # saving if not output == '': - click.echo('[cellxgene] Saving results to %s...' % output) + click.echo(f'[cellxgene] Saving results to {output}...') adata.write(output) - click.echo('[cellxgene] ' + click.style('Success!', fg='green')) - - -if __name__ == '__main__': - cli() + click.echo('[cellxgene] Success!')