mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-09-21 06:48:12 +08:00
Remove Continuous vars with 1 value from histogram, add to info drawer (#1927)
* remove single val continous metadata from histogram, add to info drawer * refactor to save singleContinuous values in state * fix edge case, single continuous values reappeard in rsb when clipped
This commit is contained in:
@@ -450,6 +450,7 @@ const Histogram = ({
|
||||
isScatterplotYYaccessor: state.controls.scatterplotYYaccessor === field,
|
||||
continuousSelectionRange: state.continuousSelection[myName],
|
||||
isColorAccessor: state.colors.colorAccessor === field,
|
||||
singleContinuousValues: state.singleContinuousValue.singleContinuousValues,
|
||||
};
|
||||
})
|
||||
class HistogramBrush extends React.PureComponent {
|
||||
@@ -608,18 +609,44 @@ class HistogramBrush extends React.PureComponent {
|
||||
};
|
||||
|
||||
fetchAsyncProps = async () => {
|
||||
const { annoMatrix } = this.props;
|
||||
const { annoMatrix, field, dispatch, singleContinuousValues } = this.props;
|
||||
const { isClipped } = annoMatrix;
|
||||
|
||||
if (singleContinuousValues.has(field)) {
|
||||
return {
|
||||
histogram: undefined,
|
||||
range: undefined,
|
||||
unclippedRange: undefined,
|
||||
unclippedRangeColor: globals.blue,
|
||||
isSingleValue: true,
|
||||
OK2Render: false,
|
||||
};
|
||||
}
|
||||
const query = this.createQuery();
|
||||
const df = await annoMatrix.fetch(...query);
|
||||
const column = df.icol(0);
|
||||
|
||||
// if we are clipped, fetch both our value and our unclipped value,
|
||||
// as we need the absolute min/max range, not just the clipped min/max.
|
||||
const summary = column.summarize();
|
||||
const range = [summary.min, summary.max];
|
||||
|
||||
if (summary.min === summary.max && !isClipped) {
|
||||
dispatch({
|
||||
type: "add single continuous value",
|
||||
field,
|
||||
value: summary.min,
|
||||
});
|
||||
return {
|
||||
histogram: undefined,
|
||||
range,
|
||||
unclippedRange: range,
|
||||
unclippedRangeColor: globals.blue,
|
||||
isSingleValue: true,
|
||||
OK2Render: false,
|
||||
};
|
||||
}
|
||||
|
||||
const isSingleValue = summary.min === summary.max;
|
||||
// if we are clipped, fetch both our value and our unclipped value,
|
||||
// as we need the absolute min/max range, not just the clipped min/max.
|
||||
let unclippedRange = [...range];
|
||||
if (isClipped) {
|
||||
const parent = await annoMatrix.viewOf.fetch(...query);
|
||||
@@ -643,7 +670,6 @@ class HistogramBrush extends React.PureComponent {
|
||||
this.height
|
||||
);
|
||||
|
||||
const isSingleValue = summary.min === summary.max;
|
||||
const nonFiniteExtent =
|
||||
summary.min === undefined ||
|
||||
summary.max === undefined ||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React, { PureComponent } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { connect, shallowEqual } from "react-redux";
|
||||
import { Drawer } from "@blueprintjs/core";
|
||||
|
||||
import InfoFormat from "./infoFormat";
|
||||
import { selectableCategoryNames } from "../../util/stateManager/controlsHelpers";
|
||||
|
||||
@@ -13,9 +12,14 @@ import { selectableCategoryNames } from "../../util/stateManager/controlsHelpers
|
||||
aboutURL: state.config?.links?.["about-dataset"],
|
||||
isOpen: state.controls.datasetDrawer,
|
||||
dataPortalProps: state.config?.["corpora_props"] ?? {},
|
||||
singleContinuousValues: state.singleContinuousValue.singleContinuousValues,
|
||||
};
|
||||
})
|
||||
class InfoDrawer extends PureComponent {
|
||||
static watchAsync(props, prevProps) {
|
||||
return !shallowEqual(props.watchProps, prevProps.watchProps);
|
||||
}
|
||||
|
||||
handleClose = () => {
|
||||
const { dispatch } = this.props;
|
||||
|
||||
@@ -30,18 +34,22 @@ class InfoDrawer extends PureComponent {
|
||||
schema,
|
||||
isOpen,
|
||||
dataPortalProps,
|
||||
singleContinuousValues,
|
||||
} = this.props;
|
||||
|
||||
const allCategoryNames = selectableCategoryNames(schema).sort();
|
||||
const singleValueCategories = new Map();
|
||||
const allSingleValues = new Map();
|
||||
|
||||
allCategoryNames.forEach((catName) => {
|
||||
const isUserAnno = schema?.annotations?.obsByName[catName]?.writable;
|
||||
const colSchema = schema.annotations.obsByName[catName];
|
||||
if (!isUserAnno && colSchema.categories?.length === 1) {
|
||||
singleValueCategories.set(catName, colSchema.categories[0]);
|
||||
allSingleValues.set(catName, colSchema.categories[0]);
|
||||
}
|
||||
});
|
||||
singleContinuousValues.forEach((value, catName) => {
|
||||
allSingleValues.set(catName, value);
|
||||
});
|
||||
|
||||
return (
|
||||
<Drawer
|
||||
@@ -53,7 +61,7 @@ class InfoDrawer extends PureComponent {
|
||||
{...{
|
||||
datasetTitle,
|
||||
aboutURL,
|
||||
singleValueCategories,
|
||||
allSingleValues,
|
||||
dataPortalProps,
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -85,13 +85,13 @@ const ONTOLOGY_KEY = "ontology_term_id";
|
||||
const CAT_WIDTH = "30%";
|
||||
const VAL_WIDTH = "35%";
|
||||
// Render list of metadata attributes found in categorical field
|
||||
const renderSingleValueCategories = (singleValueCategories) => {
|
||||
if (singleValueCategories.size === 0) return null;
|
||||
const renderSingleValues = (singleValues) => {
|
||||
if (singleValues.size === 0) return null;
|
||||
return (
|
||||
<>
|
||||
<H3>Dataset Metadata</H3>
|
||||
<UL>
|
||||
{Array.from(singleValueCategories).reduce((elems, pair) => {
|
||||
{Array.from(singleValues).reduce((elems, pair) => {
|
||||
const [category, value] = pair;
|
||||
// If the value is empty skip it
|
||||
if (!value) return elems;
|
||||
@@ -168,7 +168,7 @@ const renderLinks = (projectLinks, aboutURL) => {
|
||||
};
|
||||
|
||||
const InfoFormat = React.memo(
|
||||
({ datasetTitle, singleValueCategories, aboutURL, dataPortalProps = {} }) => {
|
||||
({ datasetTitle, allSingleValues, aboutURL, dataPortalProps = {} }) => {
|
||||
if (dataPortalProps.version?.["corpora_schema_version"] !== "1.0.0") {
|
||||
dataPortalProps = {};
|
||||
}
|
||||
@@ -190,7 +190,7 @@ const InfoFormat = React.memo(
|
||||
{renderDOILink("DOI", doi)}
|
||||
{renderDOILink("Preprint DOI", preprintDOI)}
|
||||
{renderOrganism(organism)}
|
||||
{renderSingleValueCategories(singleValueCategories)}
|
||||
{renderSingleValues(allSingleValues)}
|
||||
{renderLinks(projectLinks, aboutURL)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -21,7 +21,7 @@ import centroidLabels from "./centroidLabels";
|
||||
import pointDialation from "./pointDilation";
|
||||
import { reembedController } from "./reembed";
|
||||
import { gcMiddleware as annoMatrixGC } from "../annoMatrix";
|
||||
|
||||
import singleContinuousValue from "./singleContinuousValue";
|
||||
import undoableConfig from "./undoableConfig";
|
||||
|
||||
const Reducer = undoable(
|
||||
@@ -32,6 +32,7 @@ const Reducer = undoable(
|
||||
["ontology", ontology],
|
||||
["annotations", annotations],
|
||||
["layoutChoice", layoutChoice],
|
||||
["singleContinuousValue", singleContinuousValue],
|
||||
["categoricalSelection", categoricalSelection],
|
||||
["continuousSelection", continuousSelection],
|
||||
["graphSelection", graphSelection],
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
const initialState = {
|
||||
singleContinuousValues: new Map(),
|
||||
};
|
||||
const singleContinuousValue = (state = initialState, action) => {
|
||||
switch (action.type) {
|
||||
case "add single continuous value":
|
||||
state.singleContinuousValues.set(action.field, action.value);
|
||||
return state;
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
export default singleContinuousValue;
|
||||
Reference in New Issue
Block a user