From e7b441b0f0af782ea1c6339d77061d321ef76dbb Mon Sep 17 00:00:00 2001 From: Mehrtash Babadi Date: Thu, 12 Sep 2024 17:24:35 +0000 Subject: [PATCH 01/15] expose root node --- cellarium/cas/postprocessing/ontology_aware.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/cellarium/cas/postprocessing/ontology_aware.py b/cellarium/cas/postprocessing/ontology_aware.py index 4f60e7b..c809ab1 100644 --- a/cellarium/cas/postprocessing/ontology_aware.py +++ b/cellarium/cas/postprocessing/ontology_aware.py @@ -300,10 +300,14 @@ def _get_subtree_phyloxml_string(subtree_dict: OrderedDict, node_name: str, leve def get_most_granular_top_k_calls( - aggregated_scores: AggregatedCellOntologyScores, cl: CellOntologyCache, min_acceptable_score: float, top_k: int = 1 + aggregated_scores: AggregatedCellOntologyScores, + cl: CellOntologyCache, + min_acceptable_score: float, + top_k: int = 1, + root_note: str = CL_EUKARYOTIC_CELL_ROOT_NODE ) -> t.List[tuple]: depth_list = list( - map(cl.get_longest_path_lengths_from_target(CL_EUKARYOTIC_CELL_ROOT_NODE).get, aggregated_scores.cl_names) + map(cl.get_longest_path_lengths_from_target(root_note).get, aggregated_scores.cl_names) ) sorted_score_and_depth_list = sorted( list( @@ -319,7 +323,7 @@ def get_most_granular_top_k_calls( trunc_list = sorted_score_and_depth_list[:top_k] # pad with root node if necessary for _ in range(len(trunc_list) - top_k): - trunc_list.append((1.0, 0, CL_EUKARYOTIC_CELL_ROOT_NODE)) + trunc_list.append((1.0, 0, root_note)) return trunc_list @@ -329,6 +333,7 @@ def compute_most_granular_top_k_calls_single( min_acceptable_score: float, top_k: int = 3, obs_prefix: str = "cas_cell_type", + root_note: str = CL_EUKARYOTIC_CELL_ROOT_NODE ): top_k_calls_dict = defaultdict(list) scores_array_nc = adata.obsm[CAS_CL_SCORES_ANNDATA_OBSM_KEY].toarray() @@ -358,7 +363,7 @@ def compute_most_granular_top_k_calls_single( for i_cell in range(adata.n_obs): aggregated_scores.aggregated_scores_c = scores_array_nc[i_cell] - top_k_output = get_most_granular_top_k_calls(aggregated_scores, cl, min_acceptable_score, top_k) + top_k_output = get_most_granular_top_k_calls(aggregated_scores, cl, min_acceptable_score, top_k, root_note) for k in range(top_k): top_k_calls_dict[f"{obs_prefix}_score_{k + 1}"].append(top_k_output[k][0]) top_k_calls_dict[f"{obs_prefix}_name_{k + 1}"].append(top_k_output[k][2]) @@ -378,6 +383,7 @@ def compute_most_granular_top_k_calls_cluster( aggregation_score_threshod: float = 1e-4, top_k: int = 3, obs_prefix: str = "cas_cell_type", + root_note: str = CL_EUKARYOTIC_CELL_ROOT_NODE ): top_k_calls_dict = dict() for k in range(top_k): @@ -394,7 +400,7 @@ def _update_list(target_list, indices, value): aggregated_scores = get_aggregated_cas_ontology_aware_scores( adata, obs_indices, aggregation_op, aggregation_domain, aggregation_score_threshod ) - top_k_output = get_most_granular_top_k_calls(aggregated_scores, cl, min_acceptable_score, top_k) + top_k_output = get_most_granular_top_k_calls(aggregated_scores, cl, min_acceptable_score, top_k, root_note) for k in range(top_k): _update_list(top_k_calls_dict[f"{obs_prefix}_score_{k + 1}"], obs_indices, top_k_output[k][0]) _update_list(top_k_calls_dict[f"{obs_prefix}_name_{k + 1}"], obs_indices, top_k_output[k][2]) From 298ee678ac3e89efc559639057412b522efaed91 Mon Sep 17 00:00:00 2001 From: Mehrtash Babadi Date: Thu, 12 Sep 2024 17:24:35 +0000 Subject: [PATCH 02/15] expose root node --- cellarium/cas/postprocessing/ontology_aware.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/cellarium/cas/postprocessing/ontology_aware.py b/cellarium/cas/postprocessing/ontology_aware.py index 4f60e7b..c809ab1 100644 --- a/cellarium/cas/postprocessing/ontology_aware.py +++ b/cellarium/cas/postprocessing/ontology_aware.py @@ -300,10 +300,14 @@ def _get_subtree_phyloxml_string(subtree_dict: OrderedDict, node_name: str, leve def get_most_granular_top_k_calls( - aggregated_scores: AggregatedCellOntologyScores, cl: CellOntologyCache, min_acceptable_score: float, top_k: int = 1 + aggregated_scores: AggregatedCellOntologyScores, + cl: CellOntologyCache, + min_acceptable_score: float, + top_k: int = 1, + root_note: str = CL_EUKARYOTIC_CELL_ROOT_NODE ) -> t.List[tuple]: depth_list = list( - map(cl.get_longest_path_lengths_from_target(CL_EUKARYOTIC_CELL_ROOT_NODE).get, aggregated_scores.cl_names) + map(cl.get_longest_path_lengths_from_target(root_note).get, aggregated_scores.cl_names) ) sorted_score_and_depth_list = sorted( list( @@ -319,7 +323,7 @@ def get_most_granular_top_k_calls( trunc_list = sorted_score_and_depth_list[:top_k] # pad with root node if necessary for _ in range(len(trunc_list) - top_k): - trunc_list.append((1.0, 0, CL_EUKARYOTIC_CELL_ROOT_NODE)) + trunc_list.append((1.0, 0, root_note)) return trunc_list @@ -329,6 +333,7 @@ def compute_most_granular_top_k_calls_single( min_acceptable_score: float, top_k: int = 3, obs_prefix: str = "cas_cell_type", + root_note: str = CL_EUKARYOTIC_CELL_ROOT_NODE ): top_k_calls_dict = defaultdict(list) scores_array_nc = adata.obsm[CAS_CL_SCORES_ANNDATA_OBSM_KEY].toarray() @@ -358,7 +363,7 @@ def compute_most_granular_top_k_calls_single( for i_cell in range(adata.n_obs): aggregated_scores.aggregated_scores_c = scores_array_nc[i_cell] - top_k_output = get_most_granular_top_k_calls(aggregated_scores, cl, min_acceptable_score, top_k) + top_k_output = get_most_granular_top_k_calls(aggregated_scores, cl, min_acceptable_score, top_k, root_note) for k in range(top_k): top_k_calls_dict[f"{obs_prefix}_score_{k + 1}"].append(top_k_output[k][0]) top_k_calls_dict[f"{obs_prefix}_name_{k + 1}"].append(top_k_output[k][2]) @@ -378,6 +383,7 @@ def compute_most_granular_top_k_calls_cluster( aggregation_score_threshod: float = 1e-4, top_k: int = 3, obs_prefix: str = "cas_cell_type", + root_note: str = CL_EUKARYOTIC_CELL_ROOT_NODE ): top_k_calls_dict = dict() for k in range(top_k): @@ -394,7 +400,7 @@ def _update_list(target_list, indices, value): aggregated_scores = get_aggregated_cas_ontology_aware_scores( adata, obs_indices, aggregation_op, aggregation_domain, aggregation_score_threshod ) - top_k_output = get_most_granular_top_k_calls(aggregated_scores, cl, min_acceptable_score, top_k) + top_k_output = get_most_granular_top_k_calls(aggregated_scores, cl, min_acceptable_score, top_k, root_note) for k in range(top_k): _update_list(top_k_calls_dict[f"{obs_prefix}_score_{k + 1}"], obs_indices, top_k_output[k][0]) _update_list(top_k_calls_dict[f"{obs_prefix}_name_{k + 1}"], obs_indices, top_k_output[k][2]) From b98133724d9b7f828879cc48043df23e1eec2407 Mon Sep 17 00:00:00 2001 From: Mehrtash Babadi Date: Thu, 12 Sep 2024 19:53:35 +0000 Subject: [PATCH 03/15] refactoring some preprocessing methods out of vis --- .../cas/postprocessing/ontology_aware.py | 20 ++++++------------- .../circular_tree_plot_umap_dash_app/app.py | 16 +++++++++------ 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/cellarium/cas/postprocessing/ontology_aware.py b/cellarium/cas/postprocessing/ontology_aware.py index c809ab1..5080ddf 100644 --- a/cellarium/cas/postprocessing/ontology_aware.py +++ b/cellarium/cas/postprocessing/ontology_aware.py @@ -10,7 +10,7 @@ from cellarium.cas.models import CellTypeOntologyAwareResults -from .cell_ontology.cell_ontology_cache import CL_CELL_ROOT_NODE, CL_EUKARYOTIC_CELL_ROOT_NODE, CellOntologyCache +from .cell_ontology.cell_ontology_cache import CL_CELL_ROOT_NODE, CellOntologyCache from .common import get_obs_indices_for_cluster # AnnData-related constants @@ -63,7 +63,7 @@ def convert_cas_ontology_aware_response_to_score_matrix( def insert_cas_ontology_aware_response_into_adata( - cas_ontology_aware_response: CellTypeOntologyAwareResults, adata: AnnData, cl: CellOntologyCache + cas_ontology_aware_response: CellTypeOntologyAwareResults, adata: AnnData, cl: CellOntologyCache = CellOntologyCache() ) -> None: """ Inserts Cellarium CAS ontology aware response into `obsm` property of a provided AnnData file as a @@ -180,7 +180,7 @@ def get_aggregated_cas_ontology_aware_scores( def convert_aggregated_cell_ontology_scores_to_rooted_tree( aggregated_scores: AggregatedCellOntologyScores, cl: CellOntologyCache, - root_cl_name: str = CL_EUKARYOTIC_CELL_ROOT_NODE, + root_cl_name: str = CL_CELL_ROOT_NODE, min_fraction: float = 0.0, hidden_cl_names_set: t.Optional[t.Set[str]] = None, ) -> OrderedDict: @@ -232,14 +232,6 @@ def build_subtree(node_dict: OrderedDict, node_name: str) -> OrderedDict: # Validate that this is actually a rooted tree and if not recalculate with the base cell node if len(tree_dict) == 1: # singly-rooted tree return tree_dict - elif root_cl_name != CL_CELL_ROOT_NODE: - return convert_aggregated_cell_ontology_scores_to_rooted_tree( - aggregated_scores=aggregated_scores, - cl=cl, - root_cl_name=CL_CELL_ROOT_NODE, - min_fraction=min_fraction, - hidden_cl_names_set=hidden_cl_names_set, - ) else: raise ValueError("The tree is not singly-rooted.") @@ -304,7 +296,7 @@ def get_most_granular_top_k_calls( cl: CellOntologyCache, min_acceptable_score: float, top_k: int = 1, - root_note: str = CL_EUKARYOTIC_CELL_ROOT_NODE + root_note: str = CL_CELL_ROOT_NODE ) -> t.List[tuple]: depth_list = list( map(cl.get_longest_path_lengths_from_target(root_note).get, aggregated_scores.cl_names) @@ -333,7 +325,7 @@ def compute_most_granular_top_k_calls_single( min_acceptable_score: float, top_k: int = 3, obs_prefix: str = "cas_cell_type", - root_note: str = CL_EUKARYOTIC_CELL_ROOT_NODE + root_note: str = CL_CELL_ROOT_NODE ): top_k_calls_dict = defaultdict(list) scores_array_nc = adata.obsm[CAS_CL_SCORES_ANNDATA_OBSM_KEY].toarray() @@ -383,7 +375,7 @@ def compute_most_granular_top_k_calls_cluster( aggregation_score_threshod: float = 1e-4, top_k: int = 3, obs_prefix: str = "cas_cell_type", - root_note: str = CL_EUKARYOTIC_CELL_ROOT_NODE + root_note: str = CL_CELL_ROOT_NODE ): top_k_calls_dict = dict() for k in range(top_k): diff --git a/cellarium/cas/visualization/circular_tree_plot_umap_dash_app/app.py b/cellarium/cas/visualization/circular_tree_plot_umap_dash_app/app.py index 92affca..841be73 100644 --- a/cellarium/cas/visualization/circular_tree_plot_umap_dash_app/app.py +++ b/cellarium/cas/visualization/circular_tree_plot_umap_dash_app/app.py @@ -18,6 +18,7 @@ from cellarium.cas.models import CellTypeOntologyAwareResults from cellarium.cas.postprocessing import ( CAS_CL_SCORES_ANNDATA_OBSM_KEY, + CAS_METADATA_ANNDATA_UNS_KEY, CellOntologyScoresAggregationDomain, CellOntologyScoresAggregationOp, convert_aggregated_cell_ontology_scores_to_rooted_tree, @@ -26,7 +27,7 @@ get_obs_indices_for_cluster, insert_cas_ontology_aware_response_into_adata, ) -from cellarium.cas.postprocessing.cell_ontology import CL_EUKARYOTIC_CELL_ROOT_NODE, CellOntologyCache +from cellarium.cas.postprocessing.cell_ontology import CL_CELL_ROOT_NODE, CellOntologyCache from cellarium.cas.visualization._components.circular_tree_plot import CircularTreePlot from cellarium.cas.visualization.ui_utils import ConfigValue, find_and_kill_process @@ -195,6 +196,7 @@ def __init__( circular_tree_start_angle: int = 180, circular_tree_end_angle: int = 360, figure_height: int = 400, + root_node: str = CL_CELL_ROOT_NODE, hidden_cl_names_set: set[str] = DEFAULT_HIDDEN_CL_NAMES_SET, shown_cl_names_set: set[str] = DEFAULT_SHOWN_CL_NAMES_SET, score_colorscale: t.Union[str, list] = "Viridis", @@ -217,11 +219,16 @@ def __init__( self.circular_tree_start_angle = circular_tree_start_angle self.circular_tree_end_angle = circular_tree_end_angle self.height = figure_height + self.root_node = root_node self.hidden_cl_names_set = hidden_cl_names_set self.shown_cl_names_set = shown_cl_names_set self.score_colorscale = score_colorscale - assert "X_umap" in adata.obsm, "UMAP coordinates not found in adata.obsm['X_umap']" + assert "X_umap" in adata.obsm, "UMAP coordinates not found in adata.obsm['X_umap']. \ + This visualisation requires precomputed UMAP coordinates." + assert (CAS_CL_SCORES_ANNDATA_OBSM_KEY in adata.obsm) and (CAS_METADATA_ANNDATA_UNS_KEY in adata.uns), \ + "Cell type ontology scores not found in the provided AnnData file. Please please run \ + `cellarium.cas.insert_cas_ontology_aware_response_into_adata` prior to running this visualisation." # setup cell domains self.cell_domain_map = OrderedDict() @@ -243,9 +250,6 @@ def __init__( # instantiate the cell type ontology cache self.cl = CellOntologyCache() - # insert CA ontology-aware response into adata - insert_cas_ontology_aware_response_into_adata(cas_ontology_aware_response, adata, self.cl) - # instantiate the Dash app self.app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP, dbc.icons.BOOTSTRAP]) self.server = self.app.server @@ -284,7 +288,7 @@ def __instantiate_circular_tree_plot(self) -> CircularTreePlot: rooted_tree = convert_aggregated_cell_ontology_scores_to_rooted_tree( aggregated_scores=aggregated_scores, cl=self.cl, - root_cl_name=CL_EUKARYOTIC_CELL_ROOT_NODE, + root_cl_name=self.root_node, min_fraction=self.min_cell_fraction.get(), hidden_cl_names_set=self.hidden_cl_names_set, ) From 30a42226b09917faf7ba4f3a0e53043a6caf13f6 Mon Sep 17 00:00:00 2001 From: Mehrtash Babadi Date: Thu, 12 Sep 2024 20:31:26 +0000 Subject: [PATCH 04/15] logging instead of print --- cellarium/cas/client.py | 3 ++- cellarium/cas/service.py | 5 +++-- cellarium/cas/settings.py | 7 +++++++ .../circular_tree_plot_umap_dash_app/app.py | 9 ++++----- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/cellarium/cas/client.py b/cellarium/cas/client.py index 3fe3519..b6f054c 100644 --- a/cellarium/cas/client.py +++ b/cellarium/cas/client.py @@ -7,6 +7,7 @@ import time import typing as t import warnings +import logging from contextlib import contextmanager from uuid import UUID, uuid4 @@ -70,7 +71,7 @@ def __init__( api_token=api_token, api_url=api_url, client_session_id=self.client_session_id ) - self.__print(f"Connecting to the Cellarium Cloud backend with session {self.client_session_id}...") + logging.info(f"Connecting to the Cellarium Cloud backend with session {self.client_session_id}...") self.user_info = self.cas_api_service.validate_token() username = self.user_info["username"] self.__print(f"User is {username}") diff --git a/cellarium/cas/service.py b/cellarium/cas/service.py index 9e7d711..2bc7f6d 100644 --- a/cellarium/cas/service.py +++ b/cellarium/cas/service.py @@ -1,6 +1,7 @@ import asyncio import json import ssl +import logging import typing as t from contextlib import ContextDecorator from contextvars import ContextVar @@ -15,7 +16,7 @@ from cellarium.cas import constants, endpoints, exceptions, settings if settings.is_interactive_environment(): - print("Running in an interactive environment, applying nest_asyncio") + logging.debug("Running in an interactive environment, applying nest_asyncio") nest_asyncio.apply() # Context variable to track the action id for the current context @@ -210,7 +211,7 @@ async def _aiohttp_async_post( except (json.decoder.JSONDecodeError, client_exceptions.ClientResponseError): response_detail = await response.text() except KeyError: - print("Response body doesn't have a 'detail' key, returning full response body") + logging.warning("Response body doesn't have a 'detail' key, returning full response body") response_detail = str(await response.json()) self.raise_response_exception(status_code=status_code, detail=response_detail) diff --git a/cellarium/cas/settings.py b/cellarium/cas/settings.py index 455429e..8852629 100644 --- a/cellarium/cas/settings.py +++ b/cellarium/cas/settings.py @@ -1,3 +1,5 @@ +import logging + NUM_ATTEMPTS_PER_CHUNK_DEFAULT = 7 MAX_NUM_REQUESTS_AT_A_TIME = 8 START_RETRY_DELAY = 5 @@ -7,6 +9,11 @@ MAX_CHUNK_SIZE_SEARCH_METHOD = 500 CELLARIUM_CLOUD_BACKEND_URL = "https://cellarium-cloud-api.cellarium.ai" +logging.basicConfig( + level=logging.INFO, # Set the desired logging level + format='* [%(asctime)s] %(message)s', # Define the format + datefmt='%H:%M:%S.%f'[:12] # Set the date format to match HH:MM:SS.mmm +) def is_interactive_environment() -> bool: """ diff --git a/cellarium/cas/visualization/circular_tree_plot_umap_dash_app/app.py b/cellarium/cas/visualization/circular_tree_plot_umap_dash_app/app.py index 841be73..17b0410 100644 --- a/cellarium/cas/visualization/circular_tree_plot_umap_dash_app/app.py +++ b/cellarium/cas/visualization/circular_tree_plot_umap_dash_app/app.py @@ -177,7 +177,6 @@ class CASCircularTreePlotUMAPDashApp: def __init__( self, adata: AnnData, - cas_ontology_aware_response: CellTypeOntologyAwareResults, cluster_label_obs_column: t.Optional[str] = None, aggregation_op: CellOntologyScoresAggregationOp = CellOntologyScoresAggregationOp.MEAN, aggregation_domain: CellOntologyScoresAggregationDomain = CellOntologyScoresAggregationDomain.OVER_THRESHOLD, @@ -224,11 +223,11 @@ def __init__( self.shown_cl_names_set = shown_cl_names_set self.score_colorscale = score_colorscale - assert "X_umap" in adata.obsm, "UMAP coordinates not found in adata.obsm['X_umap']. \ - This visualisation requires precomputed UMAP coordinates." + assert "X_umap" in adata.obsm, "UMAP coordinates not found in adata.obsm['X_umap']. " \ + "This visualisation requires precomputed UMAP coordinates." assert (CAS_CL_SCORES_ANNDATA_OBSM_KEY in adata.obsm) and (CAS_METADATA_ANNDATA_UNS_KEY in adata.uns), \ - "Cell type ontology scores not found in the provided AnnData file. Please please run \ - `cellarium.cas.insert_cas_ontology_aware_response_into_adata` prior to running this visualisation." + "Cell type ontology scores not found in the provided AnnData file. Please please run " \ + "`cellarium.cas.insert_cas_ontology_aware_response_into_adata` prior to running this visualisation." # setup cell domains self.cell_domain_map = OrderedDict() From 20aafb6b8e5a0b1c2b5eac04160c74fa833c18b0 Mon Sep 17 00:00:00 2001 From: Mehrtash Babadi Date: Thu, 12 Sep 2024 20:49:55 +0000 Subject: [PATCH 05/15] more logging fixes --- .../cell_ontology/cell_ontology_cache.py | 2 +- cellarium/cas/settings.py | 6 +++--- .../circular_tree_plot_umap_dash_app/app.py | 13 +++++-------- notebooks/quickstart_tutorial.ipynb | 19 +++++++++++-------- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/cellarium/cas/postprocessing/cell_ontology/cell_ontology_cache.py b/cellarium/cas/postprocessing/cell_ontology/cell_ontology_cache.py index bc15293..6a28271 100644 --- a/cellarium/cas/postprocessing/cell_ontology/cell_ontology_cache.py +++ b/cellarium/cas/postprocessing/cell_ontology/cell_ontology_cache.py @@ -56,7 +56,7 @@ def __init__(self, cl_owl_path: str = DEFAULT_CL_OWL_PATH): """ with suppress_stderr(): - log(logging.INFO, f"Loading cell ontology OWL from:\n{cl_owl_path}") + logging.info(f"Loading cell ontology OWL from: {cl_owl_path}") cl = owlready2.get_ontology(cl_owl_path).load() # only keep CL classes with a singleton label diff --git a/cellarium/cas/settings.py b/cellarium/cas/settings.py index 8852629..f9b000a 100644 --- a/cellarium/cas/settings.py +++ b/cellarium/cas/settings.py @@ -10,9 +10,9 @@ CELLARIUM_CLOUD_BACKEND_URL = "https://cellarium-cloud-api.cellarium.ai" logging.basicConfig( - level=logging.INFO, # Set the desired logging level - format='* [%(asctime)s] %(message)s', # Define the format - datefmt='%H:%M:%S.%f'[:12] # Set the date format to match HH:MM:SS.mmm + level=logging.INFO, + format='* [%(asctime)s.%(msecs)03d] %(message)s', + datefmt='%H:%M:%S' ) def is_interactive_environment() -> bool: diff --git a/cellarium/cas/visualization/circular_tree_plot_umap_dash_app/app.py b/cellarium/cas/visualization/circular_tree_plot_umap_dash_app/app.py index 17b0410..3804794 100644 --- a/cellarium/cas/visualization/circular_tree_plot_umap_dash_app/app.py +++ b/cellarium/cas/visualization/circular_tree_plot_umap_dash_app/app.py @@ -3,7 +3,6 @@ import tempfile import typing as t from collections import OrderedDict -from logging import log import dash_bootstrap_components as dbc import numpy as np @@ -15,7 +14,6 @@ from dash.development.base_component import Component from plotly.express.colors import sample_colorscale -from cellarium.cas.models import CellTypeOntologyAwareResults from cellarium.cas.postprocessing import ( CAS_CL_SCORES_ANNDATA_OBSM_KEY, CAS_METADATA_ANNDATA_UNS_KEY, @@ -24,8 +22,7 @@ convert_aggregated_cell_ontology_scores_to_rooted_tree, generate_phyloxml_from_scored_cell_ontology_tree, get_aggregated_cas_ontology_aware_scores, - get_obs_indices_for_cluster, - insert_cas_ontology_aware_response_into_adata, + get_obs_indices_for_cluster ) from cellarium.cas.postprocessing.cell_ontology import CL_CELL_ROOT_NODE, CellOntologyCache from cellarium.cas.visualization._components.circular_tree_plot import CircularTreePlot @@ -256,19 +253,19 @@ def __init__( self.__setup_initialization() self.__setup_callbacks() - def run(self, port: int = 8050, **kwargs): + def run(self, port: int = 8050, jupyter_mode: str = "inline", **kwargs): """ Run the Dash application on the specified port. :param port: The port on which to run the Dash application. |br| `Default:` ``8050`` """ - log(logging.INFO, "Starting Dash application on port {port}...") + logging.info(f"Starting Dash application on port {port}...") try: - self.app.run_server(port=port, jupyter_mode="inline", jupyter_height=self.height + 100, **kwargs) + self.app.run_server(port=port, jupyter_mode=jupyter_mode, jupyter_height=self.height + 100, **kwargs) except OSError: # Dash raises OSError if the port is already in use find_and_kill_process(port) - self.app.run_server(port=port, jupyter_mode="inline", jupyter_height=self.height + 100, **kwargs) + self.app.run_server(port=port, jupyter_mode=jupyter_mode, jupyter_height=self.height + 100, **kwargs) def __instantiate_circular_tree_plot(self) -> CircularTreePlot: # reduce scores over the provided cells diff --git a/notebooks/quickstart_tutorial.ipynb b/notebooks/quickstart_tutorial.ipynb index 0004763..360860d 100644 --- a/notebooks/quickstart_tutorial.ipynb +++ b/notebooks/quickstart_tutorial.ipynb @@ -29,7 +29,7 @@ "metadata": {}, "outputs": [], "source": [ - "!pip install --force-reinstall cellarium-cas[vis]" + "!pip install --no-cache-dir cellarium-cas[vis]" ] }, { @@ -197,7 +197,7 @@ "metadata": {}, "outputs": [], "source": [ - "api_token = \"\"" + "api_token = \"\"" ] }, { @@ -222,7 +222,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The response will contain a list of annotation models and their brief descriptions. You need to choose the model that is suitable for your dataset. For this tutorial, choose a model that is suitable for annotating human scRNA-seq datasets:" + "The response will contain a list of annotation models and their brief descriptions. You need to choose the model that is suitable for your dataset. For this tutorial, choose a model that is suitable for annotating human scRNA-seq datasets. At the time of writing, the default model is `cellarium-pca-default-v1`:" ] }, { @@ -232,7 +232,7 @@ "outputs": [], "source": [ "# Select the annotation model\n", - "cas_model_name = ''" + "cas_model_name = 'cellarium-pca-default-v1'" ] }, { @@ -334,15 +334,18 @@ "source": [ "from cellarium.cas._io import suppress_stderr\n", "from cellarium.cas.visualization import CASCircularTreePlotUMAPDashApp\n", + "from cellarium.cas.postprocessing import insert_cas_ontology_aware_response_into_adata\n", + "\n", + "# Insert the CAS ontology-aware cell type query response into the AnnData object for the visualization application\n", + "insert_cas_ontology_aware_response_into_adata(cas_ontology_aware_response, adata)\n", "\n", "DASH_SERVER_PORT = 8050\n", "\n", "with suppress_stderr():\n", " CASCircularTreePlotUMAPDashApp(\n", - " adata, # the AnnData file\n", - " cas_ontology_aware_response, # CAS response\n", + " adata=adata, # the AnnData file\n", " cluster_label_obs_column=\"cluster_label\", # (optional) The .obs column name containing cluster labels \n", - " ).run(port=DASH_SERVER_PORT, debug=False, jupyter_width=\"100%\")" + " ).run(port=DASH_SERVER_PORT, debug=False, jupyter_width=800)" ] }, { @@ -471,7 +474,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.9" + "version": "3.10.13" } }, "nbformat": 4, From fc5044bdacad69ec713a4f4bcbf23d54c915061b Mon Sep 17 00:00:00 2001 From: Mehrtash Babadi Date: Thu, 12 Sep 2024 20:53:35 +0000 Subject: [PATCH 06/15] linting --- cellarium/cas/client.py | 2 +- cellarium/cas/postprocessing/ontology_aware.py | 16 +++++++--------- cellarium/cas/service.py | 2 +- cellarium/cas/settings.py | 7 ++----- .../circular_tree_plot_umap_dash_app/app.py | 11 +++++++---- 5 files changed, 18 insertions(+), 20 deletions(-) diff --git a/cellarium/cas/client.py b/cellarium/cas/client.py index b6f054c..c726328 100644 --- a/cellarium/cas/client.py +++ b/cellarium/cas/client.py @@ -1,13 +1,13 @@ import asyncio import datetime import functools +import logging import math import operator import pkgutil import time import typing as t import warnings -import logging from contextlib import contextmanager from uuid import UUID, uuid4 diff --git a/cellarium/cas/postprocessing/ontology_aware.py b/cellarium/cas/postprocessing/ontology_aware.py index 690d51c..06de4ca 100644 --- a/cellarium/cas/postprocessing/ontology_aware.py +++ b/cellarium/cas/postprocessing/ontology_aware.py @@ -63,9 +63,9 @@ def convert_cas_ontology_aware_response_to_score_matrix( def insert_cas_ontology_aware_response_into_adata( - cas_ontology_aware_response: CellTypeOntologyAwareResults, - adata: AnnData, - cl: CellOntologyCache = CellOntologyCache() + cas_ontology_aware_response: CellTypeOntologyAwareResults, + adata: AnnData, + cl: CellOntologyCache = CellOntologyCache(), ) -> None: """ Inserts Cellarium CAS ontology aware response into `obsm` property of a provided AnnData file as a @@ -298,11 +298,9 @@ def get_most_granular_top_k_calls( cl: CellOntologyCache, min_acceptable_score: float, top_k: int = 1, - root_note: str = CL_CELL_ROOT_NODE + root_note: str = CL_CELL_ROOT_NODE, ) -> t.List[tuple]: - depth_list = list( - map(cl.get_longest_path_lengths_from_target(root_note).get, aggregated_scores.cl_names) - ) + depth_list = list(map(cl.get_longest_path_lengths_from_target(root_note).get, aggregated_scores.cl_names)) sorted_score_and_depth_list = sorted( list( (score, depth, cl_name) @@ -327,7 +325,7 @@ def compute_most_granular_top_k_calls_single( min_acceptable_score: float, top_k: int = 3, obs_prefix: str = "cas_cell_type", - root_note: str = CL_CELL_ROOT_NODE + root_note: str = CL_CELL_ROOT_NODE, ): top_k_calls_dict = defaultdict(list) scores_array_nc = adata.obsm[CAS_CL_SCORES_ANNDATA_OBSM_KEY].toarray() @@ -377,7 +375,7 @@ def compute_most_granular_top_k_calls_cluster( aggregation_score_threshod: float = 1e-4, top_k: int = 3, obs_prefix: str = "cas_cell_type", - root_note: str = CL_CELL_ROOT_NODE + root_note: str = CL_CELL_ROOT_NODE, ): top_k_calls_dict = dict() for k in range(top_k): diff --git a/cellarium/cas/service.py b/cellarium/cas/service.py index 2bc7f6d..73966fa 100644 --- a/cellarium/cas/service.py +++ b/cellarium/cas/service.py @@ -1,7 +1,7 @@ import asyncio import json -import ssl import logging +import ssl import typing as t from contextlib import ContextDecorator from contextvars import ContextVar diff --git a/cellarium/cas/settings.py b/cellarium/cas/settings.py index f9b000a..86f5c6d 100644 --- a/cellarium/cas/settings.py +++ b/cellarium/cas/settings.py @@ -9,11 +9,8 @@ MAX_CHUNK_SIZE_SEARCH_METHOD = 500 CELLARIUM_CLOUD_BACKEND_URL = "https://cellarium-cloud-api.cellarium.ai" -logging.basicConfig( - level=logging.INFO, - format='* [%(asctime)s.%(msecs)03d] %(message)s', - datefmt='%H:%M:%S' -) +logging.basicConfig(level=logging.INFO, format="* [%(asctime)s.%(msecs)03d] %(message)s", datefmt="%H:%M:%S") + def is_interactive_environment() -> bool: """ diff --git a/cellarium/cas/visualization/circular_tree_plot_umap_dash_app/app.py b/cellarium/cas/visualization/circular_tree_plot_umap_dash_app/app.py index 3804794..b326dbb 100644 --- a/cellarium/cas/visualization/circular_tree_plot_umap_dash_app/app.py +++ b/cellarium/cas/visualization/circular_tree_plot_umap_dash_app/app.py @@ -22,7 +22,7 @@ convert_aggregated_cell_ontology_scores_to_rooted_tree, generate_phyloxml_from_scored_cell_ontology_tree, get_aggregated_cas_ontology_aware_scores, - get_obs_indices_for_cluster + get_obs_indices_for_cluster, ) from cellarium.cas.postprocessing.cell_ontology import CL_CELL_ROOT_NODE, CellOntologyCache from cellarium.cas.visualization._components.circular_tree_plot import CircularTreePlot @@ -220,11 +220,14 @@ def __init__( self.shown_cl_names_set = shown_cl_names_set self.score_colorscale = score_colorscale - assert "X_umap" in adata.obsm, "UMAP coordinates not found in adata.obsm['X_umap']. " \ + assert "X_umap" in adata.obsm, ( + "UMAP coordinates not found in adata.obsm['X_umap']. " "This visualisation requires precomputed UMAP coordinates." - assert (CAS_CL_SCORES_ANNDATA_OBSM_KEY in adata.obsm) and (CAS_METADATA_ANNDATA_UNS_KEY in adata.uns), \ - "Cell type ontology scores not found in the provided AnnData file. Please please run " \ + ) + assert (CAS_CL_SCORES_ANNDATA_OBSM_KEY in adata.obsm) and (CAS_METADATA_ANNDATA_UNS_KEY in adata.uns), ( + "Cell type ontology scores not found in the provided AnnData file. Please please run " "`cellarium.cas.insert_cas_ontology_aware_response_into_adata` prior to running this visualisation." + ) # setup cell domains self.cell_domain_map = OrderedDict() From 75fe873ba799f5eea32359efd8ca539117adaa58 Mon Sep 17 00:00:00 2001 From: Mehrtash Babadi Date: Thu, 12 Sep 2024 21:03:55 +0000 Subject: [PATCH 07/15] set the root note to eukaryotic cell in the tutorial --- notebooks/quickstart_tutorial.ipynb | 1 + 1 file changed, 1 insertion(+) diff --git a/notebooks/quickstart_tutorial.ipynb b/notebooks/quickstart_tutorial.ipynb index 360860d..93f798c 100644 --- a/notebooks/quickstart_tutorial.ipynb +++ b/notebooks/quickstart_tutorial.ipynb @@ -344,6 +344,7 @@ "with suppress_stderr():\n", " CASCircularTreePlotUMAPDashApp(\n", " adata=adata, # the AnnData file\n", + " root_node=\"CL_0000255\", # set to CL root node to \"eukaryotic cell\"\n", " cluster_label_obs_column=\"cluster_label\", # (optional) The .obs column name containing cluster labels \n", " ).run(port=DASH_SERVER_PORT, debug=False, jupyter_width=800)" ] From f7577777f24cee4cb5c1ab49192da5dd932099be Mon Sep 17 00:00:00 2001 From: Mehrtash Babadi Date: Thu, 12 Sep 2024 21:11:10 +0000 Subject: [PATCH 08/15] update thresholds in the tutorial notebook --- notebooks/quickstart_tutorial.ipynb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/notebooks/quickstart_tutorial.ipynb b/notebooks/quickstart_tutorial.ipynb index 93f798c..f75f3a1 100644 --- a/notebooks/quickstart_tutorial.ipynb +++ b/notebooks/quickstart_tutorial.ipynb @@ -346,7 +346,7 @@ " adata=adata, # the AnnData file\n", " root_node=\"CL_0000255\", # set to CL root node to \"eukaryotic cell\"\n", " cluster_label_obs_column=\"cluster_label\", # (optional) The .obs column name containing cluster labels \n", - " ).run(port=DASH_SERVER_PORT, debug=False, jupyter_width=800)" + " ).run(port=DASH_SERVER_PORT, debug=False, jupyter_width=\"1000\")" ] }, { @@ -389,7 +389,7 @@ "pp.compute_most_granular_top_k_calls_single(\n", " adata=adata,\n", " cl=cl,\n", - " min_acceptable_score=0.1, # minimum acceptable score for a call\n", + " min_acceptable_score=0.2, # minimum acceptable evidence score for a cell type call\n", " top_k=3, # how many top calls to make?\n", " obs_prefix=\"cas_cell_type\" # .obs column to write the top-k calls to\n", ")" @@ -431,7 +431,7 @@ "pp.compute_most_granular_top_k_calls_cluster(\n", " adata=adata,\n", " cl=cl,\n", - " min_acceptable_score=0.1, # minimum acceptable score for a call\n", + " min_acceptable_score=0.2, # minimum acceptable evidence score for a cell type call\n", " cluster_label_obs_column='cluster_label', # .obs column containing cluster labels\n", " top_k=3, # how many top calls to make?\n", " obs_prefix='cas_cell_type_cluster' # .obs column to write the top-k calls to\n", From 19ef38a37c013e9d106ab749dc2671bbef9aab41 Mon Sep 17 00:00:00 2001 From: Mehrtash Babadi Date: Thu, 12 Sep 2024 21:14:06 +0000 Subject: [PATCH 09/15] import settings before logging --- .../cas/postprocessing/cell_ontology/cell_ontology_cache.py | 2 +- .../cas/visualization/circular_tree_plot_umap_dash_app/app.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cellarium/cas/postprocessing/cell_ontology/cell_ontology_cache.py b/cellarium/cas/postprocessing/cell_ontology/cell_ontology_cache.py index 6a28271..bc861e0 100644 --- a/cellarium/cas/postprocessing/cell_ontology/cell_ontology_cache.py +++ b/cellarium/cas/postprocessing/cell_ontology/cell_ontology_cache.py @@ -1,12 +1,12 @@ import logging import typing as t from functools import lru_cache -from logging import log import networkx as nx import owlready2 from scipy import sparse as sp +from cellarium.cas import settings from cellarium.cas._io import suppress_stderr # Used in CZ CELLxGENE schema v5: diff --git a/cellarium/cas/visualization/circular_tree_plot_umap_dash_app/app.py b/cellarium/cas/visualization/circular_tree_plot_umap_dash_app/app.py index b326dbb..68757a0 100644 --- a/cellarium/cas/visualization/circular_tree_plot_umap_dash_app/app.py +++ b/cellarium/cas/visualization/circular_tree_plot_umap_dash_app/app.py @@ -14,6 +14,7 @@ from dash.development.base_component import Component from plotly.express.colors import sample_colorscale +from cellarium.cas import settings from cellarium.cas.postprocessing import ( CAS_CL_SCORES_ANNDATA_OBSM_KEY, CAS_METADATA_ANNDATA_UNS_KEY, From 8272dab43727f3e8311806c29d39234f8a3940f1 Mon Sep 17 00:00:00 2001 From: nmalfroy Date: Mon, 30 Sep 2024 13:20:19 -0400 Subject: [PATCH 10/15] Ignore unused import needed for log formatting Might want to eventually rethink us changing the logging --- .../cas/postprocessing/cell_ontology/cell_ontology_cache.py | 2 +- .../cas/visualization/circular_tree_plot_umap_dash_app/app.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cellarium/cas/postprocessing/cell_ontology/cell_ontology_cache.py b/cellarium/cas/postprocessing/cell_ontology/cell_ontology_cache.py index bc861e0..a677ffe 100644 --- a/cellarium/cas/postprocessing/cell_ontology/cell_ontology_cache.py +++ b/cellarium/cas/postprocessing/cell_ontology/cell_ontology_cache.py @@ -6,7 +6,7 @@ import owlready2 from scipy import sparse as sp -from cellarium.cas import settings +from cellarium.cas import settings # noqa from cellarium.cas._io import suppress_stderr # Used in CZ CELLxGENE schema v5: diff --git a/cellarium/cas/visualization/circular_tree_plot_umap_dash_app/app.py b/cellarium/cas/visualization/circular_tree_plot_umap_dash_app/app.py index 68757a0..e1f1bbd 100644 --- a/cellarium/cas/visualization/circular_tree_plot_umap_dash_app/app.py +++ b/cellarium/cas/visualization/circular_tree_plot_umap_dash_app/app.py @@ -14,7 +14,7 @@ from dash.development.base_component import Component from plotly.express.colors import sample_colorscale -from cellarium.cas import settings +from cellarium.cas import settings # noqa from cellarium.cas.postprocessing import ( CAS_CL_SCORES_ANNDATA_OBSM_KEY, CAS_METADATA_ANNDATA_UNS_KEY, From 25118a4b5b3aacbd0031e79b1d4498963b182ed9 Mon Sep 17 00:00:00 2001 From: nmalfroy Date: Mon, 30 Sep 2024 13:25:18 -0400 Subject: [PATCH 11/15] Make linting pass --- .../cas/postprocessing/cell_ontology/cell_ontology_cache.py | 2 +- .../cas/visualization/circular_tree_plot_umap_dash_app/app.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cellarium/cas/postprocessing/cell_ontology/cell_ontology_cache.py b/cellarium/cas/postprocessing/cell_ontology/cell_ontology_cache.py index a677ffe..30b8fa6 100644 --- a/cellarium/cas/postprocessing/cell_ontology/cell_ontology_cache.py +++ b/cellarium/cas/postprocessing/cell_ontology/cell_ontology_cache.py @@ -6,7 +6,7 @@ import owlready2 from scipy import sparse as sp -from cellarium.cas import settings # noqa +from cellarium.cas import settings # noqa from cellarium.cas._io import suppress_stderr # Used in CZ CELLxGENE schema v5: diff --git a/cellarium/cas/visualization/circular_tree_plot_umap_dash_app/app.py b/cellarium/cas/visualization/circular_tree_plot_umap_dash_app/app.py index e1f1bbd..c257d8a 100644 --- a/cellarium/cas/visualization/circular_tree_plot_umap_dash_app/app.py +++ b/cellarium/cas/visualization/circular_tree_plot_umap_dash_app/app.py @@ -14,7 +14,7 @@ from dash.development.base_component import Component from plotly.express.colors import sample_colorscale -from cellarium.cas import settings # noqa +from cellarium.cas import settings # noqa from cellarium.cas.postprocessing import ( CAS_CL_SCORES_ANNDATA_OBSM_KEY, CAS_METADATA_ANNDATA_UNS_KEY, From 36a9d810646b3c26810f106e2292d2f3e87b4024 Mon Sep 17 00:00:00 2001 From: Mehrtash Babadi Date: Mon, 7 Oct 2024 15:46:32 +0000 Subject: [PATCH 12/15] bugfix in ontology-aware post processing --- cellarium/cas/postprocessing/ontology_aware.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cellarium/cas/postprocessing/ontology_aware.py b/cellarium/cas/postprocessing/ontology_aware.py index 06de4ca..a75e648 100644 --- a/cellarium/cas/postprocessing/ontology_aware.py +++ b/cellarium/cas/postprocessing/ontology_aware.py @@ -314,7 +314,7 @@ def get_most_granular_top_k_calls( ) trunc_list = sorted_score_and_depth_list[:top_k] # pad with root node if necessary - for _ in range(len(trunc_list) - top_k): + for _ in range(top_k - len(trunc_list)): trunc_list.append((1.0, 0, root_note)) return trunc_list From a90f7fb8d88c830382907d8d2c79c4ba62bfee8e Mon Sep 17 00:00:00 2001 From: Mehrtash Babadi Date: Mon, 7 Oct 2024 16:26:10 +0000 Subject: [PATCH 13/15] package logger --- cellarium/cas/__init__.py | 3 ++- cellarium/cas/client.py | 4 ++-- cellarium/cas/logging.py | 17 +++++++++++++++++ .../cell_ontology/cell_ontology_cache.py | 4 ++-- cellarium/cas/service.py | 6 +++--- cellarium/cas/settings.py | 5 +++-- cellarium/cas/visualization/__init__.py | 4 ++-- .../circular_tree_plot_umap_dash_app/app.py | 4 ++-- 8 files changed, 33 insertions(+), 14 deletions(-) create mode 100644 cellarium/cas/logging.py diff --git a/cellarium/cas/__init__.py b/cellarium/cas/__init__.py index 9740146..6ce9f1d 100644 --- a/cellarium/cas/__init__.py +++ b/cellarium/cas/__init__.py @@ -1,6 +1,6 @@ from cellarium.cas.client import CASClient -from . import constants, exceptions, postprocessing, preprocessing, service, settings, version, visualization +from . import constants, exceptions, logging, postprocessing, preprocessing, service, settings, version, visualization __version__ = version.get_version() @@ -15,4 +15,5 @@ "service", "settings", "version", + "logging", ] diff --git a/cellarium/cas/client.py b/cellarium/cas/client.py index a0e6265..6c3c9e2 100644 --- a/cellarium/cas/client.py +++ b/cellarium/cas/client.py @@ -1,7 +1,6 @@ import asyncio import datetime import functools -import logging import math import operator import pkgutil @@ -15,6 +14,7 @@ from anndata import ImplicitModificationWarning from deprecated import deprecated +from cellarium.cas.logging import logger from cellarium.cas.service import action_context_manager from . import _io, constants, exceptions, models, preprocessing, service, settings, version @@ -71,7 +71,7 @@ def __init__( api_token=api_token, api_url=api_url, client_session_id=self.client_session_id ) - logging.info(f"Connecting to the Cellarium Cloud backend with session {self.client_session_id}...") + logger.info(f"Connecting to the Cellarium Cloud backend with session {self.client_session_id}...") self.user_info = self.cas_api_service.validate_token() username = self.user_info["username"] self.__print(f"User is {username}") diff --git a/cellarium/cas/logging.py b/cellarium/cas/logging.py new file mode 100644 index 0000000..c1ad726 --- /dev/null +++ b/cellarium/cas/logging.py @@ -0,0 +1,17 @@ +import logging + +from cellarium.cas import settings + +# Create a custom logger for the package +logger = logging.getLogger("cellarium.cas") +logger.setLevel(settings.LOGGING_LEVEL) + +# Create a handler +handler = logging.StreamHandler() + +# Create a formatter and set it for the handler +formatter = logging.Formatter(fmt=settings.LOGGING_FORMAT, datefmt=settings.LOGGING_DATE_FORMAT) +handler.setFormatter(formatter) + +# Add the handler to the logger +logger.addHandler(handler) diff --git a/cellarium/cas/postprocessing/cell_ontology/cell_ontology_cache.py b/cellarium/cas/postprocessing/cell_ontology/cell_ontology_cache.py index 30b8fa6..e6723e7 100644 --- a/cellarium/cas/postprocessing/cell_ontology/cell_ontology_cache.py +++ b/cellarium/cas/postprocessing/cell_ontology/cell_ontology_cache.py @@ -1,4 +1,3 @@ -import logging import typing as t from functools import lru_cache @@ -8,6 +7,7 @@ from cellarium.cas import settings # noqa from cellarium.cas._io import suppress_stderr +from cellarium.cas.logging import logger # Used in CZ CELLxGENE schema v5: # https://github.com/chanzuckerberg/single-cell-curation/blob/main/schema/5.0.0/schema.md @@ -56,7 +56,7 @@ def __init__(self, cl_owl_path: str = DEFAULT_CL_OWL_PATH): """ with suppress_stderr(): - logging.info(f"Loading cell ontology OWL from: {cl_owl_path}") + logger.info(f"Loading cell ontology OWL from: {cl_owl_path}") cl = owlready2.get_ontology(cl_owl_path).load() # only keep CL classes with a singleton label diff --git a/cellarium/cas/service.py b/cellarium/cas/service.py index 73966fa..fcd16df 100644 --- a/cellarium/cas/service.py +++ b/cellarium/cas/service.py @@ -1,6 +1,5 @@ import asyncio import json -import logging import ssl import typing as t from contextlib import ContextDecorator @@ -14,9 +13,10 @@ from aiohttp import client_exceptions from cellarium.cas import constants, endpoints, exceptions, settings +from cellarium.cas.logging import logger if settings.is_interactive_environment(): - logging.debug("Running in an interactive environment, applying nest_asyncio") + logger.debug("Running in an interactive environment, applying nest_asyncio") nest_asyncio.apply() # Context variable to track the action id for the current context @@ -211,7 +211,7 @@ async def _aiohttp_async_post( except (json.decoder.JSONDecodeError, client_exceptions.ClientResponseError): response_detail = await response.text() except KeyError: - logging.warning("Response body doesn't have a 'detail' key, returning full response body") + logger.warning("Response body doesn't have a 'detail' key, returning full response body") response_detail = str(await response.json()) self.raise_response_exception(status_code=status_code, detail=response_detail) diff --git a/cellarium/cas/settings.py b/cellarium/cas/settings.py index 86f5c6d..c87443d 100644 --- a/cellarium/cas/settings.py +++ b/cellarium/cas/settings.py @@ -8,8 +8,9 @@ AIOHTTP_READ_TIMEOUT_SECONDS = 730 MAX_CHUNK_SIZE_SEARCH_METHOD = 500 CELLARIUM_CLOUD_BACKEND_URL = "https://cellarium-cloud-api.cellarium.ai" - -logging.basicConfig(level=logging.INFO, format="* [%(asctime)s.%(msecs)03d] %(message)s", datefmt="%H:%M:%S") +LOGGING_LEVEL = logging.INFO +LOGGING_FORMAT = "* [%(asctime)s.%(msecs)03d] %(message)s" +LOGGING_DATE_FORMAT = "%H:%M:%S" def is_interactive_environment() -> bool: diff --git a/cellarium/cas/visualization/__init__.py b/cellarium/cas/visualization/__init__.py index 361380a..eb9cc5c 100644 --- a/cellarium/cas/visualization/__init__.py +++ b/cellarium/cas/visualization/__init__.py @@ -1,4 +1,4 @@ -import logging +from cellarium.cas.logging import logger try: from .circular_tree_plot_umap_dash_app.app import CASCircularTreePlotUMAPDashApp # noqa @@ -6,7 +6,7 @@ __all__ = ["CASCircularTreePlotUMAPDashApp", "find_and_kill_process"] except ImportError: - logging.warn( + logger.warning( """ Visualization dependencies not installed. To install the Cellarium CAS Client with visualation dependencies, please run: diff --git a/cellarium/cas/visualization/circular_tree_plot_umap_dash_app/app.py b/cellarium/cas/visualization/circular_tree_plot_umap_dash_app/app.py index c257d8a..dd21820 100644 --- a/cellarium/cas/visualization/circular_tree_plot_umap_dash_app/app.py +++ b/cellarium/cas/visualization/circular_tree_plot_umap_dash_app/app.py @@ -14,7 +14,7 @@ from dash.development.base_component import Component from plotly.express.colors import sample_colorscale -from cellarium.cas import settings # noqa +from cellarium.cas.logging import logger from cellarium.cas.postprocessing import ( CAS_CL_SCORES_ANNDATA_OBSM_KEY, CAS_METADATA_ANNDATA_UNS_KEY, @@ -264,7 +264,7 @@ def run(self, port: int = 8050, jupyter_mode: str = "inline", **kwargs): :param port: The port on which to run the Dash application. |br| `Default:` ``8050`` """ - logging.info(f"Starting Dash application on port {port}...") + logger.info(f"Starting Dash application on port {port}...") try: self.app.run_server(port=port, jupyter_mode=jupyter_mode, jupyter_height=self.height + 100, **kwargs) except OSError: # Dash raises OSError if the port is already in use From 36449febd23077702cc9b4b1298797c75b0dbce1 Mon Sep 17 00:00:00 2001 From: Mehrtash Babadi Date: Mon, 7 Oct 2024 16:26:23 +0000 Subject: [PATCH 14/15] notebook updates --- notebooks/quickstart_tutorial.ipynb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/notebooks/quickstart_tutorial.ipynb b/notebooks/quickstart_tutorial.ipynb index f75f3a1..82dfc57 100644 --- a/notebooks/quickstart_tutorial.ipynb +++ b/notebooks/quickstart_tutorial.ipynb @@ -222,17 +222,17 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The response will contain a list of annotation models and their brief descriptions. You need to choose the model that is suitable for your dataset. For this tutorial, choose a model that is suitable for annotating human scRNA-seq datasets. At the time of writing, the default model is `cellarium-pca-default-v1`:" + "The response will contain a list of annotation models and their brief descriptions. You need to choose the model that is suitable for your dataset. For this tutorial, we set `cas_model_name` to `None`, which implies choosing the default model. The default model is suitable for annotating human scRNA-seq datasets." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ - "# Select the annotation model\n", - "cas_model_name = 'cellarium-pca-default-v1'" + "# Select the annotation model; 'None' for choosing the default model\n", + "cas_model_name = None" ] }, { @@ -346,7 +346,7 @@ " adata=adata, # the AnnData file\n", " root_node=\"CL_0000255\", # set to CL root node to \"eukaryotic cell\"\n", " cluster_label_obs_column=\"cluster_label\", # (optional) The .obs column name containing cluster labels \n", - " ).run(port=DASH_SERVER_PORT, debug=False, jupyter_width=\"1000\")" + " ).run(port=DASH_SERVER_PORT, debug=False, jupyter_width=\"100%\")" ] }, { From 148bb01882ac4fa79f8e29d6812ac17674b73faa Mon Sep 17 00:00:00 2001 From: Mehrtash Babadi Date: Mon, 7 Oct 2024 16:29:04 +0000 Subject: [PATCH 15/15] remove unused import --- .../cas/visualization/circular_tree_plot_umap_dash_app/app.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cellarium/cas/visualization/circular_tree_plot_umap_dash_app/app.py b/cellarium/cas/visualization/circular_tree_plot_umap_dash_app/app.py index dd21820..2b78e29 100644 --- a/cellarium/cas/visualization/circular_tree_plot_umap_dash_app/app.py +++ b/cellarium/cas/visualization/circular_tree_plot_umap_dash_app/app.py @@ -1,4 +1,3 @@ -import logging import os import tempfile import typing as t