Skip to content

Commit

Permalink
Release 14.4.2 (#668)
Browse files Browse the repository at this point in the history
## What's Changed
* fix: scatter plot tweaks by @oltionchampari in
#664
* fix(vis-type: bar): focus facet selector + sort facets alphabetically
by @dv-usama-ansari in #665


**Full Changelog**:
v14.4.1...14.4.2
  • Loading branch information
thinkh authored Dec 19, 2024
2 parents 5af7ffa + 342caa1 commit 21f22f9
Show file tree
Hide file tree
Showing 9 changed files with 45 additions and 27 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "visyn_core",
"description": "Core repository for datavisyn applications.",
"version": "14.4.1",
"version": "14.4.2",
"author": {
"name": "datavisyn GmbH",
"email": "contact@datavisyn.io",
Expand Down
16 changes: 11 additions & 5 deletions src/vis/EagerVis.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,12 @@ export function EagerVis({
*/
showDownloadScreenshot?: boolean;
}) {
const [selectedList, setSelectedList] = useUncontrolled<string[]>({
value: selected,
defaultValue: [],
onChange: selectionCallback,
});

const [showSidebar, setShowSidebar] = useUncontrolled<boolean>({
value: internalShowSidebar,
defaultValue: showSidebarDefault,
Expand Down Expand Up @@ -269,12 +275,12 @@ export function EagerVis({
const selectedMap: { [key: string]: boolean } = React.useMemo(() => {
const currMap: { [key: string]: boolean } = {};

selected.forEach((s) => {
selectedList.forEach((s) => {
currMap[s] = true;
});

return currMap;
}, [selected]);
}, [selectedList]);

const commonProps = {
showSidebar,
Expand Down Expand Up @@ -333,9 +339,9 @@ export function EagerVis({
stats={stats}
statsCallback={statsCallback}
filterCallback={filterCallback}
selectionCallback={selectionCallback}
selectionCallback={setSelectedList}
selectedMap={selectedMap}
selectedList={selected}
selectedList={selectedList}
columns={columns}
showSidebar={showSidebar}
showCloseButton={showCloseButton}
Expand All @@ -348,7 +354,7 @@ export function EagerVis({
</Stack>
{showSidebar && visConfig?.merged ? (
<VisSidebarWrapper config={visConfig} setConfig={setVisConfig} onClick={() => setShowSidebar(false)}>
<VisSidebar config={visConfig} columns={columns} filterCallback={filterCallback} setConfig={setVisConfig} />
<VisSidebar config={visConfig} columns={columns} filterCallback={filterCallback} setConfig={setVisConfig} selectedList={selectedList} />
</VisSidebarWrapper>
) : null}
</Group>
Expand Down
2 changes: 2 additions & 0 deletions src/vis/VisSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export function VisSidebar({
optionsConfig,
config = null,
setConfig = null,
selectedList,
className,
style,
}: ICommonVisSideBarProps<typeof config>) {
Expand All @@ -27,6 +28,7 @@ export function VisSidebar({
filterCallback={filterCallback}
columns={columns}
className={className}
selectedList={selectedList}
style={style}
/>
) : null;
Expand Down
9 changes: 5 additions & 4 deletions src/vis/bar/BarChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,15 +108,16 @@ export function BarChart({
const allUniqueFacetVals = React.useMemo(() => {
const set = new Set();
barData?.facetsColVals?.resolvedValues.forEach((v) => set.add(getLabelOrUnknown(v.val)));
return [...set] as string[];
const uniqueFacetValues = [...set] as string[];
return uniqueFacetValues.sort((a, b) => (a === NAN_REPLACEMENT ? 1 : b === NAN_REPLACEMENT ? -1 : a && b ? a.localeCompare(b) : 0));
}, [barData?.facetsColVals?.resolvedValues]);

const filteredUniqueFacetVals = React.useMemo(() => {
const unsorted =
typeof config?.focusFacetIndex === 'number' && config?.focusFacetIndex < allUniqueFacetVals.length
? ([allUniqueFacetVals[config?.focusFacetIndex]] as string[])
: allUniqueFacetVals;
return unsorted.sort((a, b) => (a === NAN_REPLACEMENT || b === NAN_REPLACEMENT ? 1 : a && b ? a.localeCompare(b) : 0));
return unsorted.sort((a, b) => (a === NAN_REPLACEMENT ? 1 : b === NAN_REPLACEMENT ? -1 : a && b ? a.localeCompare(b) : 0));
}, [allUniqueFacetVals, config?.focusFacetIndex]);

const groupColorScale = React.useMemo(() => {
Expand Down Expand Up @@ -187,8 +188,8 @@ export function BarChart({
}, [aggregatedDataMap?.facets, config]);

const shouldRenderFacets = React.useMemo(
() => Boolean(config?.facets && barData?.facetsColVals && filteredUniqueFacetVals.length === Object.keys(chartHeightMap).length),
[config?.facets, barData?.facetsColVals, filteredUniqueFacetVals.length, chartHeightMap],
() => Boolean(config?.facets && barData?.facetsColVals && (config?.focusFacetIndex !== undefined || config?.focusFacetIndex !== null)),
[config?.facets, barData?.facetsColVals, config?.focusFacetIndex],
);

const isGroupedByNumerical = React.useMemo(() => barData?.groupColVals?.type === EColumnTypes.NUMERICAL, [barData?.groupColVals?.type]);
Expand Down
12 changes: 7 additions & 5 deletions src/vis/bar/components/FocusFacetSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import type { ICommonVisProps } from '../../interfaces';
import { IBarConfig } from '../interfaces';

export function FocusFacetSelector({ config, setConfig, facets }: Pick<ICommonVisProps<IBarConfig>, 'config' | 'setConfig'> & { facets: string[] }) {
const isFacetFocused: boolean = React.useMemo(() => config?.focusFacetIndex !== null && config?.focusFacetIndex !== undefined, [config?.focusFacetIndex]);

if (!config?.facets && facets.length === 0) {
return null;
}
Expand All @@ -17,29 +19,29 @@ export function FocusFacetSelector({ config, setConfig, facets }: Pick<ICommonVi
key={`focusFacetSelect_${config.focusFacetIndex ?? 0}`}
placeholder="Select a focus facet"
data={facets}
value={facets[config.focusFacetIndex ?? 0] || ''}
value={isFacetFocused ? facets[config.focusFacetIndex ?? 0] : ''}
onChange={(value) => {
setConfig?.({ ...config, focusFacetIndex: typeof value === 'string' ? facets.indexOf(value) : value });
}}
clearable
/>
<Tooltip label="Previous facet" position="top" withArrow>
<Tooltip label="Previous facet" position="top" hidden={!isFacetFocused} withArrow withinPortal>
<ActionIcon
color="dvGray"
variant="subtle"
disabled={(config.focusFacetIndex ?? 0) === null}
disabled={!isFacetFocused}
onClick={() => {
setConfig?.({ ...config, focusFacetIndex: ((config.focusFacetIndex ?? 0) - 1 + facets.length) % facets.length });
}}
>
<FontAwesomeIcon icon={faChevronLeft} />
</ActionIcon>
</Tooltip>
<Tooltip label="Next facet" position="top" withArrow>
<Tooltip label="Next facet" position="top" hidden={!isFacetFocused} withArrow withinPortal>
<ActionIcon
color="dvGray"
variant="subtle"
disabled={(config.focusFacetIndex ?? 0) === null}
disabled={!isFacetFocused}
onClick={() => {
setConfig?.({ ...config, focusFacetIndex: ((config.focusFacetIndex ?? 0) + 1) % facets.length });
}}
Expand Down
1 change: 1 addition & 0 deletions src/vis/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ export interface ICommonVisSideBarProps<T> {
style?: React.CSSProperties | undefined;
className?: string | undefined;
columns: VisColumn[];
selectedList?: string[];
optionsConfig?: any;
filterCallback?: (s: EFilterOptions) => void;
config: T;
Expand Down
4 changes: 3 additions & 1 deletion src/vis/scatter/OpacitySlider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ import { useSyncedRef } from '../../hooks';
interface OpacitySliderProps {
callback: (n: number) => void;
currentValue: number;
disabled?: boolean;
}

export function OpacitySlider({ callback, currentValue }: OpacitySliderProps) {
export function OpacitySlider({ callback, currentValue, disabled }: OpacitySliderProps) {
const syncedCallback = useSyncedRef(callback);

const debouncedCallback = useMemo(() => {
Expand All @@ -20,6 +21,7 @@ export function OpacitySlider({ callback, currentValue }: OpacitySliderProps) {
return (
<Input.Wrapper label="Opacity" mb="md">
<Slider
disabled={disabled}
data-testid="OpacitySlider"
step={0.05}
value={+currentValue.toFixed(2)}
Expand Down
4 changes: 3 additions & 1 deletion src/vis/scatter/ScatterVisSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,12 @@ const defaultConfig = {
},
};

export function ScatterVisSidebar({ config, optionsConfig, columns, filterCallback, setConfig }: ICommonVisSideBarProps<IInternalScatterConfig>) {
export function ScatterVisSidebar({ config, optionsConfig, columns, filterCallback, setConfig, selectedList }: ICommonVisSideBarProps<IInternalScatterConfig>) {
const mergedOptionsConfig = useMemo(() => {
return merge({}, defaultConfig, optionsConfig);
}, [optionsConfig]);

const disableOpacitySlider = React.useMemo(() => selectedList && selectedList.length > 0, [selectedList]);
return (
<>
<MultiSelect
Expand Down Expand Up @@ -95,6 +96,7 @@ export function ScatterVisSidebar({ config, optionsConfig, columns, filterCallba
label="Tooltip labels"
/>
<OpacitySlider
disabled={disableOpacitySlider}
callback={(e) => {
if (config.alphaSliderVal !== e) {
setConfig({ ...config, alphaSliderVal: e });
Expand Down
22 changes: 12 additions & 10 deletions src/vis/scatter/useData.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import * as React from 'react';
import isEmpty from 'lodash/isEmpty';
import d3v7 from 'd3v7';
import { PlotlyTypes } from '../../plotly';
import { VIS_NEUTRAL_COLOR } from '../general/constants';
import { EColumnTypes } from '../interfaces';
import { DEFAULT_COLOR, VIS_NEUTRAL_COLOR } from '../general/constants';
import { ELabelingOptions, IInternalScatterConfig } from './interfaces';
import { FetchColumnDataResult } from './utils';
import { getLabelOrUnknown } from '../general/utils';
Expand All @@ -15,7 +13,7 @@ export function baseData(alpha: number, hasColor: boolean): Partial<PlotlyTypes.
return {
selected: {
textfont: {
color: VIS_NEUTRAL_COLOR,
color: DEFAULT_COLOR,
},
marker: {
opacity: 1,
Expand All @@ -28,7 +26,7 @@ export function baseData(alpha: number, hasColor: boolean): Partial<PlotlyTypes.
},
marker: {
color: VIS_NEUTRAL_COLOR,
opacity: Math.min(alpha, 0.2),
opacity: Math.min(alpha, 0.15),
},
},
};
Expand Down Expand Up @@ -68,7 +66,7 @@ export function useData({
if (status !== 'success' || !value) {
return [];
}

const fullOpacityOrAlpha = selectedList.length > 0 ? 1 : config.alphaSliderVal;
if (subplots) {
const plots = subplots.xyPairs.map((pair) => {
return {
Expand Down Expand Up @@ -99,7 +97,8 @@ export function useData({
marker: {
color: value.colorColumn && mappingFunction ? value.colorColumn.resolvedValues.map((v) => mappingFunction(v.val)) : VIS_NEUTRAL_COLOR,
symbol: value.shapeColumn ? value.shapeColumn.resolvedValues.map((v) => shapeScale(v.val as string)) : 'circle',
opacity: config.alphaSliderVal,
opacity: fullOpacityOrAlpha,
size: 8,
},
...baseData(config.alphaSliderVal, !!value.colorColumn),
} as PlotlyTypes.Data;
Expand Down Expand Up @@ -142,9 +141,10 @@ export function useData({
textfont: {
color: VIS_NEUTRAL_COLOR,
},
size: 8,
color: value.colorColumn && mappingFunction ? value.colorColumn.resolvedValues.map((v) => mappingFunction(v.val)) : VIS_NEUTRAL_COLOR,
symbol: value.shapeColumn ? value.shapeColumn.resolvedValues.map((v) => shapeScale(v.val as string)) : 'circle',
opacity: config.alphaSliderVal,
opacity: fullOpacityOrAlpha,
},
...baseData(config.alphaSliderVal, !!value.colorColumn),
} as PlotlyTypes.Data,
Expand Down Expand Up @@ -186,7 +186,8 @@ export function useData({
marker: {
color: value.colorColumn && mappingFunction ? group.data.color.map((v) => mappingFunction(v!)) : VIS_NEUTRAL_COLOR,
symbol: value.shapeColumn ? group.data.shape.map((shape) => shapeScale(shape as string)) : 'circle',
opacity: config.alphaSliderVal,
opacity: fullOpacityOrAlpha,
size: 8,
},
...baseData(config.alphaSliderVal, !!value.colorColumn),
} as PlotlyTypes.Data;
Expand Down Expand Up @@ -215,9 +216,10 @@ export function useData({
),
...(isEmpty(selectedList) ? {} : { selectedpoints: selectedList.map((idx) => splom.idToIndex.get(idx)) }),
marker: {
size: 8,
color: value.colorColumn && mappingFunction ? value.colorColumn.resolvedValues.map((v) => mappingFunction(v.val)) : VIS_NEUTRAL_COLOR,
symbol: value.shapeColumn ? value.shapeColumn.resolvedValues.map((v) => shapeScale(v.val as string)) : 'circle',
opacity: config.alphaSliderVal,
opacity: fullOpacityOrAlpha,
},
...baseData(config.alphaSliderVal, !!value.colorColumn),
} as PlotlyTypes.Data,
Expand Down

0 comments on commit 21f22f9

Please sign in to comment.