diff --git a/src/components/AppBar.tsx b/src/components/AppBar.tsx
index 05780480..c91a9422 100644
--- a/src/components/AppBar.tsx
+++ b/src/components/AppBar.tsx
@@ -137,16 +137,8 @@ const HelpMenu = (): JSX.Element => {
);
};
-const useRobustColorScalesSelector = (c: ColorsState) => ({
- useRobustColorScales: c.useRobustColorScales,
- setUseRobustColorScales: c.setUseRobustColorScales,
-});
-
const ColorMenu = () => {
const colors = useColors();
- const { useRobustColorScales, setUseRobustColorScales } = useColors(
- useRobustColorScalesSelector
- );
const content = (
@@ -167,13 +159,27 @@ const ColorMenu = () => {
onChangeColorPalette={colors.setCategoricalPalette}
/>
-
Robust Coloring
+
+ Continuous Ints
Enable
+
+ Continuous Categories
+
+ Enable
+
+
+ Robust Coloring
+
+ Enable
+
);
diff --git a/src/components/ScalarValue.tsx b/src/components/ScalarValue.tsx
index 416d037e..ff5e7351 100644
--- a/src/components/ScalarValue.tsx
+++ b/src/components/ScalarValue.tsx
@@ -41,7 +41,7 @@ const ScalarValue: FunctionComponent = ({
// eslint-disable-next-line react-hooks/exhaustive-deps
const colorTransferFunctionSelector = useCallback(
(d: Dataset) =>
- d.colorTransferFunctions[column.key]?.[filtered ? 'filtered' : 'full'][0],
+ d.colorTransferFunctions[column.key]?.[filtered ? 'filtered' : 'full'],
[column.key, filtered]
);
diff --git a/src/hooks/useColorTransferFunction.ts b/src/hooks/useColorTransferFunction.ts
index 2c992799..3b3f4d1e 100644
--- a/src/hooks/useColorTransferFunction.ts
+++ b/src/hooks/useColorTransferFunction.ts
@@ -109,36 +109,40 @@ export const createConstantTransferFunction = (
return tf as ConstantTransferFunction;
};
-const createColorTransferFunction = (
+export const createColorTransferFunction = (
data: ColumnData | undefined,
dType: DataType | undefined,
+ robust: boolean = false,
+ continuousInts = false,
+ continuousCategories = false,
classBreaks?: number[]
): TransferFunction => {
- const robustColoring = useColors.getState().useRobustColorScales;
-
if (dType === undefined) return createConstantTransferFunction(unknownDataType);
if (data === undefined) return createConstantTransferFunction(dType);
- if (['int', 'bool', 'Category', 'str'].includes(dType.kind)) {
- const uniqValues = _.uniq(data);
+ if (['bool', 'str'].includes(dType.kind)) {
+ return createCategoricalTransferFunction(_.uniq(data), dType);
+ }
+ if (dType.kind === 'int' && !continuousInts) {
+ const uniqValues = _.uniq(data);
const tooManyInts =
dType.kind === 'int' && uniqValues.length > MAX_VALUES_FOR_INT_CATEGORY;
if (!tooManyInts) {
- const transferFunction = createCategoricalTransferFunction(
- uniqValues,
- dType
- );
- return transferFunction;
+ return createCategoricalTransferFunction(uniqValues, dType);
}
}
- if (['int', 'float'].includes(dType.kind)) {
+ if (dType.kind === 'Category' && !continuousCategories) {
+ return createCategoricalTransferFunction(_.uniq(data), dType);
+ }
+
+ if (['int', 'float', 'Category'].includes(dType.kind)) {
const stats = makeStats(dType, data);
return createContinuousTransferFunction(
- (robustColoring ? stats?.p5 : stats?.min) ?? 0,
- (robustColoring ? stats?.p95 : stats?.max) ?? 1,
+ (robust ? stats?.p5 : stats?.min) ?? 0,
+ (robust ? stats?.p95 : stats?.max) ?? 1,
dType,
classBreaks
);
@@ -148,7 +152,19 @@ const createColorTransferFunction = (
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
-export const useColorTransferFunction = (data: any[], dtype: DataType) =>
- useMemo(() => createColorTransferFunction(data, dtype), [dtype, data]);
+export const useColorTransferFunction = (data: any[], dtype: DataType) => {
+ const colors = useColors();
+ return useMemo(
+ () =>
+ createColorTransferFunction(
+ data,
+ dtype,
+ colors.robust,
+ colors.continuousInts,
+ colors.continuousCategories
+ ),
+ [dtype, data]
+ );
+};
export default useColorTransferFunction;
diff --git a/src/stores/colors.ts b/src/stores/colors.ts
index cf576ad5..d850f649 100644
--- a/src/stores/colors.ts
+++ b/src/stores/colors.ts
@@ -17,11 +17,15 @@ export interface ColorsState {
constantPalette: ConstantPalette;
categoricalPalette: CategoricalPalette;
continuousPalette: ContinuousPalette;
- useRobustColorScales: boolean;
+ robust: boolean;
+ continuousInts: boolean;
+ continuousCategories: boolean;
setConstantPalette: (palette?: ConstantPalette) => void;
setCategoricalPalette: (palette?: CategoricalPalette) => void;
setContinuousPalette: (palette?: ContinuousPalette) => void;
- setUseRobustColorScales: (useRobust: boolean) => void;
+ setRobust: (robust: boolean) => void;
+ setContinuousInts: (continuous: boolean) => void;
+ setContinuousCategories: (continuous: boolean) => void;
}
export const useColors = create()(
@@ -30,35 +34,26 @@ export const useColors = create()(
constantPalette: defaultConstantPalette,
categoricalPalette: defaultCategoricalPalette,
continuousPalette: defaultContinuousPalette,
- useRobustColorScales: false,
+ robust: false,
+ continuousInts: false,
+ continuousCategories: false,
setConstantPalette: (palette) => {
- set((state) => {
- return {
- ...state,
- constantPalette: palette ?? defaultConstantPalette,
- };
- });
+ set({ constantPalette: palette ?? defaultConstantPalette });
},
setCategoricalPalette: (palette) => {
- set((state) => {
- return {
- ...state,
- categoricalPalette: palette ?? defaultCategoricalPalette,
- };
- });
+ set({ categoricalPalette: palette ?? defaultCategoricalPalette });
},
setContinuousPalette: (palette) => {
- set((state) => {
- return {
- ...state,
- continuousPalette: palette ?? defaultContinuousPalette,
- };
- });
+ set({ continuousPalette: palette ?? defaultContinuousPalette });
+ },
+ setRobust: (robust: boolean) => {
+ set({ robust });
+ },
+ setContinuousInts: (continuousInts: boolean) => {
+ set({ continuousInts });
},
- setUseRobustColorScales: (useRobustColorScales: boolean) => {
- set((state) => {
- return { ...state, useRobustColorScales };
- });
+ setContinuousCategories: (continuousCategories: boolean) => {
+ set({ continuousCategories });
},
}),
{
diff --git a/src/stores/dataset/colorTransferFunctionFactory.tsx b/src/stores/dataset/colorTransferFunctionFactory.tsx
index f918ec43..318692ab 100644
--- a/src/stores/dataset/colorTransferFunctionFactory.tsx
+++ b/src/stores/dataset/colorTransferFunctionFactory.tsx
@@ -1,83 +1,40 @@
import {
- DataType,
- isCategorical,
- isFloat,
- isNumerical,
- isScalar,
-} from '../../datatypes';
-import {
- createCategoricalTransferFunction,
- createConstantTransferFunction,
- createContinuousTransferFunction,
+ createColorTransferFunction,
TransferFunction,
} from '../../hooks/useColorTransferFunction';
import _ from 'lodash';
-import { useColors } from '../../stores/colors';
-import {
- ColumnData,
- DataColumn,
- DataStatistics,
- isCategoricalColumn,
- isScalarColumn,
- TableData,
-} from '../../types';
-import { Dataset } from './dataset';
-
-export const makeApplicableColorTransferFunctions = (
- type: DataType,
- data: ColumnData,
- stats?: DataStatistics
-): TransferFunction[] => {
- const transferFunctions: TransferFunction[] = [];
-
- if ((isCategorical(type) || isScalar(type)) && !isFloat(type)) {
- const uniqueValues = _.uniq(data);
- const transFn = createCategoricalTransferFunction(uniqueValues, type);
- transferFunctions.push(transFn);
- }
-
- if (isNumerical(type)) {
- const useRobustColoring = useColors.getState().useRobustColorScales;
-
- const min = useRobustColoring ? stats?.p5 : stats?.min;
- const max = useRobustColoring ? stats?.p95 : stats?.max;
-
- transferFunctions.push(
- createContinuousTransferFunction(min || 0, max || 1, type)
- );
- }
-
- transferFunctions.push(createConstantTransferFunction(type));
-
- return transferFunctions;
-};
+import { DataColumn, TableData } from '../../types';
+import { useColors } from '../colors';
type ColumnsTransferFunctions = Record<
string,
- { full: TransferFunction[]; filtered: TransferFunction[] }
+ { full: TransferFunction; filtered: TransferFunction }
>;
export const makeColumnsColorTransferFunctions = (
columns: DataColumn[],
data: TableData,
- stats: Dataset['columnStats'],
filteredMask: boolean[]
): ColumnsTransferFunctions => {
- return columns
- .filter((column) => isScalarColumn(column) || isCategoricalColumn(column))
- .reduce((a, column) => {
- a[column.key] = {
- full: makeApplicableColorTransferFunctions(
- column.type,
- data[column.key],
- stats.full[column.key]
- ),
- filtered: makeApplicableColorTransferFunctions(
- column.type,
- data[column.key].filter((_, i) => filteredMask[i]),
- stats.filtered[column.key]
- ),
- };
- return a;
- }, {} as ColumnsTransferFunctions);
+ const colors = useColors.getState();
+
+ return columns.reduce((a, column) => {
+ a[column.key] = {
+ full: createColorTransferFunction(
+ data[column.key],
+ column.type,
+ colors.robust,
+ colors.continuousInts,
+ colors.continuousCategories
+ ),
+ filtered: createColorTransferFunction(
+ data[column.key].filter((_, i) => filteredMask[i]),
+ column.type,
+ colors.robust,
+ colors.continuousInts,
+ colors.continuousCategories
+ ),
+ };
+ return a;
+ }, {} as ColumnsTransferFunctions);
};
diff --git a/src/stores/dataset/dataset.ts b/src/stores/dataset/dataset.ts
index 4916c015..154f204d 100644
--- a/src/stores/dataset/dataset.ts
+++ b/src/stores/dataset/dataset.ts
@@ -44,8 +44,8 @@ export interface Dataset {
colorTransferFunctions: Record<
string,
{
- full: TransferFunction[];
- filtered: TransferFunction[];
+ full: TransferFunction;
+ filtered: TransferFunction;
}
>;
recomputeColorTransferFunctions: () => void;
@@ -430,7 +430,6 @@ export const useDataset = create(
const newTransferFunctions = makeColumnsColorTransferFunctions(
get().columns.filter(({ key }) => columnsToCompute.includes(key)),
get().columnData,
- get().columnStats,
get().isIndexFiltered
);
@@ -535,6 +534,8 @@ useDataset.subscribe(
}
);
+useColors.subscribe(useDataset.getState().recomputeColorTransferFunctions);
+
useDataset.subscribe(
(state) => state.selectedIndices,
useDataset.getState().recomputeColumnRelevance
diff --git a/src/stores/dataset/statisticsFactory.tsx b/src/stores/dataset/statisticsFactory.tsx
index 20265276..d559821f 100644
--- a/src/stores/dataset/statisticsFactory.tsx
+++ b/src/stores/dataset/statisticsFactory.tsx
@@ -1,4 +1,4 @@
-import { DataType, isNumerical } from '../../datatypes';
+import { DataType, isCategorical, isNumerical } from '../../datatypes';
import { max, mean, min, quantile, standardDeviation } from 'simple-statistics';
import {
ColumnData,
@@ -13,7 +13,7 @@ export const makeStats = (
data: ColumnData,
mask?: boolean[]
): DataStatistics | undefined => {
- if (!isNumerical(type)) {
+ if (!isNumerical(type) && !isCategorical(type)) {
return;
}
diff --git a/src/widgets/DataGrid/Cell/CategoricalCell.tsx b/src/widgets/DataGrid/Cell/CategoricalCell.tsx
index f7cb40d2..187cfcb5 100644
--- a/src/widgets/DataGrid/Cell/CategoricalCell.tsx
+++ b/src/widgets/DataGrid/Cell/CategoricalCell.tsx
@@ -22,7 +22,7 @@ const CategoricalCell: FunctionComponent = ({ value, column }) => {
(d: Dataset) =>
d.colorTransferFunctions[column.key]?.[
tableView !== 'full' ? 'filtered' : 'full'
- ][0],
+ ],
[column.key, tableView]
);
diff --git a/src/widgets/Histogram/Histogram.tsx b/src/widgets/Histogram/Histogram.tsx
index 99feb64e..1188520a 100644
--- a/src/widgets/Histogram/Histogram.tsx
+++ b/src/widgets/Histogram/Histogram.tsx
@@ -81,7 +81,7 @@ const Histogram: Widget = () => {
stackByColumnKey
? d.colorTransferFunctions[stackByColumnKey]?.[
filter ? 'filtered' : 'full'
- ][0]
+ ]
: createConstantTransferFunction(),
[filter, stackByColumnKey]
);
diff --git a/src/widgets/ScatterplotView/ScatterplotView.tsx b/src/widgets/ScatterplotView/ScatterplotView.tsx
index 3e9dd600..b4560728 100644
--- a/src/widgets/ScatterplotView/ScatterplotView.tsx
+++ b/src/widgets/ScatterplotView/ScatterplotView.tsx
@@ -139,9 +139,7 @@ const ScatterplotView: Widget = () => {
const transferFunctionSelector = useCallback(
(d: Dataset) =>
colorByKey !== undefined && colorByKey.length > 0
- ? d.colorTransferFunctions[colorByKey]?.[
- filter ? 'filtered' : 'full'
- ][0]
+ ? d.colorTransferFunctions[colorByKey]?.[filter ? 'filtered' : 'full']
: createConstantTransferFunction(),
[colorByKey, filter]
);
diff --git a/src/widgets/SimilarityMap/SimilarityMap.tsx b/src/widgets/SimilarityMap/SimilarityMap.tsx
index 023c4dd1..9bd9c55f 100644
--- a/src/widgets/SimilarityMap/SimilarityMap.tsx
+++ b/src/widgets/SimilarityMap/SimilarityMap.tsx
@@ -243,9 +243,7 @@ const SimilarityMap: Widget = () => {
const transferFunctionSelector = useCallback(
(d: Dataset) =>
colorByKey !== undefined && colorByKey.length > 0
- ? d.colorTransferFunctions[colorByKey]?.[
- filter ? 'filtered' : 'full'
- ][0]
+ ? d.colorTransferFunctions[colorByKey]?.[filter ? 'filtered' : 'full']
: createConstantTransferFunction(colorBy?.type ?? unknownDataType),
[colorByKey, filter, colorBy?.type]
);