Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release 14.4.2 #668

Merged
merged 4 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading