From 667af0d871f5ccc1054a35b8c2df464c81a26052 Mon Sep 17 00:00:00 2001 From: Bob Date: Sat, 13 May 2023 00:30:46 +0100 Subject: [PATCH 1/5] fixed order for boxplot and lineplot --- .../eda/src/lib/core/api/DataClient/types.ts | 17 +++--- .../implementations/BoxplotVisualization.tsx | 35 +++++++----- .../implementations/LineplotVisualization.tsx | 13 +++-- .../visualizations/options/types.ts | 1 + .../eda/src/lib/core/utils/visualization.ts | 57 +++++++++++++++++++ .../analysis/hooks/defaultOverlayConfig.ts | 2 +- .../analysis/hooks/standaloneMapMarkers.tsx | 6 +- .../analysis/hooks/standaloneVizPlugins.ts | 11 +++- packages/libs/eda/src/lib/map/index.ts | 5 ++ 9 files changed, 113 insertions(+), 34 deletions(-) diff --git a/packages/libs/eda/src/lib/core/api/DataClient/types.ts b/packages/libs/eda/src/lib/core/api/DataClient/types.ts index 7f3d738097..45cd1a6a9d 100755 --- a/packages/libs/eda/src/lib/core/api/DataClient/types.ts +++ b/packages/libs/eda/src/lib/core/api/DataClient/types.ts @@ -758,6 +758,15 @@ export const MapMarkersOverlayResponse = type({ // OverlayConfig will be used for all next-gen visualizations eventually +export type BinDefinitions = TypeOf; +export const BinDefinitions = array( + type({ + binStart: string, + binEnd: string, + binLabel: string, + }) +); + export type OverlayConfig = TypeOf; export const OverlayConfig = intersection([ type({ @@ -771,13 +780,7 @@ export const OverlayConfig = intersection([ }), type({ overlayType: literal('continuous'), - overlayValues: array( - type({ - binStart: string, - binEnd: string, - binLabel: string, - }) - ), + overlayValues: BinDefinitions, }), ]), ]); diff --git a/packages/libs/eda/src/lib/core/components/visualizations/implementations/BoxplotVisualization.tsx b/packages/libs/eda/src/lib/core/components/visualizations/implementations/BoxplotVisualization.tsx index b5f519ca2e..1c66fda2fd 100755 --- a/packages/libs/eda/src/lib/core/components/visualizations/implementations/BoxplotVisualization.tsx +++ b/packages/libs/eda/src/lib/core/components/visualizations/implementations/BoxplotVisualization.tsx @@ -61,6 +61,7 @@ import { fixVarIdLabel, getVariableLabel, assertValidInputVariables, + fixUnselectedBoxplot, } from '../../../utils/visualization'; import { VariablesByInputName } from '../../../utils/data-element-constraints'; import { StudyEntity, Variable } from '../../../types/study'; @@ -522,27 +523,31 @@ function BoxplotViz(props: VisualizationProps) { xAxisVariable?.vocabulary, xAxisVariable ); - const overlayVocabulary = fixLabelsForNumberVariables( - overlayVariable?.vocabulary, - overlayVariable - ); + const overlayVocabulary = + options?.getOverlayVocabulary?.() ?? + fixLabelsForNumberVariables( + overlayVariable?.vocabulary, + overlayVariable + ); const facetVocabulary = fixLabelsForNumberVariables( facetVariable?.vocabulary, facetVariable ); return grayOutLastSeries( - reorderData( - boxplotResponseToData( - response, - xAxisVariable, - overlayVariable, - facetVariable, + fixUnselectedBoxplot( + reorderData( + boxplotResponseToData( + response, + xAxisVariable, + overlayVariable, + facetVariable, + entities + ), + vocabulary, + vocabularyWithMissingData(overlayVocabulary, showMissingOverlay), + vocabularyWithMissingData(facetVocabulary, showMissingFacet), entities - ), - vocabulary, - vocabularyWithMissingData(overlayVocabulary, showMissingOverlay), - vocabularyWithMissingData(facetVocabulary, showMissingFacet), - entities + ) ), showMissingOverlay, '#a0a0a0' diff --git a/packages/libs/eda/src/lib/core/components/visualizations/implementations/LineplotVisualization.tsx b/packages/libs/eda/src/lib/core/components/visualizations/implementations/LineplotVisualization.tsx index 876a15a0d5..ec85cee5b3 100755 --- a/packages/libs/eda/src/lib/core/components/visualizations/implementations/LineplotVisualization.tsx +++ b/packages/libs/eda/src/lib/core/components/visualizations/implementations/LineplotVisualization.tsx @@ -85,6 +85,7 @@ import { vocabularyWithMissingData, hasIncompleteCases, assertValidInputVariables, + fixUnselectedLineplot, } from '../../../utils/visualization'; import { gray } from '../colors'; import { @@ -739,10 +740,12 @@ function LineplotViz(props: VisualizationProps) { xAxisVariable?.vocabulary, xAxisVariable ); - const overlayVocabulary = fixLabelsForNumberVariables( - overlayVariable?.vocabulary, - overlayVariable - ); + const overlayVocabulary = + options?.getOverlayVocabulary?.() ?? + fixLabelsForNumberVariables( + overlayVariable?.vocabulary, + overlayVariable + ); const facetVocabulary = fixLabelsForNumberVariables( facetVariable?.vocabulary, facetVariable @@ -1955,7 +1958,7 @@ export function lineplotResponseToData( })), }; return { - dataSetProcess, + dataSetProcess: fixUnselectedLineplot(dataSetProcess!), // calculated y axis limits xMin, xMinPos, diff --git a/packages/libs/eda/src/lib/core/components/visualizations/options/types.ts b/packages/libs/eda/src/lib/core/components/visualizations/options/types.ts index 9347f14270..0fa71ed537 100644 --- a/packages/libs/eda/src/lib/core/components/visualizations/options/types.ts +++ b/packages/libs/eda/src/lib/core/components/visualizations/options/types.ts @@ -11,6 +11,7 @@ export interface OverlayOptions { computeConfig: unknown ) => VariableDescriptor | undefined; getOverlayVariableHelp?: () => string; + getOverlayVocabulary?: () => string[] | undefined; getCheckedLegendItems?: (computeConfig: unknown) => string[] | undefined; } diff --git a/packages/libs/eda/src/lib/core/utils/visualization.ts b/packages/libs/eda/src/lib/core/utils/visualization.ts index c0a9e38b4c..99a94789aa 100644 --- a/packages/libs/eda/src/lib/core/utils/visualization.ts +++ b/packages/libs/eda/src/lib/core/utils/visualization.ts @@ -3,6 +3,7 @@ import { BarplotData, BoxplotData, FacetedData, + LinePlotData, } from '@veupathdb/components/lib/types/plots'; import { StudyEntity, Variable } from '../types/study'; import { CoverageStatistics } from '../types/visualization'; @@ -25,6 +26,7 @@ import { VariablesByInputName, } from './data-element-constraints'; import { isEqual } from 'lodash'; +import { UNSELECTED_DISPLAY_TEXT, UNSELECTED_TOKEN } from '../../map'; // was: BarplotData | HistogramData | { series: BoxplotData }; type SeriesWithStatistics = T & CoverageStatistics; @@ -67,6 +69,61 @@ export function grayOutLastSeries< } as SeriesWithStatistics; } +/** + * replace "__UNSELECTED__" with "All other values" in the `name` prop + * + */ + +type NamedSeries = { + series: { + name?: string; + }[]; +}; + +export function fixUnselectedBoxplot( + data: T | MaybeFacetedSeriesWithStatistics +): T | MaybeFacetedSeriesWithStatistics { + if (isFaceted(data)) { + return { + ...data, + facets: data.facets.map((facet) => ({ + ...facet, + data: fixUnselectedBoxplot(data) as T, + })), + }; + } else { + return { + ...data, + series: data.series.map((s) => ({ + ...s, + name: s.name === UNSELECTED_TOKEN ? UNSELECTED_DISPLAY_TEXT : s.name, + })), + }; + } +} + +export function fixUnselectedLineplot( + data: T | FacetedData +): T | FacetedData { + if (isFaceted(data)) { + return { + ...data, + facets: data.facets.map((facet) => ({ + ...facet, + data: fixUnselectedLineplot(data) as T, + })), + }; + } else { + return { + ...data, + series: data.series.map((s) => ({ + ...s, + name: s.name === UNSELECTED_TOKEN ? UNSELECTED_DISPLAY_TEXT : s.name, + })), + }; + } +} + /** * Calculates if there are any incomplete cases for the given variable * (usually overlay or facet variable) diff --git a/packages/libs/eda/src/lib/map/analysis/hooks/defaultOverlayConfig.ts b/packages/libs/eda/src/lib/map/analysis/hooks/defaultOverlayConfig.ts index 9d691b1632..a438e0798c 100644 --- a/packages/libs/eda/src/lib/map/analysis/hooks/defaultOverlayConfig.ts +++ b/packages/libs/eda/src/lib/map/analysis/hooks/defaultOverlayConfig.ts @@ -1,4 +1,5 @@ import { ColorPaletteDefault } from '@veupathdb/components/lib/types/plots'; +import { UNSELECTED_TOKEN } from '../..'; import { BinRange, Filter, @@ -7,7 +8,6 @@ import { Variable, } from '../../../core'; import { DataClient, SubsettingClient } from '../../../core/api'; -import { UNSELECTED_TOKEN } from './standaloneMapMarkers'; // This async function fetches the default overlay config. // For continuous variables, this involves calling the filter-aware-metadata/continuous-variable diff --git a/packages/libs/eda/src/lib/map/analysis/hooks/standaloneMapMarkers.tsx b/packages/libs/eda/src/lib/map/analysis/hooks/standaloneMapMarkers.tsx index 19c3267183..d3c3bb5037 100644 --- a/packages/libs/eda/src/lib/map/analysis/hooks/standaloneMapMarkers.tsx +++ b/packages/libs/eda/src/lib/map/analysis/hooks/standaloneMapMarkers.tsx @@ -27,11 +27,7 @@ import { defaultAnimationDuration } from '@veupathdb/components/lib/map/config/m import { LegendItemsProps } from '@veupathdb/components/lib/components/plotControls/PlotListLegend'; import { VariableDescriptor } from '../../../core/types/variable'; import { useDeepValue } from '../../../core/hooks/immutability'; - -// Back end overlay values contain a special token for the "Other" category: -export const UNSELECTED_TOKEN = '__UNSELECTED__'; -// This is what is displayed to the user instead: -const UNSELECTED_DISPLAY_TEXT = 'All other values'; +import { UNSELECTED_DISPLAY_TEXT, UNSELECTED_TOKEN } from '../..'; /** * Provides markers for use in the MapVEuMap component diff --git a/packages/libs/eda/src/lib/map/analysis/hooks/standaloneVizPlugins.ts b/packages/libs/eda/src/lib/map/analysis/hooks/standaloneVizPlugins.ts index c20e6d9c8a..a3de806435 100644 --- a/packages/libs/eda/src/lib/map/analysis/hooks/standaloneVizPlugins.ts +++ b/packages/libs/eda/src/lib/map/analysis/hooks/standaloneVizPlugins.ts @@ -17,7 +17,7 @@ import { scatterplotVisualization } from '../../../core/components/visualization import { lineplotVisualization } from '../../../core/components/visualizations/implementations/LineplotVisualization'; import { barplotVisualization } from '../../../core/components/visualizations/implementations/BarplotVisualization'; import { boxplotVisualization } from '../../../core/components/visualizations/implementations/BoxplotVisualization'; -import { OverlayConfig } from '../../../core'; +import { BinDefinitions, OverlayConfig } from '../../../core'; import { boxplotRequest } from './plugins/boxplot'; import { barplotRequest } from './plugins/barplot'; import { lineplotRequest } from './plugins/lineplot'; @@ -42,6 +42,15 @@ export function useStandaloneVizPlugins({ hideShowMissingnessToggle: true, layoutComponent: FloatingLayout, getOverlayVariable: (_) => selectedOverlayConfig?.overlayVariable, + getOverlayVocabulary: () => { + const overlayValues = selectedOverlayConfig?.overlayValues; + if (overlayValues == null) return undefined; + if (BinDefinitions.is(overlayValues)) { + return overlayValues.map((bin) => bin.binLabel); + } else { + return overlayValues; + } + }, getOverlayVariableHelp: () => 'The overlay variable can be selected via the top-right panel.', }); diff --git a/packages/libs/eda/src/lib/map/index.ts b/packages/libs/eda/src/lib/map/index.ts index 8eff1a9302..4d824ee45d 100644 --- a/packages/libs/eda/src/lib/map/index.ts +++ b/packages/libs/eda/src/lib/map/index.ts @@ -11,3 +11,8 @@ export type SiteInformationProps = { export const mapNavigationBackgroundColor = 'white'; export const mapNavigationBorder: CSSProperties['border'] = '1px solid #D9D9D9'; + +// Back end overlay values contain a special token for the "Other" category: +export const UNSELECTED_TOKEN = '__UNSELECTED__'; +// This is what is displayed to the user instead: +export const UNSELECTED_DISPLAY_TEXT = 'All other values'; From 39fc4130683d361209a6180367217cebbc4a268a Mon Sep 17 00:00:00 2001 From: Bob Date: Sat, 13 May 2023 12:24:00 +0100 Subject: [PATCH 2/5] fixed ordering and __UNSELECTED__ token --- .../implementations/BarplotVisualization.tsx | 33 +++++++++++-------- .../implementations/BoxplotVisualization.tsx | 4 +-- .../HistogramVisualization.tsx | 31 +++++++++-------- .../implementations/LineplotVisualization.tsx | 4 +-- .../ScatterplotVisualization.tsx | 6 ++-- .../eda/src/lib/core/utils/visualization.ts | 10 +++--- 6 files changed, 51 insertions(+), 37 deletions(-) diff --git a/packages/libs/eda/src/lib/core/components/visualizations/implementations/BarplotVisualization.tsx b/packages/libs/eda/src/lib/core/components/visualizations/implementations/BarplotVisualization.tsx index 788aa2f079..9ffa8bfce6 100755 --- a/packages/libs/eda/src/lib/core/components/visualizations/implementations/BarplotVisualization.tsx +++ b/packages/libs/eda/src/lib/core/components/visualizations/implementations/BarplotVisualization.tsx @@ -53,6 +53,7 @@ import { nonUniqueWarning, hasIncompleteCases, assertValidInputVariables, + substituteUnselectedToken1, } from '../../../utils/visualization'; import { VariablesByInputName } from '../../../utils/data-element-constraints'; // use lodash instead of Math.min/max @@ -452,26 +453,30 @@ function BarplotViz(props: VisualizationProps) { variable?.vocabulary, variable ); - const overlayVocabulary = fixLabelsForNumberVariables( - overlayVariable?.vocabulary, - overlayVariable - ); + const overlayVocabulary = + options?.getOverlayVocabulary?.() ?? + fixLabelsForNumberVariables( + overlayVariable?.vocabulary, + overlayVariable + ); const facetVocabulary = fixLabelsForNumberVariables( facetVariable?.vocabulary, facetVariable ); return grayOutLastSeries( - reorderData( - barplotResponseToData( - response, - variable, - overlayVariable, - facetVariable - ), - vocabulary, - vocabularyWithMissingData(overlayVocabulary, showMissingOverlay), - vocabularyWithMissingData(facetVocabulary, showMissingFacet) + substituteUnselectedToken1( + reorderData( + barplotResponseToData( + response, + variable, + overlayVariable, + facetVariable + ), + vocabulary, + vocabularyWithMissingData(overlayVocabulary, showMissingOverlay), + vocabularyWithMissingData(facetVocabulary, showMissingFacet) + ) ), showMissingOverlay ); diff --git a/packages/libs/eda/src/lib/core/components/visualizations/implementations/BoxplotVisualization.tsx b/packages/libs/eda/src/lib/core/components/visualizations/implementations/BoxplotVisualization.tsx index 1c66fda2fd..ca2f913d3d 100755 --- a/packages/libs/eda/src/lib/core/components/visualizations/implementations/BoxplotVisualization.tsx +++ b/packages/libs/eda/src/lib/core/components/visualizations/implementations/BoxplotVisualization.tsx @@ -61,7 +61,7 @@ import { fixVarIdLabel, getVariableLabel, assertValidInputVariables, - fixUnselectedBoxplot, + substituteUnselectedToken1, } from '../../../utils/visualization'; import { VariablesByInputName } from '../../../utils/data-element-constraints'; import { StudyEntity, Variable } from '../../../types/study'; @@ -534,7 +534,7 @@ function BoxplotViz(props: VisualizationProps) { facetVariable ); return grayOutLastSeries( - fixUnselectedBoxplot( + substituteUnselectedToken1( reorderData( boxplotResponseToData( response, diff --git a/packages/libs/eda/src/lib/core/components/visualizations/implementations/HistogramVisualization.tsx b/packages/libs/eda/src/lib/core/components/visualizations/implementations/HistogramVisualization.tsx index faf8281a2e..13785476f4 100755 --- a/packages/libs/eda/src/lib/core/components/visualizations/implementations/HistogramVisualization.tsx +++ b/packages/libs/eda/src/lib/core/components/visualizations/implementations/HistogramVisualization.tsx @@ -64,6 +64,7 @@ import { variablesAreUnique, nonUniqueWarning, assertValidInputVariables, + substituteUnselectedToken1, } from '../../../utils/visualization'; import { useUpdateThumbnailEffect } from '../../../hooks/thumbnails'; // import variable's metadata-based independent axis range utils @@ -521,24 +522,28 @@ function HistogramViz(props: VisualizationProps) { response.completeCasesTable ); - const overlayVocabulary = fixLabelsForNumberVariables( - overlayVariable?.vocabulary, - overlayVariable - ); + const overlayVocabulary = + options?.getOverlayVocabulary?.() ?? + fixLabelsForNumberVariables( + overlayVariable?.vocabulary, + overlayVariable + ); const facetVocabulary = fixLabelsForNumberVariables( facetVariable?.vocabulary, facetVariable ); return grayOutLastSeries( - reorderData( - histogramResponseToData( - response, - xAxisVariable, - overlayVariable, - facetVariable - ), - vocabularyWithMissingData(overlayVocabulary, showMissingOverlay), - vocabularyWithMissingData(facetVocabulary, showMissingFacet) + substituteUnselectedToken1( + reorderData( + histogramResponseToData( + response, + xAxisVariable, + overlayVariable, + facetVariable + ), + vocabularyWithMissingData(overlayVocabulary, showMissingOverlay), + vocabularyWithMissingData(facetVocabulary, showMissingFacet) + ) ), showMissingOverlay ); diff --git a/packages/libs/eda/src/lib/core/components/visualizations/implementations/LineplotVisualization.tsx b/packages/libs/eda/src/lib/core/components/visualizations/implementations/LineplotVisualization.tsx index ec85cee5b3..562deff1ae 100755 --- a/packages/libs/eda/src/lib/core/components/visualizations/implementations/LineplotVisualization.tsx +++ b/packages/libs/eda/src/lib/core/components/visualizations/implementations/LineplotVisualization.tsx @@ -85,7 +85,7 @@ import { vocabularyWithMissingData, hasIncompleteCases, assertValidInputVariables, - fixUnselectedLineplot, + substituteUnselectedToken2, } from '../../../utils/visualization'; import { gray } from '../colors'; import { @@ -1958,7 +1958,7 @@ export function lineplotResponseToData( })), }; return { - dataSetProcess: fixUnselectedLineplot(dataSetProcess!), + dataSetProcess: substituteUnselectedToken2(dataSetProcess!), // calculated y axis limits xMin, xMinPos, diff --git a/packages/libs/eda/src/lib/core/components/visualizations/implementations/ScatterplotVisualization.tsx b/packages/libs/eda/src/lib/core/components/visualizations/implementations/ScatterplotVisualization.tsx index 653b082667..e9ea666b19 100755 --- a/packages/libs/eda/src/lib/core/components/visualizations/implementations/ScatterplotVisualization.tsx +++ b/packages/libs/eda/src/lib/core/components/visualizations/implementations/ScatterplotVisualization.tsx @@ -78,6 +78,7 @@ import { fixVarIdLabel, getVariableLabel, assertValidInputVariables, + substituteUnselectedToken2, } from '../../../utils/visualization'; import { gray } from '../colors'; import { @@ -779,7 +780,8 @@ function ScatterplotViz(props: VisualizationProps) { ? response.scatterplot.config.variables.find( (v) => v.plotReference === 'overlay' && v.vocabulary != null )?.vocabulary - : fixLabelsForNumberVariables( + : options?.getOverlayVocabulary?.() ?? + fixLabelsForNumberVariables( overlayVariable?.vocabulary, overlayVariable ); @@ -2226,7 +2228,7 @@ export function scatterplotResponseToData( ); return { - dataSetProcess: dataSetProcess, + dataSetProcess: substituteUnselectedToken2(dataSetProcess), xMin, xMinPos, xMax, diff --git a/packages/libs/eda/src/lib/core/utils/visualization.ts b/packages/libs/eda/src/lib/core/utils/visualization.ts index 99a94789aa..476da4acf1 100644 --- a/packages/libs/eda/src/lib/core/utils/visualization.ts +++ b/packages/libs/eda/src/lib/core/utils/visualization.ts @@ -80,7 +80,8 @@ type NamedSeries = { }[]; }; -export function fixUnselectedBoxplot( +// boxplot, barplot, histogram +export function substituteUnselectedToken1( data: T | MaybeFacetedSeriesWithStatistics ): T | MaybeFacetedSeriesWithStatistics { if (isFaceted(data)) { @@ -88,7 +89,7 @@ export function fixUnselectedBoxplot( ...data, facets: data.facets.map((facet) => ({ ...facet, - data: fixUnselectedBoxplot(data) as T, + data: substituteUnselectedToken1(data) as T, })), }; } else { @@ -102,7 +103,8 @@ export function fixUnselectedBoxplot( } } -export function fixUnselectedLineplot( +// lineplot, scatterplot +export function substituteUnselectedToken2( data: T | FacetedData ): T | FacetedData { if (isFaceted(data)) { @@ -110,7 +112,7 @@ export function fixUnselectedLineplot( ...data, facets: data.facets.map((facet) => ({ ...facet, - data: fixUnselectedLineplot(data) as T, + data: substituteUnselectedToken2(data) as T, })), }; } else { From f87eb169cfb84802635e55f0cd3c2f9484f11824 Mon Sep 17 00:00:00 2001 From: Bob Date: Sat, 13 May 2023 13:30:50 +0100 Subject: [PATCH 3/5] start fixing continuous color palette --- .../implementations/BoxplotVisualization.tsx | 10 +++++++++- .../core/components/visualizations/options/types.ts | 2 ++ .../src/lib/map/analysis/hooks/standaloneVizPlugins.ts | 4 ++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/libs/eda/src/lib/core/components/visualizations/implementations/BoxplotVisualization.tsx b/packages/libs/eda/src/lib/core/components/visualizations/implementations/BoxplotVisualization.tsx index ca2f913d3d..fffb57eefe 100755 --- a/packages/libs/eda/src/lib/core/components/visualizations/implementations/BoxplotVisualization.tsx +++ b/packages/libs/eda/src/lib/core/components/visualizations/implementations/BoxplotVisualization.tsx @@ -69,7 +69,10 @@ import { isFaceted } from '@veupathdb/components/lib/types/guards'; // custom legend import PlotLegend from '@veupathdb/components/lib/components/plotControls/PlotLegend'; import { LegendItemsProps } from '@veupathdb/components/lib/components/plotControls/PlotListLegend'; -import { ColorPaletteDefault } from '@veupathdb/components/lib/types/plots/addOns'; +import { + ColorPaletteDefault, + SequentialGradientColorscale, +} from '@veupathdb/components/lib/types/plots/addOns'; // a custom hook to preserve the status of checked legend items import { useCheckedLegendItems } from '../../../hooks/checkedLegendItemsStatus'; import { @@ -725,6 +728,11 @@ function BoxplotViz(props: VisualizationProps) { truncatedDependentAxisWarning={truncatedDependentAxisWarning} setTruncatedDependentAxisWarning={setTruncatedDependentAxisWarning} dependentAxisMinMax={dependentAxisMinMax} + colorPalette={ + options?.getOverlayType?.() === 'continuous' + ? SequentialGradientColorscale + : ColorPaletteDefault + } {...neutralPaletteProps} /> ); diff --git a/packages/libs/eda/src/lib/core/components/visualizations/options/types.ts b/packages/libs/eda/src/lib/core/components/visualizations/options/types.ts index 0fa71ed537..275750918e 100644 --- a/packages/libs/eda/src/lib/core/components/visualizations/options/types.ts +++ b/packages/libs/eda/src/lib/core/components/visualizations/options/types.ts @@ -1,3 +1,4 @@ +import { OverlayConfig } from '../../../api/DataClient'; import { Filter } from '../../../types/filter'; import { VariableDescriptor } from '../../../types/variable'; import { Computation } from '../../../types/visualization'; @@ -11,6 +12,7 @@ export interface OverlayOptions { computeConfig: unknown ) => VariableDescriptor | undefined; getOverlayVariableHelp?: () => string; + getOverlayType?: () => OverlayConfig['overlayType'] | undefined; getOverlayVocabulary?: () => string[] | undefined; getCheckedLegendItems?: (computeConfig: unknown) => string[] | undefined; } diff --git a/packages/libs/eda/src/lib/map/analysis/hooks/standaloneVizPlugins.ts b/packages/libs/eda/src/lib/map/analysis/hooks/standaloneVizPlugins.ts index a3de806435..81e3dee1fe 100644 --- a/packages/libs/eda/src/lib/map/analysis/hooks/standaloneVizPlugins.ts +++ b/packages/libs/eda/src/lib/map/analysis/hooks/standaloneVizPlugins.ts @@ -41,7 +41,11 @@ export function useStandaloneVizPlugins({ hideFacetInputs: true, // will also enable table-only mode for mosaic hideShowMissingnessToggle: true, layoutComponent: FloatingLayout, + // why are we providing three functions to access the properties of + // one object? Because in the pre-SAM world, getOverlayVariable was already + // part of this interface. getOverlayVariable: (_) => selectedOverlayConfig?.overlayVariable, + getOverlayType: () => selectedOverlayConfig?.overlayType, getOverlayVocabulary: () => { const overlayValues = selectedOverlayConfig?.overlayValues; if (overlayValues == null) return undefined; From 6f8351313fe360ed1e9553862e2915b7d07c620f Mon Sep 17 00:00:00 2001 From: Bob Date: Sat, 13 May 2023 15:26:45 +0100 Subject: [PATCH 4/5] final fixes and note about scatter TO DO --- .../implementations/BarplotVisualization.tsx | 11 +++++++++-- .../implementations/BoxplotVisualization.tsx | 2 +- .../implementations/HistogramVisualization.tsx | 11 +++++++++-- .../implementations/LineplotVisualization.tsx | 11 +++++++++-- .../implementations/ScatterplotVisualization.tsx | 14 +++++++++++--- 5 files changed, 39 insertions(+), 10 deletions(-) diff --git a/packages/libs/eda/src/lib/core/components/visualizations/implementations/BarplotVisualization.tsx b/packages/libs/eda/src/lib/core/components/visualizations/implementations/BarplotVisualization.tsx index 9ffa8bfce6..c500566bd9 100755 --- a/packages/libs/eda/src/lib/core/components/visualizations/implementations/BarplotVisualization.tsx +++ b/packages/libs/eda/src/lib/core/components/visualizations/implementations/BarplotVisualization.tsx @@ -74,7 +74,10 @@ import PlotLegend from '@veupathdb/components/lib/components/plotControls/PlotLe import { LegendItemsProps } from '@veupathdb/components/lib/components/plotControls/PlotListLegend'; // import { gray } from '../colors'; -import { ColorPaletteDefault } from '@veupathdb/components/lib/types/plots/addOns'; +import { + ColorPaletteDefault, + SequentialGradientColorscale, +} from '@veupathdb/components/lib/types/plots/addOns'; // a custom hook to preserve the status of checked legend items import { useCheckedLegendItems } from '../../../hooks/checkedLegendItemsStatus'; @@ -454,7 +457,7 @@ function BarplotViz(props: VisualizationProps) { variable ); const overlayVocabulary = - options?.getOverlayVocabulary?.() ?? + (overlayVariable && options?.getOverlayVocabulary?.()) ?? fixLabelsForNumberVariables( overlayVariable?.vocabulary, overlayVariable @@ -680,6 +683,10 @@ function BarplotViz(props: VisualizationProps) { max: truncationConfigDependentAxisMax, }, }, + colorPalette: + options?.getOverlayType?.() === 'continuous' + ? SequentialGradientColorscale + : ColorPaletteDefault, ...neutralPaletteProps, }; diff --git a/packages/libs/eda/src/lib/core/components/visualizations/implementations/BoxplotVisualization.tsx b/packages/libs/eda/src/lib/core/components/visualizations/implementations/BoxplotVisualization.tsx index fffb57eefe..97afc036de 100755 --- a/packages/libs/eda/src/lib/core/components/visualizations/implementations/BoxplotVisualization.tsx +++ b/packages/libs/eda/src/lib/core/components/visualizations/implementations/BoxplotVisualization.tsx @@ -527,7 +527,7 @@ function BoxplotViz(props: VisualizationProps) { xAxisVariable ); const overlayVocabulary = - options?.getOverlayVocabulary?.() ?? + (overlayVariable && options?.getOverlayVocabulary?.()) ?? fixLabelsForNumberVariables( overlayVariable?.vocabulary, overlayVariable diff --git a/packages/libs/eda/src/lib/core/components/visualizations/implementations/HistogramVisualization.tsx b/packages/libs/eda/src/lib/core/components/visualizations/implementations/HistogramVisualization.tsx index 13785476f4..f92b34cb3f 100755 --- a/packages/libs/eda/src/lib/core/components/visualizations/implementations/HistogramVisualization.tsx +++ b/packages/libs/eda/src/lib/core/components/visualizations/implementations/HistogramVisualization.tsx @@ -73,7 +73,10 @@ import PluginError from '../PluginError'; // for custom legend import PlotLegend from '@veupathdb/components/lib/components/plotControls/PlotLegend'; import { LegendItemsProps } from '@veupathdb/components/lib/components/plotControls/PlotListLegend'; -import { ColorPaletteDefault } from '@veupathdb/components/lib/types/plots/addOns'; +import { + ColorPaletteDefault, + SequentialGradientColorscale, +} from '@veupathdb/components/lib/types/plots/addOns'; // a custom hook to preserve the status of checked legend items import { useCheckedLegendItems } from '../../../hooks/checkedLegendItemsStatus'; @@ -523,7 +526,7 @@ function HistogramViz(props: VisualizationProps) { ); const overlayVocabulary = - options?.getOverlayVocabulary?.() ?? + (overlayVariable && options?.getOverlayVocabulary?.()) ?? fixLabelsForNumberVariables( overlayVariable?.vocabulary, overlayVariable @@ -883,6 +886,10 @@ function HistogramViz(props: VisualizationProps) { max: truncationConfigDependentAxisMax, }, }, + colorPalette: + options?.getOverlayType?.() === 'continuous' + ? SequentialGradientColorscale + : ColorPaletteDefault, ...neutralPaletteProps, }; diff --git a/packages/libs/eda/src/lib/core/components/visualizations/implementations/LineplotVisualization.tsx b/packages/libs/eda/src/lib/core/components/visualizations/implementations/LineplotVisualization.tsx index 562deff1ae..b38df9d7dc 100755 --- a/packages/libs/eda/src/lib/core/components/visualizations/implementations/LineplotVisualization.tsx +++ b/packages/libs/eda/src/lib/core/components/visualizations/implementations/LineplotVisualization.tsx @@ -91,6 +91,7 @@ import { gray } from '../colors'; import { AvailableUnitsAddon, ColorPaletteDefault, + SequentialGradientColorscale, } from '@veupathdb/components/lib/types/plots/addOns'; // import variable's metadata-based independent axis range utils import { VariablesByInputName } from '../../../utils/data-element-constraints'; @@ -321,6 +322,12 @@ function LineplotViz(props: VisualizationProps) { providedOverlayVariableDescriptor ); + const colorPaletteOverride = + neutralPaletteProps.colorPalette ?? + options?.getOverlayType?.() === 'continuous' + ? SequentialGradientColorscale + : undefined; + const findEntityAndVariable = useFindEntityAndVariable(filters); const { @@ -741,7 +748,7 @@ function LineplotViz(props: VisualizationProps) { xAxisVariable ); const overlayVocabulary = - options?.getOverlayVocabulary?.() ?? + (overlayVariable && options?.getOverlayVocabulary?.()) ?? fixLabelsForNumberVariables( overlayVariable?.vocabulary, overlayVariable @@ -765,7 +772,7 @@ function LineplotViz(props: VisualizationProps) { showMissingFacet, facetVocabulary, facetVariable, - neutralPaletteProps.colorPalette + colorPaletteOverride ); }, [ outputEntity, diff --git a/packages/libs/eda/src/lib/core/components/visualizations/implementations/ScatterplotVisualization.tsx b/packages/libs/eda/src/lib/core/components/visualizations/implementations/ScatterplotVisualization.tsx index e9ea666b19..32ae45d183 100755 --- a/packages/libs/eda/src/lib/core/components/visualizations/implementations/ScatterplotVisualization.tsx +++ b/packages/libs/eda/src/lib/core/components/visualizations/implementations/ScatterplotVisualization.tsx @@ -86,6 +86,7 @@ import { ColorPaletteDark, gradientSequentialColorscaleMap, gradientDivergingColorscaleMap, + SequentialGradientColorscale, } from '@veupathdb/components/lib/types/plots/addOns'; import { VariablesByInputName } from '../../../utils/data-element-constraints'; import { useRouteMatch } from 'react-router'; @@ -354,7 +355,11 @@ function ScatterplotViz(props: VisualizationProps) { vizConfig.overlayVariable, providedOverlayVariableDescriptor ); - + const colorPaletteOverride = + neutralPaletteProps.colorPalette ?? + options?.getOverlayType?.() === 'continuous' + ? SequentialGradientColorscale + : ColorPaletteDefault; const findEntityAndVariable = useFindEntityAndVariable(filters); const { @@ -780,7 +785,10 @@ function ScatterplotViz(props: VisualizationProps) { ? response.scatterplot.config.variables.find( (v) => v.plotReference === 'overlay' && v.vocabulary != null )?.vocabulary - : options?.getOverlayVocabulary?.() ?? + : // TO DO: remove the categorical condition when https://github.com/VEuPathDB/EdaNewIssues/issues/642 is sorted + (overlayVariable && options?.getOverlayType?.() === 'categorical' + ? options?.getOverlayVocabulary?.() + : undefined) ?? fixLabelsForNumberVariables( overlayVariable?.vocabulary, overlayVariable @@ -802,7 +810,7 @@ function ScatterplotViz(props: VisualizationProps) { // pass computation computation.descriptor.type, entities, - neutralPaletteProps.colorPalette + colorPaletteOverride ); return { ...returnData, From 6d69a76a4ce3605282a1a4c561f367b474d70764 Mon Sep 17 00:00:00 2001 From: Bob MacCallum Date: Mon, 22 May 2023 17:29:19 +0100 Subject: [PATCH 5/5] added Dave's suggestion --- .../implementations/BarplotVisualization.tsx | 4 +-- .../implementations/BoxplotVisualization.tsx | 4 +-- .../HistogramVisualization.tsx | 4 +-- .../implementations/LineplotVisualization.tsx | 4 +-- .../ScatterplotVisualization.tsx | 4 +-- .../eda/src/lib/core/utils/visualization.ts | 33 +++---------------- 6 files changed, 15 insertions(+), 38 deletions(-) diff --git a/packages/libs/eda/src/lib/core/components/visualizations/implementations/BarplotVisualization.tsx b/packages/libs/eda/src/lib/core/components/visualizations/implementations/BarplotVisualization.tsx index c500566bd9..87148667a0 100755 --- a/packages/libs/eda/src/lib/core/components/visualizations/implementations/BarplotVisualization.tsx +++ b/packages/libs/eda/src/lib/core/components/visualizations/implementations/BarplotVisualization.tsx @@ -53,7 +53,7 @@ import { nonUniqueWarning, hasIncompleteCases, assertValidInputVariables, - substituteUnselectedToken1, + substituteUnselectedToken, } from '../../../utils/visualization'; import { VariablesByInputName } from '../../../utils/data-element-constraints'; // use lodash instead of Math.min/max @@ -468,7 +468,7 @@ function BarplotViz(props: VisualizationProps) { ); return grayOutLastSeries( - substituteUnselectedToken1( + substituteUnselectedToken( reorderData( barplotResponseToData( response, diff --git a/packages/libs/eda/src/lib/core/components/visualizations/implementations/BoxplotVisualization.tsx b/packages/libs/eda/src/lib/core/components/visualizations/implementations/BoxplotVisualization.tsx index 97afc036de..ac514f1b69 100755 --- a/packages/libs/eda/src/lib/core/components/visualizations/implementations/BoxplotVisualization.tsx +++ b/packages/libs/eda/src/lib/core/components/visualizations/implementations/BoxplotVisualization.tsx @@ -61,7 +61,7 @@ import { fixVarIdLabel, getVariableLabel, assertValidInputVariables, - substituteUnselectedToken1, + substituteUnselectedToken, } from '../../../utils/visualization'; import { VariablesByInputName } from '../../../utils/data-element-constraints'; import { StudyEntity, Variable } from '../../../types/study'; @@ -537,7 +537,7 @@ function BoxplotViz(props: VisualizationProps) { facetVariable ); return grayOutLastSeries( - substituteUnselectedToken1( + substituteUnselectedToken( reorderData( boxplotResponseToData( response, diff --git a/packages/libs/eda/src/lib/core/components/visualizations/implementations/HistogramVisualization.tsx b/packages/libs/eda/src/lib/core/components/visualizations/implementations/HistogramVisualization.tsx index f92b34cb3f..e473228da9 100755 --- a/packages/libs/eda/src/lib/core/components/visualizations/implementations/HistogramVisualization.tsx +++ b/packages/libs/eda/src/lib/core/components/visualizations/implementations/HistogramVisualization.tsx @@ -64,7 +64,7 @@ import { variablesAreUnique, nonUniqueWarning, assertValidInputVariables, - substituteUnselectedToken1, + substituteUnselectedToken, } from '../../../utils/visualization'; import { useUpdateThumbnailEffect } from '../../../hooks/thumbnails'; // import variable's metadata-based independent axis range utils @@ -536,7 +536,7 @@ function HistogramViz(props: VisualizationProps) { facetVariable ); return grayOutLastSeries( - substituteUnselectedToken1( + substituteUnselectedToken( reorderData( histogramResponseToData( response, diff --git a/packages/libs/eda/src/lib/core/components/visualizations/implementations/LineplotVisualization.tsx b/packages/libs/eda/src/lib/core/components/visualizations/implementations/LineplotVisualization.tsx index b38df9d7dc..727315c8f1 100755 --- a/packages/libs/eda/src/lib/core/components/visualizations/implementations/LineplotVisualization.tsx +++ b/packages/libs/eda/src/lib/core/components/visualizations/implementations/LineplotVisualization.tsx @@ -85,7 +85,7 @@ import { vocabularyWithMissingData, hasIncompleteCases, assertValidInputVariables, - substituteUnselectedToken2, + substituteUnselectedToken, } from '../../../utils/visualization'; import { gray } from '../colors'; import { @@ -1965,7 +1965,7 @@ export function lineplotResponseToData( })), }; return { - dataSetProcess: substituteUnselectedToken2(dataSetProcess!), + dataSetProcess: substituteUnselectedToken(dataSetProcess!), // calculated y axis limits xMin, xMinPos, diff --git a/packages/libs/eda/src/lib/core/components/visualizations/implementations/ScatterplotVisualization.tsx b/packages/libs/eda/src/lib/core/components/visualizations/implementations/ScatterplotVisualization.tsx index 32ae45d183..8d7c1ab61f 100755 --- a/packages/libs/eda/src/lib/core/components/visualizations/implementations/ScatterplotVisualization.tsx +++ b/packages/libs/eda/src/lib/core/components/visualizations/implementations/ScatterplotVisualization.tsx @@ -78,7 +78,7 @@ import { fixVarIdLabel, getVariableLabel, assertValidInputVariables, - substituteUnselectedToken2, + substituteUnselectedToken, } from '../../../utils/visualization'; import { gray } from '../colors'; import { @@ -2236,7 +2236,7 @@ export function scatterplotResponseToData( ); return { - dataSetProcess: substituteUnselectedToken2(dataSetProcess), + dataSetProcess: substituteUnselectedToken(dataSetProcess), xMin, xMinPos, xMax, diff --git a/packages/libs/eda/src/lib/core/utils/visualization.ts b/packages/libs/eda/src/lib/core/utils/visualization.ts index 476da4acf1..314519fe1c 100644 --- a/packages/libs/eda/src/lib/core/utils/visualization.ts +++ b/packages/libs/eda/src/lib/core/utils/visualization.ts @@ -80,39 +80,16 @@ type NamedSeries = { }[]; }; -// boxplot, barplot, histogram -export function substituteUnselectedToken1( - data: T | MaybeFacetedSeriesWithStatistics -): T | MaybeFacetedSeriesWithStatistics { +export function substituteUnselectedToken< + T extends NamedSeries, + Data extends T | FacetedData | MaybeFacetedSeriesWithStatistics +>(data: Data): Data { if (isFaceted(data)) { return { ...data, facets: data.facets.map((facet) => ({ ...facet, - data: substituteUnselectedToken1(data) as T, - })), - }; - } else { - return { - ...data, - series: data.series.map((s) => ({ - ...s, - name: s.name === UNSELECTED_TOKEN ? UNSELECTED_DISPLAY_TEXT : s.name, - })), - }; - } -} - -// lineplot, scatterplot -export function substituteUnselectedToken2( - data: T | FacetedData -): T | FacetedData { - if (isFaceted(data)) { - return { - ...data, - facets: data.facets.map((facet) => ({ - ...facet, - data: substituteUnselectedToken2(data) as T, + data: substituteUnselectedToken(data) as T, })), }; } else {