mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-10-06 13:58:12 +08:00
feat(geneset): save diff exp result as geneset (#2216)
* update package lock * allow falsey vals * remove old diff exp handling * save diff exp results as geneset * delete test * check for undefined or null * use global geneset description for diffexp * remove diffexp special code, no longer showing adjpval + logfoldchange * remove differential map to state * remove clear from FSM, since we no longer support those actions * restore controlHelpers test with todo
This commit is contained in:
@@ -1,38 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
test controls helpers
|
test controls helpers
|
||||||
*/
|
*/
|
||||||
import { subsetAndResetGeneLists } from "../../../src/util/stateManager/controlsHelpers";
|
|
||||||
import * as globals from "../../../src/globals";
|
|
||||||
|
|
||||||
describe("controls helpers", () => {
|
describe("controls helpers", () => {
|
||||||
test("subsetAndResetGeneLists", () => {
|
// TODO #2227 test: improve test coverage on control helper functions
|
||||||
const geneList = [];
|
// (`topNCategories()`, `isSelectableCategoryName()`, `selectableCategoryNames()`, `createCategorySummaryFromDfCol()`, `createCategoricalSelection()`, )
|
||||||
const genRandGene = () => Math.random().toString(36).substring(2, 6);
|
|
||||||
|
|
||||||
// build a unique set of genes
|
|
||||||
for (let i = 0; i < 150; i += 1) {
|
|
||||||
let randGene = genRandGene();
|
|
||||||
while (geneList.includes(randGene)) randGene = genRandGene();
|
|
||||||
geneList.push(randGene);
|
|
||||||
}
|
|
||||||
// insert duplicates
|
|
||||||
geneList[0] = "dupl";
|
|
||||||
geneList[20] = "dupl";
|
|
||||||
const state = {
|
|
||||||
userDefinedGenes: geneList.slice(0, 20),
|
|
||||||
diffexpGenes: geneList.slice(20),
|
|
||||||
};
|
|
||||||
const [newUserDefinedGenes, newDiffExpGenes] = subsetAndResetGeneLists(
|
|
||||||
state
|
|
||||||
);
|
|
||||||
const expectedNewUserDefinedGenes = [
|
|
||||||
...geneList.slice(0, 20),
|
|
||||||
...geneList.slice(21),
|
|
||||||
].slice(0, globals.maxGenes);
|
|
||||||
expect(globals.maxUserDefinedGenes).toBeLessThan(globals.maxGenes);
|
|
||||||
expect(geneList.length).toBeGreaterThan(globals.maxGenes);
|
|
||||||
expect(newUserDefinedGenes).toHaveLength(globals.maxGenes);
|
|
||||||
expect(newUserDefinedGenes).toStrictEqual(expectedNewUserDefinedGenes);
|
|
||||||
expect(newDiffExpGenes).toStrictEqual([]);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
Generated
+21812
-10
File diff suppressed because it is too large
Load Diff
@@ -8,22 +8,17 @@ const HistogramFooter = React.memo(
|
|||||||
rangeMax,
|
rangeMax,
|
||||||
rangeColorMin,
|
rangeColorMin,
|
||||||
rangeColorMax,
|
rangeColorMax,
|
||||||
logFoldChange,
|
|
||||||
pvalAdj,
|
|
||||||
isObs,
|
isObs,
|
||||||
isGeneSetSummary,
|
isGeneSetSummary,
|
||||||
}) => {
|
}) => {
|
||||||
/*
|
/*
|
||||||
Footer of each histogram. Will render range, title, and optionally
|
Footer of each histogram. Will render range and title.
|
||||||
differential expression info.
|
|
||||||
|
|
||||||
Required props:
|
Required props:
|
||||||
* displayName - the displayName, aka "n_genes", "FOXP2", etc.
|
* displayName - the displayName, aka "n_genes", "FOXP2", etc.
|
||||||
* hideRanges - true/false, enables/disable rendering of ranges
|
* hideRanges - true/false, enables/disable rendering of ranges
|
||||||
* range - length two array, [min, max], containing the range values to display
|
* range - length two array, [min, max], containing the range values to display
|
||||||
* rangeColor - length two array, [mincolor, maxcolor], each a CSS color
|
* rangeColor - length two array, [mincolor, maxcolor], each a CSS color
|
||||||
* logFoldChange - lfc to display, optional.
|
|
||||||
* pValue - pValue to display, optional.
|
|
||||||
*/
|
*/
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@@ -60,30 +55,6 @@ const HistogramFooter = React.memo(
|
|||||||
max {rangeMax.toPrecision(4)}
|
max {rangeMax.toPrecision(4)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{logFoldChange && pvalAdj ? (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "baseline",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span>
|
|
||||||
<strong>log fold change:</strong>
|
|
||||||
{` ${logFoldChange.toPrecision(4)}`}
|
|
||||||
</span>
|
|
||||||
<span
|
|
||||||
style={{
|
|
||||||
marginLeft: 7,
|
|
||||||
padding: 2,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<strong>p-value (adj):</strong>
|
|
||||||
{pvalAdj < 0.0001 ? " < 0.0001" : ` ${pvalAdj.toFixed(4)}`}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ import StillLoading from "./loading";
|
|||||||
import ErrorLoading from "./error";
|
import ErrorLoading from "./error";
|
||||||
|
|
||||||
@connect((state, ownProps) => {
|
@connect((state, ownProps) => {
|
||||||
const { isObs, isUserDefined, isDiffExp, isGeneSetSummary, field } = ownProps;
|
const { isObs, isUserDefined, isGeneSetSummary, field } = ownProps;
|
||||||
const myName = makeContinuousDimensionName(
|
const myName = makeContinuousDimensionName(
|
||||||
{ isObs, isUserDefined, isDiffExp, isGeneSetSummary },
|
{ isObs, isUserDefined, isGeneSetSummary },
|
||||||
field
|
field
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
@@ -80,7 +80,6 @@ class HistogramBrush extends React.PureComponent {
|
|||||||
field,
|
field,
|
||||||
isObs,
|
isObs,
|
||||||
isUserDefined,
|
isUserDefined,
|
||||||
isDiffExp,
|
|
||||||
isGeneSetSummary,
|
isGeneSetSummary,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
@@ -98,7 +97,6 @@ class HistogramBrush extends React.PureComponent {
|
|||||||
continuousNamespace: {
|
continuousNamespace: {
|
||||||
isObs,
|
isObs,
|
||||||
isUserDefined,
|
isUserDefined,
|
||||||
isDiffExp,
|
|
||||||
isGeneSetSummary,
|
isGeneSetSummary,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -115,7 +113,6 @@ class HistogramBrush extends React.PureComponent {
|
|||||||
field,
|
field,
|
||||||
isObs,
|
isObs,
|
||||||
isUserDefined,
|
isUserDefined,
|
||||||
isDiffExp,
|
|
||||||
isGeneSetSummary,
|
isGeneSetSummary,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const minAllowedBrushSize = 10;
|
const minAllowedBrushSize = 10;
|
||||||
@@ -156,7 +153,6 @@ class HistogramBrush extends React.PureComponent {
|
|||||||
continuousNamespace: {
|
continuousNamespace: {
|
||||||
isObs,
|
isObs,
|
||||||
isUserDefined,
|
isUserDefined,
|
||||||
isDiffExp,
|
|
||||||
isGeneSetSummary,
|
isGeneSetSummary,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -362,10 +358,7 @@ class HistogramBrush extends React.PureComponent {
|
|||||||
field,
|
field,
|
||||||
isColorAccessor,
|
isColorAccessor,
|
||||||
isUserDefined,
|
isUserDefined,
|
||||||
isDiffExp,
|
|
||||||
logFoldChange,
|
|
||||||
isGeneSetSummary,
|
isGeneSetSummary,
|
||||||
pvalAdj,
|
|
||||||
isScatterplotXXaccessor,
|
isScatterplotXXaccessor,
|
||||||
isScatterplotYYaccessor,
|
isScatterplotYYaccessor,
|
||||||
zebra,
|
zebra,
|
||||||
@@ -383,7 +376,7 @@ class HistogramBrush extends React.PureComponent {
|
|||||||
heightMini,
|
heightMini,
|
||||||
} = this.state;
|
} = this.state;
|
||||||
const fieldForId = field.replace(/\s/g, "_");
|
const fieldForId = field.replace(/\s/g, "_");
|
||||||
const showScatterPlot = isDiffExp || isUserDefined;
|
const showScatterPlot = isUserDefined;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Async
|
<Async
|
||||||
@@ -406,9 +399,7 @@ class HistogramBrush extends React.PureComponent {
|
|||||||
id={`histogram_${fieldForId}`}
|
id={`histogram_${fieldForId}`}
|
||||||
data-testid={`histogram-${field}`}
|
data-testid={`histogram-${field}`}
|
||||||
data-testclass={
|
data-testclass={
|
||||||
isDiffExp
|
isUserDefined
|
||||||
? "histogram-diffexp"
|
|
||||||
: isUserDefined
|
|
||||||
? "histogram-user-gene"
|
? "histogram-user-gene"
|
||||||
: "histogram-continuous-metadata"
|
: "histogram-continuous-metadata"
|
||||||
}
|
}
|
||||||
@@ -454,15 +445,12 @@ class HistogramBrush extends React.PureComponent {
|
|||||||
<HistogramFooter
|
<HistogramFooter
|
||||||
isGeneSetSummary={isGeneSetSummary}
|
isGeneSetSummary={isGeneSetSummary}
|
||||||
isObs={isObs}
|
isObs={isObs}
|
||||||
isDiffExp={isDiffExp}
|
|
||||||
displayName={field}
|
displayName={field}
|
||||||
hideRanges={asyncProps.isSingleValue}
|
hideRanges={asyncProps.isSingleValue}
|
||||||
rangeMin={asyncProps.unclippedRange[0]}
|
rangeMin={asyncProps.unclippedRange[0]}
|
||||||
rangeMax={asyncProps.unclippedRange[1]}
|
rangeMax={asyncProps.unclippedRange[1]}
|
||||||
rangeColorMin={asyncProps.unclippedRangeColor[0]}
|
rangeColorMin={asyncProps.unclippedRangeColor[0]}
|
||||||
rangeColorMax={asyncProps.unclippedRangeColor[1]}
|
rangeColorMax={asyncProps.unclippedRangeColor[1]}
|
||||||
logFoldChange={logFoldChange}
|
|
||||||
pvalAdj={pvalAdj}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -45,7 +45,6 @@ const LABEL_WIDTH_ANNO = LABEL_WIDTH - ANNO_BUTTON_WIDTH;
|
|||||||
crossfilter: state.obsCrossfilter,
|
crossfilter: state.obsCrossfilter,
|
||||||
isUserAnno,
|
isUserAnno,
|
||||||
genesets: state.genesets.genesets,
|
genesets: state.genesets.genesets,
|
||||||
differential: state.differential,
|
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
class Category extends React.PureComponent {
|
class Category extends React.PureComponent {
|
||||||
@@ -144,15 +143,14 @@ class Category extends React.PureComponent {
|
|||||||
*/
|
*/
|
||||||
const { schema } = annoMatrix;
|
const { schema } = annoMatrix;
|
||||||
const { colorAccessor, colorMode } = colors;
|
const { colorAccessor, colorMode } = colors;
|
||||||
const { genesets, differential } = this.props;
|
const { genesets } = this.props;
|
||||||
let colorDataPromise = Promise.resolve(null);
|
let colorDataPromise = Promise.resolve(null);
|
||||||
if (colorAccessor) {
|
if (colorAccessor) {
|
||||||
const query = createColorQuery(
|
const query = createColorQuery(
|
||||||
colorMode,
|
colorMode,
|
||||||
colorAccessor,
|
colorAccessor,
|
||||||
schema,
|
schema,
|
||||||
genesets,
|
genesets
|
||||||
differential.diffExp
|
|
||||||
);
|
);
|
||||||
if (query) colorDataPromise = annoMatrix.fetch(...query);
|
if (query) colorDataPromise = annoMatrix.fetch(...query);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -107,11 +107,10 @@ const continuous = (selectorId, colorScale, colorAccessor) => {
|
|||||||
annoMatrix: state.annoMatrix,
|
annoMatrix: state.annoMatrix,
|
||||||
colors: state.colors,
|
colors: state.colors,
|
||||||
genesets: state.genesets.genesets,
|
genesets: state.genesets.genesets,
|
||||||
differential: state.differential,
|
|
||||||
}))
|
}))
|
||||||
class ContinuousLegend extends React.Component {
|
class ContinuousLegend extends React.Component {
|
||||||
async componentDidUpdate(prevProps) {
|
async componentDidUpdate(prevProps) {
|
||||||
const { annoMatrix, colors, genesets, differential } = this.props;
|
const { annoMatrix, colors, genesets } = this.props;
|
||||||
if (!colors || !annoMatrix) return;
|
if (!colors || !annoMatrix) return;
|
||||||
|
|
||||||
if (colors !== prevProps?.colors || annoMatrix !== prevProps?.annoMatrix) {
|
if (colors !== prevProps?.colors || annoMatrix !== prevProps?.annoMatrix) {
|
||||||
@@ -122,8 +121,7 @@ class ContinuousLegend extends React.Component {
|
|||||||
colorMode,
|
colorMode,
|
||||||
colorAccessor,
|
colorAccessor,
|
||||||
schema,
|
schema,
|
||||||
genesets,
|
genesets
|
||||||
differential.diffExp
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const colorDf = colorQuery ? await annoMatrix.fetch(...colorQuery) : null;
|
const colorDf = colorQuery ? await annoMatrix.fetch(...colorQuery) : null;
|
||||||
|
|||||||
@@ -63,9 +63,6 @@ class Gene extends React.Component {
|
|||||||
isColorAccessor,
|
isColorAccessor,
|
||||||
isScatterplotXXaccessor,
|
isScatterplotXXaccessor,
|
||||||
isScatterplotYYaccessor,
|
isScatterplotYYaccessor,
|
||||||
isDiffExp,
|
|
||||||
pvalAdj,
|
|
||||||
logFoldChange,
|
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const { geneIsExpanded } = this.state;
|
const { geneIsExpanded } = this.state;
|
||||||
const genesetNameLengthVisible = 310; /* this magic number determines how much of a long geneset name we see */
|
const genesetNameLengthVisible = 310; /* this magic number determines how much of a long geneset name we see */
|
||||||
@@ -120,25 +117,20 @@ class Gene extends React.Component {
|
|||||||
</Truncate>
|
</Truncate>
|
||||||
</div>
|
</div>
|
||||||
{!geneIsExpanded ? (
|
{!geneIsExpanded ? (
|
||||||
isDiffExp ? (
|
<HistogramBrush isUserDefined field={gene} mini />
|
||||||
<HistogramBrush isDiffExp field={gene} mini />
|
|
||||||
) : (
|
|
||||||
<HistogramBrush isUserDefined field={gene} mini />
|
|
||||||
)
|
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<div style={{ flexShrink: 0, marginLeft: 2 }}>
|
<div style={{ flexShrink: 0, marginLeft: 2 }}>
|
||||||
{!isDiffExp ? (
|
<AnchorButton
|
||||||
<AnchorButton
|
minimal
|
||||||
minimal
|
small
|
||||||
small
|
data-testid={`delete-from-geneset-${gene}`}
|
||||||
data-testid={`delete-from-geneset-${gene}`}
|
onClick={this.handleDeleteGeneFromSet}
|
||||||
onClick={this.handleDeleteGeneFromSet}
|
intent="none"
|
||||||
intent="none"
|
style={{ fontWeight: 700, marginRight: 2 }}
|
||||||
style={{ fontWeight: 700, marginRight: 2 }}
|
icon={<Icon icon="trash" iconSize={10} />}
|
||||||
icon={<Icon icon="trash" iconSize={10} />}
|
/>
|
||||||
/>
|
)
|
||||||
) : null}
|
|
||||||
<AnchorButton
|
<AnchorButton
|
||||||
minimal
|
minimal
|
||||||
small
|
small
|
||||||
@@ -184,17 +176,7 @@ class Gene extends React.Component {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{geneIsExpanded &&
|
{geneIsExpanded && <HistogramBrush isUserDefined field={gene} />}
|
||||||
(isDiffExp ? (
|
|
||||||
<HistogramBrush
|
|
||||||
isDiffExp
|
|
||||||
field={gene}
|
|
||||||
pvalAdj={pvalAdj}
|
|
||||||
logFoldChange={logFoldChange}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<HistogramBrush isUserDefined field={gene} />
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,33 +79,8 @@ class GeneSet extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
renderGenes() {
|
renderGenes() {
|
||||||
const {
|
const { setName, setGenes, setGenesWithDescriptions } = this.props;
|
||||||
setName,
|
|
||||||
setGenes,
|
|
||||||
setGenesWithDescriptions,
|
|
||||||
isDiffExp,
|
|
||||||
diffExp,
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
if (isDiffExp) {
|
|
||||||
// [ [gene, logfoldchange, pval, pval_adj], ...]
|
|
||||||
return setGenes.map((gene, idx) => {
|
|
||||||
const logFoldChange = diffExp[idx][1];
|
|
||||||
const pvalAdj = diffExp[idx][3];
|
|
||||||
return (
|
|
||||||
<Gene
|
|
||||||
key={gene}
|
|
||||||
gene={gene}
|
|
||||||
geneset={setName}
|
|
||||||
isDiffExp
|
|
||||||
logFoldChange={logFoldChange}
|
|
||||||
pvalAdj={pvalAdj}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// otherwise...
|
|
||||||
return setGenes.map((gene) => {
|
return setGenes.map((gene) => {
|
||||||
const { geneDescription } = setGenesWithDescriptions.get(gene);
|
const { geneDescription } = setGenesWithDescriptions.get(gene);
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import CreateGenesetDialogue from "./menus/createGenesetDialogue";
|
|||||||
|
|
||||||
@connect((state) => {
|
@connect((state) => {
|
||||||
return {
|
return {
|
||||||
differential: state.differential,
|
|
||||||
genesets: state.genesets.genesets,
|
genesets: state.genesets.genesets,
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
@@ -30,24 +29,6 @@ class GeneExpression extends React.Component {
|
|||||||
return sets;
|
return sets;
|
||||||
};
|
};
|
||||||
|
|
||||||
renderDiffexpGeneSets = () => {
|
|
||||||
const { differential } = this.props;
|
|
||||||
const { diffExp } = differential;
|
|
||||||
if (!diffExp) return null;
|
|
||||||
|
|
||||||
// [ [gene, logfoldchange, pval, pval_adj], ...]
|
|
||||||
const setGenes = diffExp.map((diffExpGene) => diffExpGene[0]);
|
|
||||||
return (
|
|
||||||
<GeneSet
|
|
||||||
key="Temp DiffExp Set"
|
|
||||||
setGenes={setGenes}
|
|
||||||
isDiffExp
|
|
||||||
diffExp={diffExp}
|
|
||||||
setName="Temp DiffExp Set"
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
handleActivateCreateGenesetMode = () => {
|
handleActivateCreateGenesetMode = () => {
|
||||||
const { dispatch } = this.props;
|
const { dispatch } = this.props;
|
||||||
dispatch({ type: "geneset: activate add new geneset mode" });
|
dispatch({ type: "geneset: activate add new geneset mode" });
|
||||||
@@ -68,7 +49,6 @@ class GeneExpression extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
<CreateGenesetDialogue />
|
<CreateGenesetDialogue />
|
||||||
</div>
|
</div>
|
||||||
<div>{this.renderDiffexpGeneSets()}</div>
|
|
||||||
<div>{this.renderGeneSets()}</div>
|
<div>{this.renderGeneSets()}</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -54,7 +54,6 @@ const filterGenes = (query, genes) =>
|
|||||||
annoMatrix: state.annoMatrix,
|
annoMatrix: state.annoMatrix,
|
||||||
userDefinedGenes: state.controls.userDefinedGenes,
|
userDefinedGenes: state.controls.userDefinedGenes,
|
||||||
userDefinedGenesLoading: state.controls.userDefinedGenesLoading,
|
userDefinedGenesLoading: state.controls.userDefinedGenesLoading,
|
||||||
differential: state.differential,
|
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
class AddGenes extends React.Component {
|
class AddGenes extends React.Component {
|
||||||
|
|||||||
@@ -77,7 +77,6 @@ function createModelTF() {
|
|||||||
colors: state.colors,
|
colors: state.colors,
|
||||||
pointDilation: state.pointDilation,
|
pointDilation: state.pointDilation,
|
||||||
genesets: state.genesets.genesets,
|
genesets: state.genesets.genesets,
|
||||||
differential: state.differential,
|
|
||||||
}))
|
}))
|
||||||
class Graph extends React.Component {
|
class Graph extends React.Component {
|
||||||
static createReglState(canvas) {
|
static createReglState(canvas) {
|
||||||
@@ -785,17 +784,11 @@ class Graph extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createColorByQuery(colors) {
|
createColorByQuery(colors) {
|
||||||
const { annoMatrix, genesets, differential } = this.props;
|
const { annoMatrix, genesets } = this.props;
|
||||||
const { schema } = annoMatrix;
|
const { schema } = annoMatrix;
|
||||||
const { colorMode, colorAccessor } = colors;
|
const { colorMode, colorAccessor } = colors;
|
||||||
|
|
||||||
return createColorQuery(
|
return createColorQuery(colorMode, colorAccessor, schema, genesets);
|
||||||
colorMode,
|
|
||||||
colorAccessor,
|
|
||||||
schema,
|
|
||||||
genesets,
|
|
||||||
differential.diffExp
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
renderPoints(
|
renderPoints(
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ export default
|
|||||||
categoricalSelection: state.categoricalSelection,
|
categoricalSelection: state.categoricalSelection,
|
||||||
showLabels: state.centroidLabels?.showLabels,
|
showLabels: state.centroidLabels?.showLabels,
|
||||||
genesets: state.genesets.genesets,
|
genesets: state.genesets.genesets,
|
||||||
differential: state.differential,
|
|
||||||
}))
|
}))
|
||||||
class CentroidLabels extends PureComponent {
|
class CentroidLabels extends PureComponent {
|
||||||
static watchAsync(props, prevProps) {
|
static watchAsync(props, prevProps) {
|
||||||
@@ -76,16 +75,10 @@ class CentroidLabels extends PureComponent {
|
|||||||
};
|
};
|
||||||
|
|
||||||
colorByQuery() {
|
colorByQuery() {
|
||||||
const { annoMatrix, colors, genesets, differential } = this.props;
|
const { annoMatrix, colors, genesets } = this.props;
|
||||||
const { schema } = annoMatrix;
|
const { schema } = annoMatrix;
|
||||||
const { colorMode, colorAccessor } = colors;
|
const { colorMode, colorAccessor } = colors;
|
||||||
return createColorQuery(
|
return createColorQuery(colorMode, colorAccessor, schema, genesets);
|
||||||
colorMode,
|
|
||||||
colorAccessor,
|
|
||||||
schema,
|
|
||||||
genesets,
|
|
||||||
differential.diffExp
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchData() {
|
async fetchData() {
|
||||||
|
|||||||
@@ -9,12 +9,9 @@ import actions from "../../actions";
|
|||||||
}))
|
}))
|
||||||
class CellSetButton extends React.PureComponent {
|
class CellSetButton extends React.PureComponent {
|
||||||
set() {
|
set() {
|
||||||
const { differential, dispatch, eitherCellSetOneOrTwo } = this.props;
|
const { dispatch, eitherCellSetOneOrTwo } = this.props;
|
||||||
|
|
||||||
if (!differential.diffExp) {
|
dispatch(actions.setCellSetFromSelection(eitherCellSetOneOrTwo));
|
||||||
// disallow this action if the user has active differential expression results
|
|
||||||
dispatch(actions.setCellSetFromSelection(eitherCellSetOneOrTwo));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@@ -31,7 +28,6 @@ class CellSetButton extends React.PureComponent {
|
|||||||
>
|
>
|
||||||
<AnchorButton
|
<AnchorButton
|
||||||
type="button"
|
type="button"
|
||||||
disabled={differential.diffExp}
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
this.set();
|
this.set();
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { Button, ButtonGroup, AnchorButton, Tooltip } from "@blueprintjs/core";
|
import { ButtonGroup, AnchorButton, Tooltip } from "@blueprintjs/core";
|
||||||
import * as globals from "../../globals";
|
import * as globals from "../../globals";
|
||||||
import styles from "./menubar.css";
|
import styles from "./menubar.css";
|
||||||
import actions from "../../actions";
|
import actions from "../../actions";
|
||||||
@@ -8,8 +8,6 @@ import CellSetButton from "./cellSetButtons";
|
|||||||
|
|
||||||
@connect((state) => ({
|
@connect((state) => ({
|
||||||
differential: state.differential,
|
differential: state.differential,
|
||||||
celllist1: state.differential?.celllist1,
|
|
||||||
celllist2: state.differential?.celllist2,
|
|
||||||
diffexpMayBeSlow: state.config?.parameters?.["diffexp-may-be-slow"] ?? false,
|
diffexpMayBeSlow: state.config?.parameters?.["diffexp-may-be-slow"] ?? false,
|
||||||
diffexpCellcountMax: state.config?.limits?.diffexp_cellcount_max,
|
diffexpCellcountMax: state.config?.limits?.diffexp_cellcount_max,
|
||||||
}))
|
}))
|
||||||
@@ -26,17 +24,6 @@ class DiffexpButtons extends React.PureComponent {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
clearDifferentialExpression = () => {
|
|
||||||
const { dispatch, differential } = this.props;
|
|
||||||
dispatch({
|
|
||||||
type: "clear differential expression",
|
|
||||||
diffExp: differential.diffExp,
|
|
||||||
});
|
|
||||||
dispatch({
|
|
||||||
type: "clear scatterplot",
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
/* diffexp-related buttons may be disabled */
|
/* diffexp-related buttons may be disabled */
|
||||||
const { differential, diffexpMayBeSlow, diffexpCellcountMax } = this.props;
|
const { differential, diffexpMayBeSlow, diffexpCellcountMax } = this.props;
|
||||||
@@ -65,41 +52,22 @@ class DiffexpButtons extends React.PureComponent {
|
|||||||
<ButtonGroup className={styles.menubarButton}>
|
<ButtonGroup className={styles.menubarButton}>
|
||||||
<CellSetButton eitherCellSetOneOrTwo={1} />
|
<CellSetButton eitherCellSetOneOrTwo={1} />
|
||||||
<CellSetButton eitherCellSetOneOrTwo={2} />
|
<CellSetButton eitherCellSetOneOrTwo={2} />
|
||||||
{!differential.diffExp ? (
|
<Tooltip
|
||||||
<Tooltip
|
content={warnMaxSizeExceeded ? tipMessageWarn : tipMessage}
|
||||||
content={warnMaxSizeExceeded ? tipMessageWarn : tipMessage}
|
position="bottom"
|
||||||
position="bottom"
|
hoverOpenDelay={globals.tooltipHoverOpenDelayQuick}
|
||||||
hoverOpenDelay={globals.tooltipHoverOpenDelayQuick}
|
intent={warnMaxSizeExceeded ? "danger" : "none"}
|
||||||
intent={warnMaxSizeExceeded ? "danger" : "none"}
|
>
|
||||||
>
|
<AnchorButton
|
||||||
<AnchorButton
|
disabled={!haveBothCellSets || warnMaxSizeExceeded}
|
||||||
disabled={!haveBothCellSets || warnMaxSizeExceeded}
|
intent={warnMaxSizeExceeded ? "danger" : "primary"}
|
||||||
intent={warnMaxSizeExceeded ? "danger" : "primary"}
|
data-testid="diffexp-button"
|
||||||
data-testid="diffexp-button"
|
loading={differential.loading}
|
||||||
loading={differential.loading}
|
icon="left-join"
|
||||||
icon="left-join"
|
fill
|
||||||
fill
|
onClick={this.computeDiffExp}
|
||||||
onClick={this.computeDiffExp}
|
/>
|
||||||
/>
|
</Tooltip>
|
||||||
</Tooltip>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
{differential.diffExp ? (
|
|
||||||
<Tooltip
|
|
||||||
content="Remove differentially expressed gene list and clear cell selections"
|
|
||||||
position="bottom"
|
|
||||||
hoverOpenDelay={globals.tooltipHoverOpenDelayQuick}
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
type="button"
|
|
||||||
fill
|
|
||||||
intent="warning"
|
|
||||||
onClick={this.clearDifferentialExpression}
|
|
||||||
>
|
|
||||||
Clear Differential Expression
|
|
||||||
</Button>
|
|
||||||
</Tooltip>
|
|
||||||
) : null}
|
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,17 +29,13 @@ import { getEmbSubsetView } from "../../util/stateManager/viewStackHelpers";
|
|||||||
return {
|
return {
|
||||||
subsetPossible,
|
subsetPossible,
|
||||||
subsetResetPossible,
|
subsetResetPossible,
|
||||||
differential: state.differential,
|
|
||||||
graphInteractionMode: state.controls.graphInteractionMode,
|
graphInteractionMode: state.controls.graphInteractionMode,
|
||||||
clipPercentileMin: Math.round(100 * (annoMatrix?.clipRange?.[0] ?? 0)),
|
clipPercentileMin: Math.round(100 * (annoMatrix?.clipRange?.[0] ?? 0)),
|
||||||
clipPercentileMax: Math.round(100 * (annoMatrix?.clipRange?.[1] ?? 1)),
|
clipPercentileMax: Math.round(100 * (annoMatrix?.clipRange?.[1] ?? 1)),
|
||||||
userDefinedGenes: state.controls.userDefinedGenes,
|
userDefinedGenes: state.controls.userDefinedGenes,
|
||||||
diffexpGenes: state.controls.diffexpGenes,
|
|
||||||
colorAccessor: state.colors.colorAccessor,
|
colorAccessor: state.colors.colorAccessor,
|
||||||
scatterplotXXaccessor: state.controls.scatterplotXXaccessor,
|
scatterplotXXaccessor: state.controls.scatterplotXXaccessor,
|
||||||
scatterplotYYaccessor: state.controls.scatterplotYYaccessor,
|
scatterplotYYaccessor: state.controls.scatterplotYYaccessor,
|
||||||
celllist1: state.differential.celllist1,
|
|
||||||
celllist2: state.differential.celllist2,
|
|
||||||
libraryVersions: state.config?.library_versions,
|
libraryVersions: state.config?.library_versions,
|
||||||
auth: state.config?.authentication,
|
auth: state.config?.authentication,
|
||||||
userInfo: state.userInfo,
|
userInfo: state.userInfo,
|
||||||
|
|||||||
@@ -51,7 +51,6 @@ const getYScale = memoize(getScale);
|
|||||||
scatterplotXXaccessor,
|
scatterplotXXaccessor,
|
||||||
scatterplotYYaccessor,
|
scatterplotYYaccessor,
|
||||||
|
|
||||||
differential: state.differential,
|
|
||||||
crossfilter,
|
crossfilter,
|
||||||
genesets: state.genesets.genesets,
|
genesets: state.genesets.genesets,
|
||||||
};
|
};
|
||||||
@@ -314,16 +313,10 @@ class Scatterplot extends React.PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createColorByQuery(colors) {
|
createColorByQuery(colors) {
|
||||||
const { annoMatrix, genesets, differential } = this.props;
|
const { annoMatrix, genesets } = this.props;
|
||||||
const { schema } = annoMatrix;
|
const { schema } = annoMatrix;
|
||||||
const { colorMode, colorAccessor } = colors;
|
const { colorMode, colorAccessor } = colors;
|
||||||
return createColorQuery(
|
return createColorQuery(colorMode, colorAccessor, schema, genesets);
|
||||||
colorMode,
|
|
||||||
colorAccessor,
|
|
||||||
schema,
|
|
||||||
genesets,
|
|
||||||
differential
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateColorTable(colors, colorDf) {
|
updateColorTable(colors, colorDf) {
|
||||||
|
|||||||
@@ -7,9 +7,7 @@ const ColorsReducer = (
|
|||||||
colorMode: null /* by continuous, by expression */,
|
colorMode: null /* by continuous, by expression */,
|
||||||
colorAccessor: null /* tissue, Apod */,
|
colorAccessor: null /* tissue, Apod */,
|
||||||
},
|
},
|
||||||
action,
|
action
|
||||||
nextSharedState,
|
|
||||||
prevSharedState
|
|
||||||
) => {
|
) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case "universe: user color load success": {
|
case "universe: user color load success": {
|
||||||
@@ -20,19 +18,6 @@ const ColorsReducer = (
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
case "clear differential expression":
|
|
||||||
case "set clip quantiles":
|
|
||||||
case "subset to selection": {
|
|
||||||
const { controls: prevControls } = prevSharedState;
|
|
||||||
if (prevControls.diffexpGenes.includes(state.colorAccessor)) {
|
|
||||||
return {
|
|
||||||
colorMode: null,
|
|
||||||
colorAccessor: null,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
case "annotation: category edited": {
|
case "annotation: category edited": {
|
||||||
const { colorAccessor } = state;
|
const { colorAccessor } = state;
|
||||||
if (action.metadataField !== colorAccessor) {
|
if (action.metadataField !== colorAccessor) {
|
||||||
|
|||||||
Vendored
-25
@@ -1,6 +1,5 @@
|
|||||||
import uniq from "lodash.uniq";
|
import uniq from "lodash.uniq";
|
||||||
import filter from "lodash.filter";
|
import filter from "lodash.filter";
|
||||||
import { subsetAndResetGeneLists } from "../util/stateManager/controlsHelpers";
|
|
||||||
|
|
||||||
const Controls = (
|
const Controls = (
|
||||||
state = {
|
state = {
|
||||||
@@ -11,7 +10,6 @@ const Controls = (
|
|||||||
// all of the data + selection state
|
// all of the data + selection state
|
||||||
userDefinedGenes: [],
|
userDefinedGenes: [],
|
||||||
userDefinedGenesLoading: false,
|
userDefinedGenesLoading: false,
|
||||||
diffexpGenes: [],
|
|
||||||
|
|
||||||
resettingInterface: false,
|
resettingInterface: false,
|
||||||
graphInteractionMode: "select",
|
graphInteractionMode: "select",
|
||||||
@@ -45,26 +43,16 @@ const Controls = (
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
case "reset subset": {
|
case "reset subset": {
|
||||||
const [newUserDefinedGenes, newDiffExpGenes] = subsetAndResetGeneLists(
|
|
||||||
state
|
|
||||||
);
|
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
resettingInterface: false,
|
resettingInterface: false,
|
||||||
userDefinedGenes: newUserDefinedGenes,
|
|
||||||
diffexpGenes: newDiffExpGenes,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case "subset to selection": {
|
case "subset to selection": {
|
||||||
const [newUserDefinedGenes, newDiffExpGenes] = subsetAndResetGeneLists(
|
|
||||||
state
|
|
||||||
);
|
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
loading: false,
|
loading: false,
|
||||||
error: null,
|
error: null,
|
||||||
userDefinedGenes: newUserDefinedGenes,
|
|
||||||
diffexpGenes: newDiffExpGenes,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case "request user defined gene started": {
|
case "request user defined gene started": {
|
||||||
@@ -90,19 +78,6 @@ const Controls = (
|
|||||||
userDefinedGenesLoading: false,
|
userDefinedGenesLoading: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case "request differential expression success": {
|
|
||||||
const diffexpGenes = action.data.map((v) => v[0]);
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
diffexpGenes,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
case "clear differential expression": {
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
diffexpGenes: [],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
case "clear user defined gene": {
|
case "clear user defined gene": {
|
||||||
const { userDefinedGenes } = state;
|
const { userDefinedGenes } = state;
|
||||||
const newUserDefinedGenes = filter(
|
const newUserDefinedGenes = filter(
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
const Differential = (
|
const Differential = (
|
||||||
state = {
|
state = {
|
||||||
diffExp: null,
|
|
||||||
loading: null,
|
loading: null,
|
||||||
error: null,
|
error: null,
|
||||||
celllist1: null,
|
celllist1: null,
|
||||||
@@ -20,7 +19,6 @@ const Differential = (
|
|||||||
...state,
|
...state,
|
||||||
error: null,
|
error: null,
|
||||||
loading: false,
|
loading: false,
|
||||||
diffExp: action.data,
|
|
||||||
};
|
};
|
||||||
case "request differential expression error":
|
case "request differential expression error":
|
||||||
return {
|
return {
|
||||||
@@ -38,18 +36,10 @@ const Differential = (
|
|||||||
...state,
|
...state,
|
||||||
celllist2: action.data,
|
celllist2: action.data,
|
||||||
};
|
};
|
||||||
case "clear differential expression":
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
diffExp: null,
|
|
||||||
celllist1: null,
|
|
||||||
celllist2: null,
|
|
||||||
};
|
|
||||||
case "reset subset":
|
case "reset subset":
|
||||||
case "subset to selection":
|
case "subset to selection":
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
diffExp: null,
|
|
||||||
celllist1: null,
|
celllist1: null,
|
||||||
celllist2: null,
|
celllist2: null,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ const GeneSets = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
...state,
|
||||||
initialized: true,
|
initialized: true,
|
||||||
lastTid,
|
lastTid,
|
||||||
genesets,
|
genesets,
|
||||||
@@ -353,6 +354,33 @@ const GeneSets = (
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case "request differential expression success": {
|
||||||
|
const { data } = action;
|
||||||
|
|
||||||
|
const genes = new Map(
|
||||||
|
data.map((diffExpGene) => [
|
||||||
|
diffExpGene[0],
|
||||||
|
{
|
||||||
|
geneSymbol: diffExpGene[0],
|
||||||
|
},
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
const genesetName = `DiffExp Set (${new Date().toLocaleString()})`;
|
||||||
|
|
||||||
|
const genesets = new Map(state.genesets); // clone
|
||||||
|
genesets.set(genesetName, {
|
||||||
|
genesetName,
|
||||||
|
genesetDescription: "",
|
||||||
|
genes,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
genesets,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -185,20 +185,6 @@ const createFsmTransitions = (
|
|||||||
action: applyPending,
|
action: applyPending,
|
||||||
},
|
},
|
||||||
|
|
||||||
/* Clear Differential Expression button user action */
|
|
||||||
{
|
|
||||||
event: "clear differential expression",
|
|
||||||
from: "init",
|
|
||||||
to: "CDE Button in progress",
|
|
||||||
action: stashPending,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
event: "clear scatterplot",
|
|
||||||
from: "CDE Button in progress",
|
|
||||||
to: "done",
|
|
||||||
action: applyPending,
|
|
||||||
},
|
|
||||||
|
|
||||||
/* clear scatter plot button (eg, on scatterplot view) */
|
/* clear scatter plot button (eg, on scatterplot view) */
|
||||||
{
|
{
|
||||||
event: "clear scatterplot",
|
event: "clear scatterplot",
|
||||||
|
|||||||
@@ -12,13 +12,7 @@ import { range } from "../range";
|
|||||||
given a color mode & accessor, generate an annoMatrix query that will
|
given a color mode & accessor, generate an annoMatrix query that will
|
||||||
fulfill it
|
fulfill it
|
||||||
*/
|
*/
|
||||||
export function createColorQuery(
|
export function createColorQuery(colorMode, colorByAccessor, schema, genesets) {
|
||||||
colorMode,
|
|
||||||
colorByAccessor,
|
|
||||||
schema,
|
|
||||||
genesets,
|
|
||||||
diffExp
|
|
||||||
) {
|
|
||||||
if (!colorMode || !colorByAccessor || !schema || !genesets) return null;
|
if (!colorMode || !colorByAccessor || !schema || !genesets) return null;
|
||||||
|
|
||||||
switch (colorMode) {
|
switch (colorMode) {
|
||||||
@@ -46,19 +40,8 @@ export function createColorQuery(
|
|||||||
if (!varIndex) return null;
|
if (!varIndex) return null;
|
||||||
if (!genesets) return null;
|
if (!genesets) return null;
|
||||||
|
|
||||||
let _geneset;
|
const _geneset = genesets.get(colorByAccessor);
|
||||||
let _setGenes;
|
const _setGenes = [..._geneset.genes.keys()];
|
||||||
|
|
||||||
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 [
|
return [
|
||||||
"X",
|
"X",
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
Helper functions for the controls reducer
|
Helper functions for the controls reducer
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import uniq from "lodash.uniq";
|
|
||||||
import difference from "lodash.difference";
|
import difference from "lodash.difference";
|
||||||
|
|
||||||
import * as globals from "../../globals";
|
import * as globals from "../../globals";
|
||||||
@@ -158,12 +157,3 @@ export function pruneVarDataCache(varData, needed) {
|
|||||||
}
|
}
|
||||||
return varData;
|
return varData;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function subsetAndResetGeneLists(state) {
|
|
||||||
const { userDefinedGenes, diffexpGenes } = state;
|
|
||||||
const newUserDefinedGenes = uniq(
|
|
||||||
[].concat(userDefinedGenes, diffexpGenes)
|
|
||||||
).slice(0, globals.maxGenes);
|
|
||||||
const newDiffExpGenes = [];
|
|
||||||
return [newUserDefinedGenes, newDiffExpGenes];
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user