diff --git a/docker-compose.yml b/docker-compose.yml index 95ee135..b3261c7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,4 +5,4 @@ services: dockerfile: Dockerfile ports: - 8080:8080 - image: bigdatainbiomedicine/simba-qc:0.2.2 + image: bigdatainbiomedicine/simba-qc:0.2.3 diff --git a/src/plots.py b/src/plots.py index 22609be..f9d36c1 100644 --- a/src/plots.py +++ b/src/plots.py @@ -5,27 +5,29 @@ from typing import Dict import numpy as np + @module.ui def plots_ui(): return ui.div( - ui.card( - ui.card_header("Scatter plot"), - ui.output_plot("plot_scatter") - ), + ui.card(ui.card_header("Number of cells"), ui.output_text("n_cells")), + ui.card(ui.card_header("Scatter plot"), ui.output_plot("plot_scatter")), ui.card( ui.card_header("Histograms"), ui.output_ui("coloring_histograms"), - ui.output_plot("plot_histograms") - ) + ui.output_plot("plot_histograms"), + ), ) @module.server -def plots_server(input, output, session, - _adata: reactive.Value[ad.AnnData], - _pretty_names: reactive.Value[Dict[str, str]], - _distributions: reactive.Value[Dict[str, Dict[str, float]]] - ): +def plots_server( + input, + output, + session, + _adata: reactive.Value[ad.AnnData], + _pretty_names: reactive.Value[Dict[str, str]], + _distributions: reactive.Value[Dict[str, Dict[str, float]]], +): @output @render.plot def plot_scatter(): @@ -42,12 +44,14 @@ def plot_scatter(): fig, ax = plt.subplots() - ax.scatter(adata.obs[x_col], - adata.obs[y_col], - c=adata.obs[color_col], - s=dot_size, - cmap='viridis') - + ax.scatter( + adata.obs[x_col], + adata.obs[y_col], + c=adata.obs[color_col], + s=dot_size, + cmap="viridis", + ) + ax.set_xlabel(pretty_names[x_col]) ax.set_ylabel(pretty_names[y_col]) @@ -57,7 +61,7 @@ def plot_scatter(): cbar.set_label(pretty_names[color_col]) return fig - + @output @render.ui def coloring_histograms(): @@ -65,8 +69,13 @@ def coloring_histograms(): if adata is None: return - - categorical_obs = [None] + [column for column in adata.obs.select_dtypes(include=["object", "category"]).columns] + + categorical_obs = [None] + [ + column + for column in adata.obs.select_dtypes( + include=["object", "category"] + ).columns + ] return ui.input_select("histo_coloring", "Coloring", categorical_obs) @@ -90,11 +99,7 @@ def plot_histograms(): for i, (col, pretty_name) in enumerate(pretty_names.items()): ax = axes[i // n_cols, i % n_cols] if n_rows > 1 else axes[i] - kwargs = { - "x": col, - "ax": ax, - "bins": 50 - } + kwargs = {"x": col, "ax": ax, "bins": 50} if coloring: kwargs["hue"] = coloring @@ -104,10 +109,34 @@ def plot_histograms(): current_distribution = distributions[col] # Add horizontal line for median - ax.axvline(current_distribution['median'], color='r', linestyle='--') + ax.axvline(current_distribution["median"], color="r", linestyle="--") for mads in [1, 2, 3]: - ax.axvline(min(current_distribution['median'] + mads * current_distribution['std'], current_distribution['max']), color='g', linestyle=':') - ax.axvline(max(current_distribution['median'] - mads * current_distribution['std'], current_distribution['min']), color='g', linestyle=':') + ax.axvline( + min( + current_distribution["median"] + + mads * current_distribution["std"], + current_distribution["max"], + ), + color="g", + linestyle=":", + ) + ax.axvline( + max( + current_distribution["median"] + - mads * current_distribution["std"], + current_distribution["min"], + ), + color="g", + linestyle=":", + ) + + return fig + + @render.text + def n_cells(): + adata = _adata.get() - return fig \ No newline at end of file + if adata is not None: + n_cells = adata.n_obs + return f"{n_cells} cells pass the current filtering thresholds"