def launch(data, verbose, debug, open_browser, port, host, layout, obs_names, var_names, max_category_items, diffexp_lfc_cutoff, title, scripts): """Launch the cellxgene data viewer. This web app lets you explore single-cell expression data. Data must be in a format that cellxgene expects, read the "getting started" guide. Examples: > cellxgene launch example_dataset/pbmc3k.h5ad --title pbmc3k > 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...") # Argument checking name, extension = splitext(data) if extension != ".h5ad": raise click.FileError(basename(data), hint="file type must be .h5ad") if debug: verbose = True open_browser = False else: warnings.formatwarning = custom_format_warning 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] if port: if debug: raise click.ClickException( "--port and --debug may not be used together (try --verbose for error logging)." ) if not is_port_available(host, int(port)): raise click.ClickException( f"The port selected {port} is in use, please specify an open port using the --port flag." ) else: port = find_available_port(host) # Setup app cellxgene_url = f"http://{host}:{port}" # Import Flask app server = Server() server.create_app() server.app.config.update(SCRIPTS=scripts) if not verbose: log = logging.getLogger("werkzeug") log.setLevel(logging.ERROR) file_size = getsize(data) # if a big file, let the user know it may take a while to load. if file_size > BIG_FILE_SIZE_THRESHOLD: click.echo( f"[cellxgene] Loading data from {basename(data)}, this may take awhile..." ) else: click.echo(f"[cellxgene] Loading data from {basename(data)}.") # Fix for anaconda python. matplotlib typically expects python to be installed as a framework TKAgg is usually # available and fixes this issue. See https://matplotlib.org/faq/virtualenv_faq.html import matplotlib as mpl mpl.use("TkAgg") from server.app.scanpy_engine.scanpy_engine import ScanpyEngine try: server.attach_data(ScanpyEngine(data, e_args), title=title) except ScanpyFileError as e: raise click.ClickException(f"{e}") if open_browser: click.echo( f"[cellxgene] Launching! Opening your browser to {cellxgene_url} now." ) webbrowser.open(cellxgene_url) else: click.echo( f"[cellxgene] Launching! Please go to {cellxgene_url} in your browser." ) click.echo("[cellxgene] Type CTRL-C at any time to exit.") if not verbose: f = open(devnull, "w") sys.stdout = f try: server.app.run(host=host, debug=debug, port=port, threaded=True, use_debugger=False) except OSError as e: if e.errno == errno.EADDRINUSE: raise click.ClickException( "Port is in use, please specify an open port using the --port flag." ) from e raise
def launch(data, verbose, debug, open_browser, port, host, embedding, obs_names, var_names, max_category_items, diffexp_lfc_cutoff, title, scripts, about, experimental_label_file, backed, disable_diffexp): """Launch the cellxgene data viewer. This web app lets you explore single-cell expression data. Data must be in a format that cellxgene expects, read the "getting started" guide. Examples: > cellxgene launch example_dataset/pbmc3k.h5ad --title pbmc3k > cellxgene launch <your data file> --title <your title> > cellxgene launch <url>""" e_args = parse_engine_args(embedding, obs_names, var_names, max_category_items, diffexp_lfc_cutoff, experimental_label_file, backed, disable_diffexp) try: data_locator = DataLocator(data) except RuntimeError as re: raise click.ClickException( f"Unable to access data at {data}. {str(re)}") # Startup message click.echo("[cellxgene] Starting the CLI...") # Argument checking if data_locator.islocal(): # if data locator is local, apply file system conventions and other "cheap" # validation checks. If a URI, defer until we actually fetch the data and # try to read it. Many of these tests don't make sense for URIs (eg, extension- # based typing). if not data_locator.exists(): raise click.FileError(data, hint="file does not exist") if not data_locator.isfile(): raise click.FileError(data, hint="data is not a file") name, extension = splitext(data) if extension != ".h5ad": raise click.FileError(basename(data), hint="file type must be .h5ad") if debug: verbose = True open_browser = False else: warnings.formatwarning = custom_format_warning 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] if port: if debug: raise click.ClickException( "--port and --debug may not be used together (try --verbose for error logging)." ) if not is_port_available(host, int(port)): raise click.ClickException( f"The port selected {port} is in use, please specify an open port using the --port flag." ) else: port = find_available_port(host) if experimental_label_file: lf_name, lf_ext = splitext(experimental_label_file) if lf_ext and lf_ext != ".csv": raise click.FileError(basename(experimental_label_file), hint="label file type must be .csv") if about: def url_check(url): try: result = urlparse(url) if all([result.scheme, result.netloc]): return True else: return False except ValueError: return False if not url_check(about): raise click.ClickException( "Must provide an absolute URL for --about. (Example format: http://example.com)" ) # Setup app cellxgene_url = f"http://{host}:{port}" # Import Flask app server = Server() server.create_app() server.app.config.update(SCRIPTS=scripts) if not verbose: log = logging.getLogger("werkzeug") log.setLevel(logging.ERROR) file_size = data_locator.size() if data_locator.islocal() else 0 # if a big file, let the user know it may take a while to load. if file_size > BIG_FILE_SIZE_THRESHOLD: click.echo( f"[cellxgene] Loading data from {basename(data)}, this may take a while..." ) else: click.echo(f"[cellxgene] Loading data from {basename(data)}.") from server.app.scanpy_engine.scanpy_engine import ScanpyEngine try: server.attach_data(ScanpyEngine(data_locator, e_args), title=title, about=about) except ScanpyFileError as e: raise click.ClickException(f"{e}") if not disable_diffexp and server.app.data.config['diffexp_may_be_slow']: click.echo(f"[cellxgene] CAUTION: due to the size of your dataset, " f"running differential expression may take longer or fail.") if open_browser: click.echo( f"[cellxgene] Launching! Opening your browser to {cellxgene_url} now." ) webbrowser.open(cellxgene_url) else: click.echo( f"[cellxgene] Launching! Please go to {cellxgene_url} in your browser." ) click.echo("[cellxgene] Type CTRL-C at any time to exit.") if not verbose: f = open(devnull, "w") sys.stdout = f try: server.app.run(host=host, debug=debug, port=port, threaded=False if debug else True, use_debugger=False) except OSError as e: if e.errno == errno.EADDRINUSE: raise click.ClickException( "Port is in use, please specify an open port using the --port flag." ) from e raise
from server.gui.browser import CefWidget, CefApplication from server.gui.workers import Worker, SiteReadyWorker from server.gui.utils import WINDOWS, LINUX, MAC, FileLoadSignals, Emitter, WorkerSignals, FileChanged from server.utils.utils import find_available_port if WINDOWS or LINUX: dirname = dirname(PySide2.__file__) plugin_path = join(dirname, 'plugins', 'platforms') environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = plugin_path # Configuration # TODO remember this or calculate it? WIDTH = 1300 HEIGHT = 800 MAX_CONTENT_WIDTH = 700 GUI_PORT = find_available_port("localhost") BROWSER_INDEX = 0 LOAD_INDEX = 1 class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__(None) self.cef_widget = None self.data_widget = None self.stacked_layout = None self.parent_conn, self.child_conn = None, None self.load_emitter = None self.emitter_thread = None self.worker = None self.url = f"http://localhost:{GUI_PORT}/"