mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-09-23 20:58:11 +08:00
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:
@@ -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}
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user