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

Explorer empty bucket #990

Merged
merged 10 commits into from
Sep 13, 2023
20 changes: 20 additions & 0 deletions common/types/explorer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -381,3 +381,23 @@ export interface VisSpecificMetaData {
x_coordinate: string;
y_coordinate: string;
}

export type MOMENT_UNIT_OF_TIME =
| 'years'
| 'y'
| 'quarters'
| 'Q'
| 'months'
| 'M'
| 'weeks'
| 'w'
| 'days'
| 'd'
| 'hours'
| 'h'
| 'minutes'
| 'm'
| 'seconds'
| 's'
| 'milliseconds'
| 'ms';
7 changes: 6 additions & 1 deletion public/components/event_analytics/explorer/explorer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,12 @@ export const Explorer = ({
startTime={appLogEvents ? startTime : dateRange[0]}
endTime={appLogEvents ? endTime : dateRange[1]}
/>
<CountDistribution countDistribution={countDistribution} />
<CountDistribution
countDistribution={countDistribution}
selectedInterval={selectedIntervalRef.current?.value}
startTime={appLogEvents ? startTime : dateRange[0]}
endTime={appLogEvents ? endTime : dateRange[1]}
/>
<EuiHorizontalRule margin="xs" />
<LogPatterns
selectedIntervalUnit={selectedIntervalRef.current}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,134 +44,7 @@ exports[`Count distribution component Renders count distribution component with
},
}
}
>
<Plt
data={
Array [
Object {
"name": Object {
"name": "count()",
"type": "integer",
},
"orientation": "v",
"type": "bar",
"x": Array [
"2021-05-01 00:00:00",
"2021-06-01 00:00:00",
"2021-07-01 00:00:00",
],
"y": Array [
2549,
9337,
1173,
],
},
]
}
layout={
Object {
"colorway": Array [
"#8C55A3",
],
"height": 220,
"margin": Object {
"b": 15,
"l": 60,
"pad": 0,
"r": 10,
"t": 30,
},
"showlegend": true,
}
}
>
<PlotlyComponent
config={
Object {
"displayModeBar": false,
}
}
data={
Array [
Object {
"name": Object {
"name": "count()",
"type": "integer",
},
"orientation": "v",
"type": "bar",
"x": Array [
"2021-05-01 00:00:00",
"2021-06-01 00:00:00",
"2021-07-01 00:00:00",
],
"y": Array [
2549,
9337,
1173,
],
},
]
}
debug={false}
divId="explorerPlotComponent"
layout={
Object {
"autosize": true,
"barmode": "stack",
"colorway": Array [
"#8C55A3",
],
"height": 220,
"hovermode": "closest",
"legend": Object {
"orientation": "h",
"traceorder": "normal",
},
"margin": Object {
"b": 15,
"l": 60,
"pad": 0,
"r": 10,
"t": 30,
},
"showlegend": true,
"xaxis": Object {
"automargin": true,
"rangemode": "normal",
"showgrid": true,
"zeroline": false,
},
"yaxis": Object {
"rangemode": "normal",
"showgrid": true,
"title": Object {
"text": "Count",
},
"zeroline": false,
},
}
}
style={
Object {
"height": "100%",
"width": "100%",
}
}
useResizeHandler={true}
>
<div
id="explorerPlotComponent"
style={
Object {
"height": "100%",
"width": "100%",
}
}
/>
</PlotlyComponent>
</Plt>
</Component>
/>
`;

exports[`Count distribution component Renders empty count distribution component 1`] = `<Component />`;
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,20 @@
import React from 'react';
import { BarOrientation, LONG_CHART_COLOR } from '../../../../../../common/constants/shared';
import { Plt } from '../../../../visualizations/plotly/plot';
import { fillTimeDataWithEmpty } from '../../../utils/utils';

export const CountDistribution = ({ countDistribution }: any) => {
export const CountDistribution = ({
countDistribution,
selectedInterval,
startTime,
endTime,
}: any) => {
if (
!countDistribution ||
!countDistribution.data ||
!countDistribution.metadata ||
!countDistribution.metadata.fields
!countDistribution.metadata.fields ||
!selectedInterval
)
return null;

Expand All @@ -31,9 +38,31 @@ export const CountDistribution = ({ countDistribution }: any) => {
},
];

// fill the final data with the exact right amount of empty buckets
function fillWithEmpty(processedData: any) {
paulstn marked this conversation as resolved.
Show resolved Hide resolved
// original x and y fields
const xVals = processedData[0].x;
const yVals = processedData[0].y;

const { buckets, values } = fillTimeDataWithEmpty(
xVals,
yVals,
selectedInterval.replace(/^auto_/, ''),
startTime,
endTime
);

// replace old x and y values with new
processedData[0].x = buckets;
processedData[0].y = values;

// // at the end, return the new object
return processedData;
}

return (
<Plt
data={finalData}
data={fillWithEmpty(finalData)}
layout={{
showlegend: true,
margin: {
Expand Down
66 changes: 66 additions & 0 deletions public/components/event_analytics/utils/__tests__/utils.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
isValidTraceId,
rangeNumDocs,
getHeaders,
fillTimeDataWithEmpty,
} from '../utils';

describe('Utils event analytics helper functions', () => {
Expand Down Expand Up @@ -80,4 +81,69 @@ describe('Utils event analytics helper functions', () => {
).toBeTruthy();
expect(getHeaders([], ['', 'Time', '_source'], undefined)).toBeTruthy();
});

it('validates fillTimeDataWithEmpty function', () => {
expect(
fillTimeDataWithEmpty(
['2023-07-01 00:00:00', '2023-08-01 00:00:00', '2023-09-01 00:00:00'],
[54, 802, 292],
'M',
'2023-01-01T08:00:00.000Z',
'2023-09-12T21:36:31.389Z'
)
).toEqual({
buckets: [
'2023-01-01 00:00:00',
'2023-02-01 00:00:00',
'2023-03-01 00:00:00',
'2023-04-01 00:00:00',
'2023-05-01 00:00:00',
'2023-06-01 00:00:00',
'2023-07-01 00:00:00',
'2023-08-01 00:00:00',
'2023-09-01 00:00:00',
],
values: [0, 0, 0, 0, 0, 0, 54, 802, 292],
});
expect(
fillTimeDataWithEmpty(
[
'2023-09-11 07:00:00',
'2023-09-11 09:00:00',
'2023-09-11 10:00:00',
'2023-09-11 11:00:00',
'2023-09-11 12:00:00',
'2023-09-11 13:00:00',
'2023-09-11 14:00:00',
'2023-09-11 15:00:00',
],
[1, 1, 5, 4, 2, 3, 3, 1],
'h',
'2023-09-11T00:00:00.000',
'2023-09-11T17:00:00.000'
)
).toEqual({
buckets: [
'2023-09-11 00:00:00',
'2023-09-11 01:00:00',
'2023-09-11 02:00:00',
'2023-09-11 03:00:00',
'2023-09-11 04:00:00',
'2023-09-11 05:00:00',
'2023-09-11 06:00:00',
'2023-09-11 07:00:00',
'2023-09-11 08:00:00',
'2023-09-11 09:00:00',
'2023-09-11 10:00:00',
'2023-09-11 11:00:00',
'2023-09-11 12:00:00',
'2023-09-11 13:00:00',
'2023-09-11 14:00:00',
'2023-09-11 15:00:00',
'2023-09-11 16:00:00',
'2023-09-11 17:00:00',
],
values: [0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 5, 4, 2, 3, 3, 1, 0, 0],
});
});
});
58 changes: 57 additions & 1 deletion public/components/event_analytics/utils/utils.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
/* eslint-disable no-bitwise */
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

/* eslint-disable no-bitwise */

import { uniqueId, isEmpty } from 'lodash';
import moment from 'moment';
import React from 'react';
import { EuiText } from '@elastic/eui';
import datemath from '@elastic/datemath';
import { HttpStart } from '../../../../../../src/core/public';
import {
CUSTOM_LABEL,
TIME_INTERVAL_OPTIONS,
GROUPBY,
AGGREGATIONS,
BREAKDOWNS,
DATE_PICKER_FORMAT,
} from '../../../../common/constants/explorer';
import { PPL_DATE_FORMAT, PPL_INDEX_REGEX } from '../../../../common/constants/shared';
import {
Expand All @@ -23,6 +26,7 @@ import {
IExplorerFields,
IField,
IQuery,
MOMENT_UNIT_OF_TIME,
} from '../../../../common/types/explorer';
import PPLService from '../../../services/requests/ppl';
import { DocViewRow, IDocType } from '../explorer/events_views';
Expand Down Expand Up @@ -459,3 +463,55 @@ export const getContentTabTitle = (tabID: string, tabTitle: string) => {
</>
);
};

/**
* Used to fill in missing empty data where x is an array of time values and there are only x
* values when y is non-zero.
* @param xVals all x values being used
* @param yVals all y values being used
* @param intervalPeriod Moment unitOfTime used to dictate how long each interval is
* @param startTime starting time of x values
* @param endTime ending time of x values
* @returns an object with buckets and values where the buckets are all of the new x values and
* values are the corresponding values which include y values that are 0 for empty data
*/
export const fillTimeDataWithEmpty = (
xVals: string[],
yVals: number[],
intervalPeriod: MOMENT_UNIT_OF_TIME,
startTime: string,
endTime: string
): { buckets: string[]; values: number[] } => {
// parses out datetime for start and end, then reformats
const startDate = datemath
.parse(startTime)
?.startOf(intervalPeriod === 'w' ? 'isoWeek' : intervalPeriod);
const endDate = datemath
.parse(endTime)
?.startOf(intervalPeriod === 'w' ? 'isoWeek' : intervalPeriod);

// find the number of buckets
// below essentially does ((end - start) / interval_period) + 1
const numBuckets = endDate.diff(startDate, intervalPeriod) + 1;

// populate buckets as x values in the graph
const buckets = [startDate.format(DATE_PICKER_FORMAT)];
const currentDate = startDate;
for (let i = 1; i < numBuckets; i++) {
const nextBucket = currentDate.add(1, intervalPeriod);
buckets.push(nextBucket.format(DATE_PICKER_FORMAT));
}

// create y values, use old y values if they exist
const values: number[] = [];
buckets.forEach((bucket) => {
const bucketIndex = xVals.findIndex((x: string) => x === bucket);
if (bucketIndex !== -1) {
values.push(yVals[bucketIndex]);
} else {
values.push(0);
}
});

return { buckets, values };
};