Skip to content

Commit

Permalink
Support analysis on a subset of cells. (#133)
Browse files Browse the repository at this point in the history
* UI to subset cells based on annotations
* Option to skip QC (RNA and ADT) steps, e.g., when processing filtered datasets. (#130)
* Updated the analysis loader for new bakana calls.
* Sort custom selection indices
* more error catching
* update docs, changelog, bump version

Co-authored-by: Jayaram Kancherla <[email protected]>
  • Loading branch information
LTLA and jkanche authored Jul 23, 2022
1 parent 8069427 commit 6107617
Show file tree
Hide file tree
Showing 13 changed files with 472 additions and 125 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# Changelog

## V2.2.0
- Perform analysis on a subset of cells

![Subset cells](assets/subset.png)

## V2.0.0
- Support for a multi-modal analysis of ADT + RNA
- Added new parameter elements for ADT, integrated analysis
- Support multiple modalities in the marker selection
- Support multiple modalities in diagnostic plots

![Multimodal analysis](assets/v2_adt.gif)

## V1.2.0

- Visually compare embeddings across annotations
Expand Down
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Kana: Single cell RNA-seq analysis in the browser

*Kana* comes from the [Telugu](https://en.wikipedia.org/wiki/Telugu_language) word [kaṇaṁ (కణం)](https://www.shabdkosh.com/dictionary/english-telugu/%E0%B0%95%E0%B0%A3%E0%B0%82/%E0%B0%95%E0%B0%A3%E0%B0%82-meaning-in-telugu), which means ... drumroll... ***cell***

## Overview

**kana** is a web application for single-cell RNA-seq data analysis that works directly in the browser.
Expand Down Expand Up @@ -40,7 +42,8 @@ Briefly, this involves:
- Make custom cell selections and detect markers for this selection
- Cell type annotation for each cluster across user selected reference datasets
- Perform Integration or Batch correction using MNN correction. You can provide a single dataset containing multiple batches and specify the `batch` column in the cell annotations, or load multiple datasets where each dataset is considered a batch
- ADT aware for Cite-seq data
- Support Multi-modal analysis for Cite-seq data
- Perform analysis on subsets (filter based on cell annotation)

The interface provides a depiction of the dimensionality reduction of choice,
a ranking of marker genes for the cluster of interest,
Expand Down Expand Up @@ -90,7 +93,7 @@ We also create separate Web Workers for the t-SNE and UMAP steps so that they ca

![Worker Model](assets/scran.js.app.workers.png)

The Wasm code itself is compiled with PThreads support to enable parallelization of some analysis steps.
The WASM code itself is compiled with PThreads support to enable parallelization of some analysis steps.
This involves the use of a [`SharedArrayBuffer`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer) to efficiently share memory across Web Workers,
which in turn requires cross origin isolation of the site.
We achieve this by using a service worker to cache the resources and load the blobs with the relevant headers - hence the need for HTTPS.
Expand Down
Binary file added assets/subset.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/v2_adt.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "kana",
"description": "Single cell data analysis in the browser",
"version": "2.0.1",
"version": "2.2.0",
"private": true,
"author": {
"name": "Jayaram Kancherla",
Expand Down Expand Up @@ -32,7 +32,7 @@
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
"bakana": "^0.3.4",
"bakana": "^0.4.0",
"d3": "^7.1.1",
"epiviz.gl": "^1.0.2",
"epiviz.scatter.gl": "^0.0.5",
Expand Down
47 changes: 27 additions & 20 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ const App = () => {
// when a new custom selection of cells is made through the UI
useEffect(() => {

if (customSelection !== null && Object.keys(customSelection).length > 0) {
if (customSelection !== null && Object.keys(customSelection).length > 0 && !initLoadState) {
let csLen = `cs${Object.keys(customSelection).length}`;
var cs = customSelection[csLen];
scranWorker.postMessage({
Expand Down Expand Up @@ -425,14 +425,16 @@ const App = () => {
add_to_logs("complete", payload.type.toLowerCase().replace("_cache", ""), "finished (from cache)");
} else if (payload.type.toLowerCase().endsWith("data")) {
add_to_logs("complete", payload.type.toLowerCase().replace("_data", ""), "finished");
} else if (payload.type.toLowerCase().endsWith("error")) {
const { resp } = payload;
}

const { resp } = payload;
if (payload.type.toLowerCase().endsWith("error") || resp?.status === "ERROR") {
add_to_logs("error", `${resp.reason}`, "");

setScranError({
type: payload.type,
msg: resp.reason,
fatal: resp.fatal
fatal: resp?.fatal === undefined ? true: resp.fatal
});

return;
Expand Down Expand Up @@ -470,21 +472,26 @@ const App = () => {
} else if (payload.type === "quality_control_DATA") {
const { resp } = payload;

var ranges = {}, data = resp["data"], all = {};
if (!resp) {
setQcData(null);
setShowQCLoader(false);
} else {
var ranges = {}, data = resp["data"], all = {};

for (const [group, gvals] of Object.entries(data)) {
for (const [key, val] of Object.entries(gvals)) {
if (!all[key]) all[key] = [Infinity, -Infinity];
let [min, max] = getMinMax(val);
if (min < all[key][0]) all[key][0] = min;
if (max > all[key][1]) all[key][1] = max;
for (const [group, gvals] of Object.entries(data)) {
for (const [key, val] of Object.entries(gvals)) {
if (!all[key]) all[key] = [Infinity, -Infinity];
let [min, max] = getMinMax(val);
if (min < all[key][0]) all[key][0] = min;
if (max > all[key][1]) all[key][1] = max;
}
ranges[group] = all;
}
ranges[group] = all;

resp["ranges"] = ranges;
setQcData(resp);
setShowQCLoader(false);
}

resp["ranges"] = ranges;
setQcData(resp);
setShowQCLoader(false);
} else if (payload.type === "adt_quality_control_DATA") {
const { resp } = payload;

Expand Down Expand Up @@ -651,10 +658,10 @@ const App = () => {
setIndexedDBState(false);
} else if (payload.type === "loadedParameters") {
const { resp } = payload;
setLoadParams(resp);
setLoadParams(resp.parameters);

if (resp?.custom_selections?.selections) {
let cluster_count = clusterColors.length + Object.keys(resp?.custom_selections?.selections).length;
if (resp.other.custom_selections) {
let cluster_count = clusterColors.length + Object.keys(resp.other.custom_selections).length;
let cluster_colors = null;
if (cluster_count > Object.keys(palette).length) {
cluster_colors = randomColor({ luminosity: 'dark', count: cluster_count + 1 });
Expand All @@ -663,7 +670,7 @@ const App = () => {
}
setClusterColors(cluster_colors);

setCustomSelection(resp?.custom_selections?.selections);
setCustomSelection(resp.other.custom_selections);
}

setTimeout(() => {
Expand Down
38 changes: 38 additions & 0 deletions src/components/Analysis/Analysis.css
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,42 @@
.cell-top {
width: 100%;
height: 100%;
}

.subset-section {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-around;
align-items:flex-start;
padding: 5px;
width: 100%;
}

.subset-section-top {
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items:flex-start;
padding: 5px;
}

.subset-section-top > label {
margin-top: 5px;
}

.subset-range-field {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-around;
align-items:center;
padding: 5px;
}

.subset-range-field > h5 {
padding-right: 15px;
text-align: center;
vertical-align: middle;
padding-top: 5px;
}
Loading

0 comments on commit 6107617

Please sign in to comment.