mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-09-30 13:48:12 +08:00
GUI UI Elements (#816)
This commit is contained in:
+67
-53
@@ -1,4 +1,5 @@
|
||||
import errno
|
||||
import functools
|
||||
import logging
|
||||
from os import devnull
|
||||
from os.path import splitext, basename, getsize
|
||||
@@ -13,22 +14,56 @@ from server.app.util.errors import ScanpyFileError
|
||||
from server.app.util.utils import custom_format_warning
|
||||
from server.utils.utils import find_available_port, is_port_available
|
||||
|
||||
|
||||
# anything bigger than this will generate a special message
|
||||
BIG_FILE_SIZE_THRESHOLD = 100 * 2**20 # 100MB
|
||||
BIG_FILE_SIZE_THRESHOLD = 100 * 2 ** 20 # 100MB
|
||||
|
||||
|
||||
def common_args(func):
|
||||
"""
|
||||
Decorator to contain CLI args that will be common to both CLI and GUI: title and engine args.
|
||||
"""
|
||||
@click.option("--title", "-t", help="Title to display (if omitted will use file name).")
|
||||
@click.option(
|
||||
"--layout",
|
||||
"-l",
|
||||
default=[],
|
||||
multiple=True,
|
||||
show_default=True,
|
||||
help="Layout name, eg, 'umap'."
|
||||
)
|
||||
@click.option("--obs-names", default=None, metavar="", help="Name of annotation field to use for observations.")
|
||||
@click.option("--var-names", default=None, metavar="", help="Name of annotation to use for variables.")
|
||||
@click.option(
|
||||
"--max-category-items",
|
||||
default=1000,
|
||||
metavar="",
|
||||
show_default=True,
|
||||
help="Categories with more distinct values than this will not be displayed.",
|
||||
)
|
||||
@click.option(
|
||||
"--diffexp-lfc-cutoff",
|
||||
default=0.01,
|
||||
show_default=True,
|
||||
help="Relative expression cutoff used when selecting top N differentially expressed genes",
|
||||
)
|
||||
@functools.wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
return func(*args, **kwargs)
|
||||
return wrapper
|
||||
|
||||
|
||||
def parse_engine_args(layout, obs_names, var_names, max_category_items, diffexp_lfc_cutoff):
|
||||
return {
|
||||
"layout": layout,
|
||||
"max_category_items": max_category_items,
|
||||
"diffexp_lfc_cutoff": diffexp_lfc_cutoff,
|
||||
"obs_names": obs_names,
|
||||
"var_names": var_names,
|
||||
}
|
||||
|
||||
|
||||
@click.command()
|
||||
@click.argument("data", metavar="<data file>", type=click.Path(exists=True, file_okay=True, dir_okay=False))
|
||||
@click.option(
|
||||
"--layout",
|
||||
"-l",
|
||||
default=[],
|
||||
multiple=True,
|
||||
show_default=True,
|
||||
help="Layout name, eg, 'umap'."
|
||||
)
|
||||
@click.option("--title", "-t", help="Title to display (if omitted will use file name).", metavar="")
|
||||
@click.option(
|
||||
"--verbose",
|
||||
"-v",
|
||||
@@ -49,22 +84,7 @@ BIG_FILE_SIZE_THRESHOLD = 100 * 2**20 # 100MB
|
||||
)
|
||||
@click.option("--port", "-p", help="Port to run server on, if not specified cellxgene will find an available port.",
|
||||
metavar="", show_default=True)
|
||||
@click.option("--obs-names", default=None, metavar="", help="Name of annotation field to use for observations.")
|
||||
@click.option("--var-names", default=None, metavar="", help="Name of annotation to use for variables.")
|
||||
@click.option("--host", default="127.0.0.1", help="Host IP address")
|
||||
@click.option(
|
||||
"--max-category-items",
|
||||
default=1000,
|
||||
metavar="",
|
||||
show_default=True,
|
||||
help="Categories with more distinct values than this will not be displayed.",
|
||||
)
|
||||
@click.option(
|
||||
"--diffexp-lfc-cutoff",
|
||||
default=0.01,
|
||||
show_default=True,
|
||||
help="Relative expression cutoff used when selecting top N differentially expressed genes",
|
||||
)
|
||||
@click.option(
|
||||
"--scripts",
|
||||
default=[],
|
||||
@@ -72,20 +92,21 @@ BIG_FILE_SIZE_THRESHOLD = 100 * 2**20 # 100MB
|
||||
help="Additional script files to include in html page",
|
||||
show_default=True,
|
||||
)
|
||||
@common_args
|
||||
def launch(
|
||||
data,
|
||||
layout,
|
||||
title,
|
||||
verbose,
|
||||
debug,
|
||||
obs_names,
|
||||
var_names,
|
||||
open_browser,
|
||||
port,
|
||||
host,
|
||||
layout,
|
||||
obs_names,
|
||||
var_names,
|
||||
max_category_items,
|
||||
diffexp_lfc_cutoff,
|
||||
scripts,
|
||||
title,
|
||||
scripts
|
||||
):
|
||||
"""Launch the cellxgene data viewer.
|
||||
This web app lets you explore single-cell expression data.
|
||||
@@ -98,6 +119,7 @@ def launch(
|
||||
|
||||
> cellxgene launch <your data file> --title <your title>"""
|
||||
|
||||
e_args = parse_engine_args(layout, obs_names, var_names, max_category_items, diffexp_lfc_cutoff)
|
||||
# Startup message
|
||||
click.echo("[cellxgene] Starting the CLI...")
|
||||
|
||||
@@ -112,22 +134,22 @@ def launch(
|
||||
else:
|
||||
warnings.formatwarning = custom_format_warning
|
||||
|
||||
if scripts:
|
||||
click.echo(r"""
|
||||
/ / /\ \ \__ _ _ __ _ __ (_)_ __ __ _
|
||||
\ \/ \/ / _` | '__| '_ \| | '_ \ / _` |
|
||||
\ /\ / (_| | | | | | | | | | | (_| |
|
||||
\/ \/ \__,_|_| |_| |_|_|_| |_|\__, |
|
||||
|___/
|
||||
The --scripts flag is intended for developers to include google analytics etc. You could be opening yourself to a
|
||||
security risk by including the --scripts flag. Make sure you trust the scripts that you are including.
|
||||
""")
|
||||
scripts_pretty = ", ".join(scripts)
|
||||
click.confirm(f"Are you sure you want to inject these scripts: {scripts_pretty}?", abort=True)
|
||||
|
||||
if not verbose:
|
||||
sys.tracebacklimit = 0
|
||||
|
||||
if scripts:
|
||||
click.echo(r"""
|
||||
/ / /\ \ \__ _ _ __ _ __ (_)_ __ __ _
|
||||
\ \/ \/ / _` | '__| '_ \| | '_ \ / _` |
|
||||
\ /\ / (_| | | | | | | | | | | (_| |
|
||||
\/ \/ \__,_|_| |_| |_|_|_| |_|\__, |
|
||||
|___/
|
||||
The --scripts flag is intended for developers to include google analytics etc. You could be opening yourself to a
|
||||
security risk by including the --scripts flag. Make sure you trust the scripts that you are including.
|
||||
""")
|
||||
scripts_pretty = ", ".join(scripts)
|
||||
click.confirm(f"Are you sure you want to inject these scripts: {scripts_pretty}?", abort=True)
|
||||
|
||||
if not title:
|
||||
file_parts = splitext(basename(data))
|
||||
title = file_parts[0]
|
||||
@@ -170,16 +192,8 @@ security risk by including the --scripts flag. Make sure you trust the scripts t
|
||||
mpl.use("TkAgg")
|
||||
from server.app.scanpy_engine.scanpy_engine import ScanpyEngine
|
||||
|
||||
args = {
|
||||
"layout": layout,
|
||||
"max_category_items": max_category_items,
|
||||
"diffexp_lfc_cutoff": diffexp_lfc_cutoff,
|
||||
"obs_names": obs_names,
|
||||
"var_names": var_names,
|
||||
}
|
||||
|
||||
try:
|
||||
server.attach_data(ScanpyEngine(data, args), title=title)
|
||||
server.attach_data(ScanpyEngine(data, e_args), title=title)
|
||||
except ScanpyFileError as e:
|
||||
raise click.ClickException(f"{e}")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user