Skip to content

Commit

Permalink
Release 14.2.0 (#623)
Browse files Browse the repository at this point in the history
## What's Changed
* fix(vis-type: bar): grouping with zero values by @dvdanielamoitzi in
#598
* fix(vis-type: bar): add tooltip to clipped axis labels by
@dv-usama-ansari in #599
* fix(vis-type: bar): selection is lost when bar plot is sorted by
@dv-usama-ansari in #604
* feat: use `FastTextMeasure` to get the truncated labels by
@dv-usama-ansari in #606
* fix(vis-type: bar): axis labels when sort state is null by
@dv-usama-ansari in #607
* fix: capturing a screenshot is broken for several visualizations by
@oltionchampari in #608
* feat(icon): Option for descending sort first + no unsorted state by
@dvdanielamoitzi in #609
* feat: Add `onClick` to `usePan` by @dvmoritzschoefl in
#619
* feat: add `get_default_redis_url()` by @dvviktordelev in
#610
* feat(vis-type: scatter): Add log scale option for axes by
@dvmoritzschoefl in #602
* fix: exports in general vis by @dvdanielamoitzi in
#621
* Added `useAnimatedTransform` hook by @dvmoritzschoefl in
#620
* Pinned @swc/core to 1.7.42 by @dvmoritzschoefl in
#622


**Full Changelog**:
v14.1.0...14.2.0
  • Loading branch information
thinkh authored Nov 6, 2024
2 parents ca56290 + e4a6e3a commit 662fbb4
Show file tree
Hide file tree
Showing 31 changed files with 466 additions and 158 deletions.
5 changes: 4 additions & 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.1.1",
"version": "14.2.0",
"author": {
"name": "datavisyn GmbH",
"email": "[email protected]",
Expand Down Expand Up @@ -145,6 +145,9 @@
"storybook": "^7.6.20",
"storybook-addon-swc": "^1.2.0"
},
"resolutions": {
"@swc/core": "1.7.42"
},
"visyn": {
"entries": {
"app": {
Expand Down
44 changes: 19 additions & 25 deletions src/vis/bar/BarChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@ import { ListChildComponentProps, VariableSizeList } from 'react-window';
import { BlurredOverlay } from '../../components';
import { useAsync } from '../../hooks/useAsync';
import { categoricalColors10 } from '../../utils/colors';
import { NAN_REPLACEMENT } from '../general';
import { DownloadPlotButton } from '../general/DownloadPlotButton';
import { ErrorMessage } from '../general/ErrorMessage';
import { getLabelOrUnknown } from '../general/utils';
import { DownloadPlotButton, ErrorMessage } from '../general';
import { FastTextMeasure } from '../general/FastTextMeasure';
import { ColumnInfo, EAggregateTypes, EColumnTypes, ICommonVisProps } from '../interfaces';
import { FocusFacetSelector } from './components';
import { EBarDirection, EBarDisplayType, EBarGroupingType, IBarConfig } from './interfaces';
Expand All @@ -29,6 +27,8 @@ import {
WorkerWrapper,
} from './interfaces/internal';
import { SingleEChartsBarChart } from './SingleEChartsBarChart';
import { getLabelOrUnknown } from '../general/utils';
import { NAN_REPLACEMENT } from '../general/constants';

type VirtualizedBarChartProps = {
aggregatedDataMap: Awaited<ReturnType<typeof generateAggregatedDataLookup>>;
Expand All @@ -51,6 +51,8 @@ type VirtualizedBarChartProps = {
setConfig: (config: IBarConfig) => void;
};

const textMeasure = new FastTextMeasure('16px Arial');

export function BarChart({
config,
setConfig,
Expand All @@ -73,6 +75,7 @@ export function BarChart({
config?.facets as ColumnInfo,
config?.aggregateColumn as ColumnInfo,
]);

const generateDataTableWorker = React.useCallback(async (...args: Parameters<typeof generateDataTable>) => WorkerWrapper.generateDataTable(...args), []);
const { execute: generateDataTableTrigger, status: dataTableStatus } = useAsync(generateDataTableWorker);

Expand All @@ -82,12 +85,6 @@ export function BarChart({
);
const { execute: generateAggregatedDataLookupTrigger, status: dataLookupStatus } = useAsync(generateAggregateDataLookupWorker);

const getTruncatedTextMapWorker = React.useCallback(
async (...args: Parameters<GenerateAggregatedDataLookup['getTruncatedTextMap']>) => WorkerWrapper.getTruncatedTextMap(...args),
[],
);
const { execute: getTruncatedTextMapTrigger, status: truncatedTextStatus } = useAsync(getTruncatedTextMapWorker);

const [itemData, setItemData] = React.useState<VirtualizedBarChartProps | null>(null);
const [dataTable, setDataTable] = React.useState<ReturnType<typeof generateDataTable>>([]);
const [aggregatedDataMap, setAggregatedDataMap] = React.useState<Awaited<ReturnType<typeof generateAggregateDataLookupWorker>> | null>(null);
Expand All @@ -102,8 +99,8 @@ export function BarChart({
const isLoading = React.useMemo(() => barDataStatus === 'pending' || dataTableStatus === 'pending', [barDataStatus, dataTableStatus]);

const isError = React.useMemo(
() => barDataStatus === 'error' || dataTableStatus === 'error' || dataLookupStatus === 'error' || truncatedTextStatus === 'error',
[barDataStatus, dataLookupStatus, dataTableStatus, truncatedTextStatus],
() => barDataStatus === 'error' || dataTableStatus === 'error' || dataLookupStatus === 'error',
[barDataStatus, dataLookupStatus, dataTableStatus],
);

const isSuccess = React.useMemo(() => barDataStatus === 'success' && dataTableStatus === 'success', [barDataStatus, dataTableStatus]);
Expand Down Expand Up @@ -315,19 +312,16 @@ export function BarChart({
]);

useShallowEffect(() => {
const fetchTruncatedTextMap = async () => {
const truncatedTextMap = await getTruncatedTextMapTrigger(
Object.values(aggregatedDataMap?.facets ?? {})
.map((value) => value?.categoriesList ?? [])
.flat(),
config?.direction === EBarDirection.HORIZONTAL ? Math.max(gridLeft, containerWidth / 3) - 20 : 70,
);
setLabelsMap(truncatedTextMap.map);
setLongestLabelWidth(truncatedTextMap.longestLabelWidth);
setGridLeft(Math.min(containerWidth / 3, Math.max(longestLabelWidth + 20, 60)));
};
fetchTruncatedTextMap();
}, [aggregatedDataMap?.facets, aggregatedDataMap?.facetsList, config?.direction, containerWidth, getTruncatedTextMapTrigger, gridLeft, longestLabelWidth]);
Object.values(aggregatedDataMap?.facets ?? {})
.map((value) => value?.categoriesList ?? [])
.flat()
.forEach((c) => {
const text = textMeasure.textEllipsis(c, config?.direction === EBarDirection.HORIZONTAL ? Math.max(gridLeft, containerWidth / 3) - 20 : 70);
setLongestLabelWidth((p) => Math.max(p, textMeasure.fastMeasureText(c)));
setLabelsMap((prev) => ({ ...prev, [c]: text }));
});
setGridLeft(Math.min(containerWidth / 3, Math.max(longestLabelWidth + 20, 60)));
}, [aggregatedDataMap?.facets, config?.direction, containerWidth, gridLeft, longestLabelWidth]);

React.useEffect(() => {
setItemData({
Expand Down
10 changes: 5 additions & 5 deletions src/vis/bar/SingleEChartsBarChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { BlurredOverlay } from '../../components';
import { type ECOption, useChart } from '../../echarts';
import { useAsync } from '../../hooks';
import { sanitize, selectionColorDark } from '../../utils';
import { DEFAULT_COLOR, NAN_REPLACEMENT, SELECT_COLOR, VIS_NEUTRAL_COLOR, VIS_UNSELECTED_OPACITY } from '../general';
import { DEFAULT_COLOR, NAN_REPLACEMENT, SELECT_COLOR, VIS_NEUTRAL_COLOR, VIS_UNSELECTED_OPACITY } from '../general/constants';
import { ErrorMessage } from '../general/ErrorMessage';
import { WarningMessage } from '../general/WarningMessage';
import { ColumnInfo, EAggregateTypes, ICommonVisProps } from '../interfaces';
Expand Down Expand Up @@ -681,9 +681,9 @@ function EagerSingleEChartsBarChart({
: '';
const aggregationAxisSortText =
config?.direction === EBarDirection.HORIZONTAL
? SortDirectionMap[config?.sortState?.x as EBarSortState]
? SortDirectionMap[config?.sortState?.x ?? EBarSortState.NONE]
: config?.direction === EBarDirection.VERTICAL
? SortDirectionMap[config?.sortState?.y as EBarSortState]
? SortDirectionMap[config?.sortState?.y ?? EBarSortState.NONE]
: '';
const aggregationAxisName = `${aggregationAxisNameBase}${aggregationAxisDescription} (${aggregationAxisSortText})`;

Expand All @@ -695,9 +695,9 @@ function EagerSingleEChartsBarChart({
: '';
const categoricalAxisSortText =
config?.direction === EBarDirection.HORIZONTAL
? SortDirectionMap[config?.sortState?.y as EBarSortState]
? SortDirectionMap[config?.sortState?.y ?? EBarSortState.NONE]
: config?.direction === EBarDirection.VERTICAL
? SortDirectionMap[config?.sortState?.x as EBarSortState]
? SortDirectionMap[config?.sortState?.x ?? EBarSortState.NONE]
: '';
const categoricalAxisName = `${categoricalAxisNameBase}${categoricalAxisDescription} (${categoricalAxisSortText})`;

Expand Down
3 changes: 1 addition & 2 deletions src/vis/bar/interfaces/internal/helpers/bar-vis.worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ import * as ComLink from 'comlink';
import { generateAggregatedDataLookup } from './generate-aggregated-data-lookup';
import { generateBarSeries } from './generate-bar-series';
import { generateDataTable } from './generate-data-table';
import { getTruncatedTextMap } from './get-truncated-text-map';

const exposed = { generateAggregatedDataLookup, generateBarSeries, generateDataTable, getTruncatedTextMap };
const exposed = { generateAggregatedDataLookup, generateBarSeries, generateDataTable };

export type GenerateAggregatedDataLookup = typeof exposed;

Expand Down
2 changes: 1 addition & 1 deletion src/vis/bar/interfaces/internal/helpers/get-bar-data.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { resolveSingleColumn } from '../../../../general';
import { resolveSingleColumn } from '../../../../general/layoutUtils';
import { ColumnInfo, EColumnTypes, VisCategoricalValue, VisColumn, VisNumericalValue } from '../../../../interfaces';
import { VisColumnWithResolvedValues } from '../../types';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { NAN_REPLACEMENT } from '../../../../general';
import { NAN_REPLACEMENT } from '../../../../general/constants';
import { defaultConfig } from '../../constants';
import { getDataForAggregationType } from './get-data-for-aggregate-type';

Expand Down
38 changes: 0 additions & 38 deletions src/vis/bar/interfaces/internal/helpers/get-truncated-text-map.ts

This file was deleted.

1 change: 0 additions & 1 deletion src/vis/bar/interfaces/internal/helpers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ export * from './create-bin-lookup';
export * from './generate-aggregated-data-lookup';
export * from './generate-bar-series';
export * from './generate-data-table';
export * from './get-truncated-text-map';
export * from './get-bar-data';
export * from './get-data-for-aggregate-type';
export * from './median';
Expand Down
2 changes: 1 addition & 1 deletion src/vis/bar/interfaces/internal/helpers/sort-series.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { BarSeriesOption } from 'echarts/charts';
import { NAN_REPLACEMENT } from '../../../../general';
import { NAN_REPLACEMENT } from '../../../../general/constants';
import { EBarSortState, EBarDirection } from '../../enums';

/**
Expand Down
44 changes: 23 additions & 21 deletions src/vis/correlation/CorrelationMatrix.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -184,32 +184,34 @@ export function CorrelationMatrix({
return (
<Stack pr="40px" style={{ height: '100%', width: '100%' }}>
{status === 'success' ? (
<Stack align="center" gap={0} id={id} style={{ height: '100%', width: '100%' }}>
<Stack align="center" gap={0} style={{ height: '100%', width: '100%' }}>
{showDownloadScreenshot ? (
<Center>
<DownloadPlotButton uniquePlotId={id} config={config} />
</Center>
) : null}
<Box pl={margin.left} pr={margin.right}>
<ColorLegendVert format=".3~g" scale={colorScale} width={availableSize} height={20} range={[-1, 1]} title="Correlation" />
</Box>
<Box ref={ref} style={{ height: '100%', width: `100%`, overflow: 'hidden' }}>
<svg style={{ height, width, overflow: 'hidden' }}>
<g transform={`translate(${(width - availableSize - margin.left - margin.right) / 2}, 0)`}>
{memoizedCorrelationResults?.map((value) => {
return (
<CorrelationPair
key={`${value.xName}-${value.yName}`}
value={value}
fill={colorScale(value.correlation)}
boundingRect={{ width: xScale.bandwidth(), height: yScale.bandwidth() }}
config={config}
/>
);
})}
{labelsDiagonal}
</g>
</svg>
<Box id={id} style={{ height: '100%', width: '100%' }}>
<Box pl={margin.left} pr={margin.right}>
<ColorLegendVert format=".3~g" scale={colorScale} width={availableSize} height={20} range={[-1, 1]} title="Correlation" />
</Box>
<Box ref={ref} style={{ height: '100%', width: `100%`, overflow: 'hidden' }}>
<svg style={{ height, width, overflow: 'hidden' }}>
<g transform={`translate(${(width - availableSize - margin.left - margin.right) / 2}, 0)`}>
{memoizedCorrelationResults?.map((value) => {
return (
<CorrelationPair
key={`${value.xName}-${value.yName}`}
value={value}
fill={colorScale(value.correlation)}
boundingRect={{ width: xScale.bandwidth(), height: yScale.bandwidth() }}
config={config}
/>
);
})}
{labelsDiagonal}
</g>
</svg>
</Box>
</Box>
</Stack>
) : (
Expand Down
File renamed without changes.
86 changes: 86 additions & 0 deletions src/vis/general/SortIcon.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import React from 'react';
import { ComponentStory } from '@storybook/react';
import { Stack, Text, Group } from '@mantine/core';
import { ESortStates, SortIcon, ISortIconProps } from './SortIcon';

function Wrapper({ props, initialState }: { props?: Omit<ISortIconProps, 'sortState' | 'setSortState'>; initialState?: ESortStates }) {
const [sortState, setSortState] = React.useState<ESortStates>(initialState || ESortStates.NONE);

return (
<Stack gap="xs">
<Group>
<SortIcon {...props} sortState={sortState} setSortState={setSortState} />

{[2, 1, 5, 3, 4]
.sort((a, b) => {
switch (sortState) {
case ESortStates.ASC:
return a - b;
case ESortStates.DESC:
return b - a;
default:
return 0;
}
})
.map((i) => (
<Text key={i}>{i}</Text>
))}
</Group>
</Stack>
);
}

function Docs() {
return (
<Stack p="xl" gap="xl">
<Stack gap="xs">
<Text fz="xl" fw={500}>
Basic example
</Text>
<Wrapper />
</Stack>
<Stack gap="xs">
<Text fz="xl" fw={500}>
Compact icon
</Text>
<Wrapper props={{ compact: true }} />
</Stack>
<Stack gap="xs">
<Text fz="xl" fw={500}>
With priority
</Text>
<Wrapper props={{ priority: 1 }} />
</Stack>
<Stack gap="xs">
<Text fz="xl" fw={500}>
Has no unsorted state
</Text>
<Wrapper props={{ hasUnsortedState: false }} initialState={ESortStates.ASC} />
</Stack>
<Stack gap="xs">
<Stack gap={0}>
<Text fz="xl" fw={500}>
Sort descending on first click
</Text>
<Text c="dimmed">Only for specific use cases - the default is ascending</Text>
</Stack>
<Wrapper props={{ sortStateOnFirstClick: ESortStates.DESC }} />
</Stack>
</Stack>
);
}

// More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
export default {
title: 'Components/SortIcon',
component: Docs,
// More on argTypes: https://storybook.js.org/docs/react/api/argtypes
};

// More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args
// eslint-disable-next-line react/function-component-definition
const Template: ComponentStory<typeof Docs> = (args) => {
return <Docs />;
};

export const Default: typeof Template = Template.bind({});
Loading

0 comments on commit 662fbb4

Please sign in to comment.