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:
Madison Dunitz
2020-10-14 12:46:24 -05:00
committed by GitHub
parent 798976e4c1
commit 242546371b
5 changed files with 65 additions and 16 deletions
@@ -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 ||
+13 -5
View File
@@ -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>
);
+2 -1
View File
@@ -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;