Color by gene set mean expression (#2157)

* colorby histo

* color graph by mean expression

* move var index after returns

* add genesets as an argument

* varindex

* undo redo for mean expression

* destructure

* ternary

* Revert "destructure"

This reverts commit 2d9432c1c7.

* color by mean for diffexp
This commit is contained in:
Colin Megill
2021-04-22 13:58:30 -04:00
committed by GitHub
parent 860547ced1
commit fd2a7a53ab
10 changed files with 170 additions and 27 deletions
@@ -44,6 +44,8 @@ const LABEL_WIDTH_ANNO = LABEL_WIDTH - ANNO_BUTTON_WIDTH;
schema,
crossfilter: state.obsCrossfilter,
isUserAnno,
genesets: state.genesets.genesets,
differential: state.differential,
};
})
class Category extends React.PureComponent {
@@ -142,9 +144,16 @@ class Category extends React.PureComponent {
*/
const { schema } = annoMatrix;
const { colorAccessor, colorMode } = colors;
const { genesets, differential } = this.props;
let colorDataPromise = Promise.resolve(null);
if (colorAccessor) {
const query = createColorQuery(colorMode, colorAccessor, schema);
const query = createColorQuery(
colorMode,
colorAccessor,
schema,
genesets,
differential.diffExp
);
if (query) colorDataPromise = annoMatrix.fetch(...query);
}
const [categoryData, colorData] = await Promise.all([
@@ -106,16 +106,26 @@ const continuous = (selectorId, colorScale, colorAccessor) => {
@connect((state) => ({
annoMatrix: state.annoMatrix,
colors: state.colors,
genesets: state.genesets.genesets,
differential: state.differential,
}))
class ContinuousLegend extends React.Component {
async componentDidUpdate(prevProps) {
const { annoMatrix, colors } = this.props;
const { annoMatrix, colors, genesets, differential } = this.props;
if (!colors || !annoMatrix) return;
if (colors !== prevProps?.colors || annoMatrix !== prevProps?.annoMatrix) {
const { schema } = annoMatrix;
const { colorMode, colorAccessor, userColors } = colors;
const colorQuery = createColorQuery(colorMode, colorAccessor, schema);
const colorQuery = createColorQuery(
colorMode,
colorAccessor,
schema,
genesets,
differential.diffExp
);
const colorDf = colorQuery ? await annoMatrix.fetch(...colorQuery) : null;
const colorTable = createColorTable(
colorMode,
@@ -184,7 +184,12 @@ class GeneSet extends React.Component {
)}
</span>
<div>
<GenesetMenus genesetsEditable geneset={setName} />
<GenesetMenus
isOpen={isOpen}
toggleSummaryHisto={toggleSummaryHisto}
genesetsEditable
geneset={setName}
/>
</div>
</div>
@@ -1,12 +1,14 @@
import React from "react";
import { connect } from "react-redux";
import { Tooltip2 } from "@blueprintjs/popover2";
import {
Button,
AnchorButton,
Menu,
MenuItem,
Popover,
Position,
Tooltip,
Icon,
PopoverInteractionKind,
} from "@blueprintjs/core";
@@ -18,6 +20,7 @@ import AddGeneToGenesetDialogue from "./addGeneToGenesetDialogue";
@connect((state) => {
return {
genesetsUI: state.genesetsUI,
colorAccessor: state.colors.colorAccessor,
};
})
class GenesetMenus extends React.PureComponent {
@@ -43,19 +46,41 @@ class GenesetMenus extends React.PureComponent {
});
};
handleColorByEntireGeneset = () => {
const { dispatch, geneset } = this.props;
dispatch({
type: "color by geneset mean expression",
geneset,
});
};
handleDeleteCategory = () => {
const { dispatch, geneset } = this.props;
dispatch(actions.genesetDelete(geneset));
};
render() {
const { geneset, genesetsEditable, createText } = this.props;
const {
geneset,
genesetsEditable,
createText,
colorAccessor,
isOpen,
toggleSummaryHisto,
} = this.props;
const isColorBy = geneset === colorAccessor;
const genesetClosed = !isOpen;
const showingAllGenes = !toggleSummaryHisto;
const notShowingSummary = genesetClosed || showingAllGenes;
return (
<>
{genesetsEditable ? (
{genesetsEditable && (
<>
<Tooltip
<Tooltip2
content={createText}
position={Position.BOTTOM}
hoverOpenDelay={globals.tooltipHoverOpenDelay}
@@ -69,7 +94,7 @@ class GenesetMenus extends React.PureComponent {
small
minimal
/>
</Tooltip>
</Tooltip2>
<AddGeneToGenesetDialogue geneset={geneset} />
<Popover
interactionKind={PopoverInteractionKind.HOVER}
@@ -104,15 +129,24 @@ class GenesetMenus extends React.PureComponent {
minimal
/>
</Popover>
<Button
disabled
style={{ marginLeft: 0 }}
data-testclass="colorby-entire-geneset"
data-testid={`${geneset}:colorby-entire-geneset`}
icon={<Icon icon="tint" iconSize={16} />}
/>
<Tooltip2
content={`Color by gene set ${geneset} mean (gene set must be open, and toggled to mean expression histogram)`}
position={Position.BOTTOM}
hoverOpenDelay={globals.tooltipHoverOpenDelay}
>
<AnchorButton
disabled={notShowingSummary && !isColorBy}
active={isColorBy}
intent={isColorBy ? "primary" : "none"}
style={{ marginLeft: 0 }}
onClick={this.handleColorByEntireGeneset}
data-testclass="colorby-entire-geneset"
data-testid={`${geneset}:colorby-entire-geneset`}
icon={<Icon icon="tint" iconSize={16} />}
/>
</Tooltip2>
</>
) : null}
)}
</>
);
}
+12 -2
View File
@@ -76,6 +76,8 @@ function createModelTF() {
graphInteractionMode: state.controls.graphInteractionMode,
colors: state.colors,
pointDilation: state.pointDilation,
genesets: state.genesets.genesets,
differential: state.differential,
}))
class Graph extends React.Component {
static createReglState(canvas) {
@@ -526,6 +528,7 @@ class Graph extends React.Component {
colorsProp,
pointDilation
);
const { currentDimNames } = layoutChoice;
const X = layoutDf.col(currentDimNames[0]).asArray();
const Y = layoutDf.col(currentDimNames[1]).asArray();
@@ -782,10 +785,17 @@ class Graph extends React.Component {
}
createColorByQuery(colors) {
const { annoMatrix } = this.props;
const { annoMatrix, genesets, differential } = this.props;
const { schema } = annoMatrix;
const { colorMode, colorAccessor } = colors;
return createColorQuery(colorMode, colorAccessor, schema);
return createColorQuery(
colorMode,
colorAccessor,
schema,
genesets,
differential.diffExp
);
}
renderPoints(
@@ -14,6 +14,8 @@ export default
dilatedValue: state.pointDilation.categoryField,
categoricalSelection: state.categoricalSelection,
showLabels: state.centroidLabels?.showLabels,
genesets: state.genesets.genesets,
differential: state.differential,
}))
class CentroidLabels extends PureComponent {
static watchAsync(props, prevProps) {
@@ -74,10 +76,16 @@ class CentroidLabels extends PureComponent {
};
colorByQuery() {
const { annoMatrix, colors } = this.props;
const { annoMatrix, colors, genesets, differential } = this.props;
const { schema } = annoMatrix;
const { colorMode, colorAccessor } = colors;
return createColorQuery(colorMode, colorAccessor, schema);
return createColorQuery(
colorMode,
colorAccessor,
schema,
genesets,
differential.diffExp
);
}
async fetchData() {
@@ -53,6 +53,7 @@ const getYScale = memoize(getScale);
differential: state.differential,
crossfilter,
genesets: state.genesets.genesets,
};
})
class Scatterplot extends React.PureComponent {
@@ -313,10 +314,16 @@ class Scatterplot extends React.PureComponent {
}
createColorByQuery(colors) {
const { annoMatrix } = this.props;
const { annoMatrix, genesets, differential } = this.props;
const { schema } = annoMatrix;
const { colorMode, colorAccessor } = colors;
return createColorQuery(colorMode, colorAccessor, schema);
return createColorQuery(
colorMode,
colorAccessor,
schema,
genesets,
differential
);
}
updateColorTable(colors, colorDf) {
+17 -2
View File
@@ -4,8 +4,8 @@ Color By UI state
const ColorsReducer = (
state = {
colorMode: null,
colorAccessor: null,
colorMode: null /* by continuous, by expression */,
colorAccessor: null /* tissue, Apod */,
},
action,
nextSharedState,
@@ -96,6 +96,21 @@ const ColorsReducer = (
};
}
case "color by geneset mean expression": {
/* toggle between this mode and reset */
const resetCurrent =
action.type === state.colorMode &&
action.geneset === state.colorAccessor;
const colorMode = !resetCurrent ? action.type : null;
const colorAccessor = !resetCurrent ? action.geneset : null;
return {
...state,
colorMode,
colorAccessor,
};
}
default: {
return state;
}
+1
View File
@@ -80,6 +80,7 @@ const saveOnActions = new Set([
"color by categorical metadata",
"color by continuous metadata",
"color by expression",
"color by geneset mean expression",
"show centroid labels for category",
+46 -2
View File
@@ -12,8 +12,15 @@ import { range } from "../range";
given a color mode & accessor, generate an annoMatrix query that will
fulfill it
*/
export function createColorQuery(colorMode, colorByAccessor, schema) {
if (!colorMode || !colorByAccessor || !schema) return null;
export function createColorQuery(
colorMode,
colorByAccessor,
schema,
genesets,
diffExp
) {
if (!colorMode || !colorByAccessor || !schema || !genesets) return null;
switch (colorMode) {
case "color by categorical metadata":
case "color by continuous metadata": {
@@ -33,6 +40,38 @@ export function createColorQuery(colorMode, colorByAccessor, schema) {
},
];
}
case "color by geneset mean expression": {
const varIndex = schema?.annotations?.var?.index;
if (!varIndex) return null;
if (!genesets) return null;
let _geneset;
let _setGenes;
if (colorByAccessor === "Temp DiffExp Set") {
_geneset = diffExp;
_setGenes = _geneset.map((diffexpResultItem) => {
const geneName = diffexpResultItem[0];
return geneName;
});
} else {
_geneset = genesets.get(colorByAccessor);
_setGenes = [..._geneset.genes.keys()];
}
return [
"X",
{
summarize: {
method: "mean",
field: "var",
column: varIndex,
values: _setGenes,
},
},
];
}
default: {
return null;
}
@@ -86,6 +125,11 @@ function _createColorTable(
const { min, max } = col.summarize();
return createColorsByContinuousMetadata(col.asArray(), min, max);
}
case "color by geneset mean expression": {
const col = colorByData.icol(0);
const { min, max } = col.summarize();
return createColorsByContinuousMetadata(col.asArray(), min, max);
}
default: {
return defaultColors(schema.dataframe.nObs);
}