/* * Copyright OpenSearch Contributors * SPDX-License-Identifier: Apache-2.0 */ import React, { useMemo } from 'react'; import { colorPalette } from '@elastic/eui'; import { forEach, isEmpty, map } from 'lodash'; import Plotly from 'plotly.js-dist'; import { HEATMAP_PALETTE_COLOR, HEATMAP_SINGLE_COLOR, OPACITY, SINGLE_COLOR_PALETTE, } from '../../../../../common/constants/colors'; import { hexToRgb, lightenColor, getPropName, } from '../../../../components/event_analytics/utils/utils'; import { IVisualizationContainerProps } from '../../../../../common/types/explorer'; import { Plt } from '../../plotly/plot'; import { AGGREGATIONS, GROUPBY } from '../../../../../common/constants/explorer'; import { PLOT_MARGIN } from '../../../../../common/constants/shared'; import { getCompleteTimespanKey, removeBackTick, } from '../../../visualizations/charts/shared/common'; import { removeBacktick } from '../../../../../common/utils'; export const HeatMap = ({ visualizations, layout, config }: any) => { const { data: { explorer: { explorerData: { jsonData: fieldValueMapList }, }, userConfigs: { dataConfig: { chartStyles = {}, span = {}, legend = {}, tooltipOptions = {}, panelOptions = {}, [GROUPBY]: dimensions = [], [AGGREGATIONS]: series = [], } = {}, layoutConfig = {}, } = {}, } = {}, vis: { icontype }, }: IVisualizationContainerProps = visualizations; const combinedDemensions = [ ...(!isEmpty(span) ? [getCompleteTimespanKey(span)] : []), ...dimensions, ]; const xaxisField = { ...combinedDemensions[0] }; const yaxisField = { ...combinedDemensions[1] }; const zMetrics = { ...series[0] }; const tooltipMode = tooltipOptions.tooltipMode !== undefined ? tooltipOptions.tooltipMode : 'show'; const tooltipText = tooltipOptions.tooltipText !== undefined ? tooltipOptions.tooltipText : 'all'; const colorField = chartStyles ? chartStyles.colorMode && chartStyles.colorMode[0].name === OPACITY ? chartStyles.color ?? HEATMAP_SINGLE_COLOR : chartStyles.scheme ?? HEATMAP_PALETTE_COLOR : HEATMAP_PALETTE_COLOR; const showColorscale = legend.showLegend ?? 'show'; const traceColor: any = []; if (colorField.name === SINGLE_COLOR_PALETTE) { const colorsArray = colorPalette([lightenColor(colorField.color, 50), colorField.color], 10); colorsArray.map((hexCode, index) => { traceColor.push([ (index !== colorsArray.length - 1 ? index : 10) / 10, hexToRgb(hexCode, 1, false), ]); }); } const heatMapAxes = useMemo(() => { const dmaps = new Map(); // key: values of 1st and 2nd group-by fields combined const uniqueXaxisVals = new Set(); // any value for a field const uniqueYaxisVals = new Set(); // any value for a field const zKey = getPropName(zMetrics); forEach(fieldValueMapList, (entry) => { const backtickRemovedEntry = removeBackTick(entry); const xKey = removeBacktick(xaxisField.label); const yKey = removeBacktick(yaxisField.label); // collect unique values from all values of 1st and 2nd group-by fields // for later composing 2 dimensional heatmap x, y axes uniqueXaxisVals.add(backtickRemovedEntry[xKey]); uniqueYaxisVals.add(backtickRemovedEntry[yKey]); // establish 1st,2nd -> data entry mapping for later filling in // corresponding aggregations to 2 dimensional heatmap zaxis dmaps.set( `${backtickRemovedEntry[xKey]},${backtickRemovedEntry[yKey]}`, backtickRemovedEntry ); }); const xAxis = [...uniqueXaxisVals]; const yAxis = [...uniqueYaxisVals]; const zaxis = map(yAxis, (yvalue) => { return map(xAxis, (xvalue) => { return dmaps.get(`${xvalue},${yvalue}`) ? dmaps.get(`${xvalue},${yvalue}`)[zKey] : null; }); }); return { z: zaxis, x: xAxis, y: yAxis, }; }, [fieldValueMapList]); const heapMapData: Plotly.Data[] = [ { ...heatMapAxes, hoverinfo: tooltipMode === 'hidden' ? 'none' : tooltipText, colorscale: colorField.name === SINGLE_COLOR_PALETTE ? traceColor : colorField.name, type: 'heatmap', showscale: showColorscale === 'show', }, ]; layout.yaxis = { autosize: true, automargin: true }; const mergedLayout = { ...layout, ...(layoutConfig.layout && layoutConfig.layout), title: panelOptions.title || layoutConfig.layout?.title || '', margin: PLOT_MARGIN, }; const mergedConfigs = useMemo( () => ({ ...config, ...(layoutConfig.config && layoutConfig.config), }), [config, layoutConfig.config] ); return ; };