/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/
import { isEmpty, isEqual, uniq } from 'lodash';
import React, { useMemo } from 'react';
import {
DEFAULT_PALETTE,
MULTI_COLOR_PALETTE,
SINGLE_COLOR_PALETTE,
} from '../../../../../common/constants/colors';
import { AGGREGATIONS, GROUPBY } from '../../../../../common/constants/explorer';
import { DEFAULT_CHART_STYLES, PLOT_MARGIN } from '../../../../../common/constants/shared';
import { IVisualizationContainerProps } from '../../../../../common/types/explorer';
import { EmptyPlaceholder } from '../../../event_analytics/explorer/visualizations/shared_components/empty_placeholder';
import { Plt } from '../../plotly/plot';
export const TreeMap = ({ visualizations, layout, config }: any) => {
const { DefaultSortSectors } = DEFAULT_CHART_STYLES;
const {
data: {
defaultAxes,
indexFields,
query,
rawVizData: {
data: queriedVizData,
metadata: { fields },
},
userConfigs: {
dataConfig: {
chartStyles = {},
legend = {},
tooltipOptions = {},
panelOptions = {},
treemapOptions = {},
[GROUPBY]: dimensions = [],
[AGGREGATIONS]: series = [],
},
layoutConfig = {},
},
},
vis: { icontype },
}: IVisualizationContainerProps = visualizations;
const childField =
dimensions && dimensions[0]?.childField ? dimensions[0]?.childField : fields[fields.length - 1];
const parentFields = dimensions && dimensions[0]?.parentFields ? dimensions[0]?.parentFields : [];
const tooltipMode =
tooltipOptions.tooltipMode !== undefined ? tooltipOptions.tooltipMode : 'show';
const tooltipText = tooltipOptions.tooltipText !== undefined ? tooltipOptions.tooltipText : 'all';
const valueField = series && series[0]?.valueField ? series[0]?.valueField : fields[0];
const colorField =
chartStyles && chartStyles.colorTheme ? chartStyles.colorTheme : { name: DEFAULT_PALETTE };
const tilingAlgorithm =
treemapOptions && treemapOptions.tilingAlgorithm && !isEmpty(treemapOptions.tilingAlgorithm)
? treemapOptions.tilingAlgorithm[0]
: 'squarify';
const sortSectorsField = treemapOptions.sort_sectors || DefaultSortSectors;
const showColorscale = legend.showLegend ?? 'show';
const areParentFieldsInvalid =
new Set([...parentFields.map((field) => field.name)]).size !== parentFields.length ||
parentFields.some(
(field) => isEmpty(queriedVizData[field.name]) || isEqual(childField.name, field.name)
);
if (
isEmpty(queriedVizData[childField.name]) ||
isEmpty(queriedVizData[valueField.name]) ||
areParentFieldsInvalid
)
return ;
const [treemapData, mergedLayout] = useMemo(() => {
let labelsArray: string[] = [];
let parentsArray: string[] = [];
let valuesArray: number[] = [];
let colorsArray: string[] = [];
if (parentFields.length === 0) {
labelsArray = [...queriedVizData[childField.name]];
parentsArray = [...Array(labelsArray.length).fill('')];
valuesArray = [...queriedVizData[valueField.name]];
if (colorField.name === MULTI_COLOR_PALETTE) {
colorsArray = [
...Array(queriedVizData[childField.name].length).fill(colorField.childColor),
];
}
} else {
let currentLevel = parentFields.length - 1;
let lastParentField = {};
parentFields
.slice(0)
.reverse()
.map((field, i) => {
const uniqueParents = uniq(queriedVizData[field.name]) as string[];
labelsArray = [...labelsArray, ...uniqueParents];
if (i === 0) {
parentsArray = [...Array(uniqueParents.length).fill('')];
valuesArray = [...Array(uniqueParents.length).fill(0)];
colorsArray =
colorField.name === MULTI_COLOR_PALETTE
? [
...Array(uniqueParents.length).fill(
colorField.parentColors[currentLevel] ?? '#000000'
),
]
: [];
} else {
const currentParentIndices = uniqueParents.map((parent) =>
queriedVizData[field.name].findIndex((index) => index === parent)
);
const lastParents = currentParentIndices.map(
(index) => queriedVizData[lastParentField.name][index]
);
parentsArray = [...parentsArray, ...lastParents];
valuesArray = [...valuesArray, ...Array(lastParents.length).fill(0)];
colorsArray =
colorField.name === MULTI_COLOR_PALETTE
? [
...colorsArray,
...Array(lastParents.length).fill(
colorField.parentColors[currentLevel] ?? '#000000'
),
]
: [];
}
currentLevel = currentLevel - 1;
lastParentField = field;
});
labelsArray = [...labelsArray, ...queriedVizData[childField.name]];
valuesArray = [...valuesArray, ...queriedVizData[valueField.name]];
parentsArray = [...parentsArray, ...queriedVizData[lastParentField.name]];
colorsArray =
colorField.name === MULTI_COLOR_PALETTE
? [
...colorsArray,
...Array(queriedVizData[childField.name].length).fill(colorField.childColor),
]
: [];
}
if (colorField.name === SINGLE_COLOR_PALETTE) {
colorsArray = [...Array(valuesArray.length).fill(colorField.childColor)];
}
const markerColors =
colorField.name === MULTI_COLOR_PALETTE
? { colors: colorsArray }
: ![DEFAULT_PALETTE, SINGLE_COLOR_PALETTE].includes(colorField.name)
? {
colorscale: colorField.name,
colorbar: {
len: 1,
},
showscale: showColorscale === 'show',
}
: {};
const colorway = colorField.name === SINGLE_COLOR_PALETTE ? colorsArray : {};
const mapLayout = {
...layout,
...(layoutConfig.layout && layoutConfig.layout),
title: panelOptions.title || layoutConfig.layout?.title || '',
treemapcolorway: colorway,
margin: PLOT_MARGIN,
};
const mapData = [
{
type: 'treemap',
labels: labelsArray,
parents: parentsArray,
values: valuesArray,
hoverinfo: tooltipMode === 'hidden' ? 'none' : tooltipText,
textinfo: 'label+value+percent parent+percent entry',
tiling: {
packing: tilingAlgorithm.value,
},
marker: markerColors,
sort: sortSectorsField === DefaultSortSectors,
},
];
return [mapData, mapLayout];
}, [
queriedVizData,
childField,
valueField,
parentFields,
colorField,
tilingAlgorithm,
layoutConfig,
]);
const mergedConfigs = {
...config,
...(layoutConfig.config && layoutConfig.config),
};
return ;
};