Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

Add other changes related to historical workbench #352

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
19 changes: 19 additions & 0 deletions public/models/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ export type Detector = {
stateError: string;
initProgress?: InitProgress;
categoryField?: string[];
detectionDateRange?: DetectionDateRange;
taskId?: string;
taskProgress?: number;
};

export type DetectorListItem = {
Expand All @@ -124,6 +127,16 @@ export type DetectorListItem = {
enabledTime?: number;
};

export type HistoricalDetectorListItem = {
id: string;
name: string;
curState: DETECTOR_STATE;
indices: string[];
totalAnomalies: number;
dataStartTime: number;
dataEndTime: number;
};

export type EntityData = {
name: string;
value: string;
Expand Down Expand Up @@ -179,6 +192,7 @@ export type AnomalySummary = {
anomalyOccurrence: number;
minAnomalyGrade: number;
maxAnomalyGrade: number;
avgAnomalyGrade?: number;
minConfidence: number;
maxConfidence: number;
lastAnomalyOccurrence: string;
Expand All @@ -188,3 +202,8 @@ export type DateRange = {
startDate: number;
endDate: number;
};

export type DetectionDateRange = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think re-using DateRange should be sufficient.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason for adding this DetectionDateRange is because the fields understood by the backend take startTime and endTime fields instead of startDate and endDate fields used by the DateRange. I didn't want to add more converting when parsing existing detectors or creating/updating new detectors. Let me know what you think.

startTime: number;
endTime: number;
};
26 changes: 18 additions & 8 deletions public/pages/AnomalyCharts/containers/AnomaliesChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import {
} from '../utils/constants';
import { AnomalyOccurrenceChart } from './AnomalyOccurrenceChart';
import { FeatureBreakDown } from './FeatureBreakDown';
import { convertTimestampToString } from '../../../utils/utils';

interface AnomaliesChartProps {
onDateRangeChange(
Expand All @@ -65,10 +66,12 @@ interface AnomaliesChartProps {
dateRange: DateRange;
isLoading: boolean;
showAlerts?: boolean;
isNotSample?: boolean;
detector: Detector;
monitor?: Monitor;
children: React.ReactNode | React.ReactNode[];
isHCDetector?: boolean;
isHistorical?: boolean;
detectorCategoryField?: string[];
onHeatmapCellSelected?(heatmapCell: HeatmapCell): void;
selectedHeatmapCell?: HeatmapCell;
Expand All @@ -79,8 +82,12 @@ interface AnomaliesChartProps {

export const AnomaliesChart = React.memo((props: AnomaliesChartProps) => {
const [datePickerRange, setDatePickerRange] = useState({
start: 'now-7d',
end: 'now',
start: props.isHistorical
? convertTimestampToString(props.dateRange.startDate)
: 'now-7d',
end: props.isHistorical
? convertTimestampToString(props.dateRange.endDate)
: 'now',
});

const anomalies = get(props.anomaliesResult, 'anomalies', []);
Expand Down Expand Up @@ -240,20 +247,21 @@ export const AnomaliesChart = React.memo((props: AnomaliesChartProps) => {
anomalySummary={INITIAL_ANOMALY_SUMMARY}
isLoading={props.isLoading}
anomalyGradeSeriesName={getAnomalyGradeWording(
props.showAlerts
props.isNotSample
)}
confidenceSeriesName={getConfidenceWording(
props.showAlerts
props.isNotSample
)}
showAlerts={props.showAlerts}
isNotSample={props.isNotSample}
detector={props.detector}
isHCDetector={props.isHCDetector}
selectedHeatmapCell={props.selectedHeatmapCell}
/>,
<EuiSpacer size="m" />,
<FeatureBreakDown
title={getFeatureBreakdownWording(
props.showAlerts
props.isNotSample
)}
//@ts-ignore
detector={props.newDetector}
Expand All @@ -266,7 +274,7 @@ export const AnomaliesChart = React.memo((props: AnomaliesChartProps) => {
//@ts-ignore
dateRange={props.zoomRange}
featureDataSeriesName={getFeatureDataWording(
props.showAlerts
props.isNotSample
)}
isHCDetector={props.isHCDetector}
selectedHeatmapCell={props.selectedHeatmapCell}
Expand All @@ -287,12 +295,14 @@ export const AnomaliesChart = React.memo((props: AnomaliesChartProps) => {
bucketizedAnomalies={props.bucketizedAnomalies}
anomalySummary={props.anomalySummary}
isLoading={props.isLoading}
anomalyGradeSeriesName={getAnomalyGradeWording(props.showAlerts)}
confidenceSeriesName={getConfidenceWording(props.showAlerts)}
anomalyGradeSeriesName={getAnomalyGradeWording(props.isNotSample)}
confidenceSeriesName={getConfidenceWording(props.isNotSample)}
showAlerts={props.showAlerts}
isNotSample={props.isNotSample}
detector={props.detector}
monitor={props.monitor}
isHCDetector={props.isHCDetector}
isHistorical={props.isHistorical}
onDatePickerRangeChange={handleDatePickerRangeChange}
/>
)}
Expand Down
79 changes: 51 additions & 28 deletions public/pages/AnomalyCharts/containers/AnomalyDetailsChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,13 @@ interface AnomalyDetailsChartProps {
dateRange: DateRange;
isLoading: boolean;
showAlerts?: boolean;
isNotSample?: boolean;
anomalyGradeSeriesName: string;
confidenceSeriesName: string;
detector: Detector;
monitor?: Monitor;
isHCDetector?: boolean;
isHistorical?: boolean;
selectedHeatmapCell?: HeatmapCell;
onDatePickerRangeChange?(startDate: number, endDate: number): void;
}
Expand Down Expand Up @@ -200,7 +202,7 @@ export const AnomalyDetailsChart = React.memo(
<EuiFlexItem>
<EuiStat
title={isLoading ? '-' : anomalySummary.anomalyOccurrence}
description={getAnomalyOccurrenceWording(props.showAlerts)}
description={getAnomalyOccurrenceWording(props.isNotSample)}
titleSize="s"
/>
</EuiFlexItem>
Expand All @@ -209,26 +211,42 @@ export const AnomalyDetailsChart = React.memo(
isLoading={isLoading}
minValue={anomalySummary.minAnomalyGrade}
maxValue={anomalySummary.maxAnomalyGrade}
description={getAnomalyGradeWording(props.showAlerts)}
tooltip="Indicates to what extent this data point is anomalous. The scale ranges from 0 to 1."
/>
</EuiFlexItem>
<EuiFlexItem>
<AnomalyStatWithTooltip
isLoading={isLoading}
minValue={anomalySummary.minConfidence}
maxValue={anomalySummary.maxConfidence}
description={getConfidenceWording(props.showAlerts)}
tooltip="Indicates the level of confidence in the anomaly result."
/>
</EuiFlexItem>
<EuiFlexItem>
<EuiStat
title={isLoading ? '' : anomalySummary.lastAnomalyOccurrence}
description={getLastAnomalyOccurrenceWording(props.showAlerts)}
titleSize="s"
description={getAnomalyGradeWording(props.isNotSample)}
tooltip="Indicates the extent to which a data point is anomalous. Higher grades indicate more unusual data."
/>
</EuiFlexItem>
{
// If historical: only show the average grade, and don't show the confidence or last anomaly occurrence stats
}
{props.isHistorical ? (
<EuiFlexItem>
<EuiStat
title={isLoading ? '-' : anomalySummary.avgAnomalyGrade}
description={'Average anomaly grade'}
titleSize="s"
/>
</EuiFlexItem>
) : null}
{props.isHistorical ? null : (
<EuiFlexItem>
<AnomalyStatWithTooltip
isLoading={isLoading}
minValue={anomalySummary.minConfidence}
maxValue={anomalySummary.maxConfidence}
description={getConfidenceWording(props.isNotSample)}
tooltip="Indicates the level of confidence in the anomaly result."
/>
</EuiFlexItem>
)}
{props.isHistorical ? null : (
<EuiFlexItem>
<EuiStat
title={isLoading ? '' : anomalySummary.lastAnomalyOccurrence}
description={getLastAnomalyOccurrenceWording(props.isNotSample)}
titleSize="s"
/>
</EuiFlexItem>
)}
{props.showAlerts && !props.isHCDetector ? (
<EuiFlexItem>
<AlertsStat
Expand Down Expand Up @@ -326,15 +344,20 @@ export const AnomalyDetailsChart = React.memo(
domain={{ min: 0, max: 1 }}
showGridLines
/>
<LineSeries
id="confidence"
name={props.confidenceSeriesName}
xScaleType={ScaleType.Time}
yScaleType={ScaleType.Linear}
xAccessor={CHART_FIELDS.PLOT_TIME}
yAccessors={[CHART_FIELDS.CONFIDENCE]}
data={zoomedAnomalies}
/>
{
// If historical: don't show the confidence line chart
}
{props.isHistorical ? null : (
<LineSeries
id="confidence"
name={props.confidenceSeriesName}
xScaleType={ScaleType.Time}
yScaleType={ScaleType.Linear}
xAccessor={CHART_FIELDS.PLOT_TIME}
yAccessors={[CHART_FIELDS.CONFIDENCE]}
data={zoomedAnomalies}
/>
)}
<LineSeries
id="anomalyGrade"
name={props.anomalyGradeSeriesName}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ export const AnomalyHeatmapChart = React.memo(
<EuiText size="xs" style={{ margin: '0px' }}>
Anomaly grade{' '}
<EuiIconTip
content="Indicates to what extent this data point is anomalous. The scale ranges from 0 to 1."
content="Indicates the extent to which a data point is anomalous. Higher grades indicate more unusual data."
position="top"
type="iInCircle"
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ interface AnomalyOccurrenceChartProps {
dateRange: DateRange;
isLoading: boolean;
showAlerts?: boolean;
isNotSample?: boolean;
anomalyGradeSeriesName: string;
confidenceSeriesName: string;
detector: Detector;
Expand Down Expand Up @@ -94,6 +95,7 @@ export const AnomalyOccurrenceChart = React.memo(
anomalyGradeSeriesName={props.anomalyGradeSeriesName}
confidenceSeriesName={props.confidenceSeriesName}
showAlerts={props.showAlerts}
isNotSample={props.isNotSample}
detector={props.detector}
monitor={props.monitor}
isHCDetector={props.isHCDetector}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
* permissions and limitations under the License.
*/

//@ts-ignore
//@ts-ignore
import moment from 'moment';
import { getAnomalySummary } from '../anomalyChartUtils';

Expand Down Expand Up @@ -48,6 +48,7 @@ describe('anomalyChartUtils', () => {
anomalyOccurrence: 3,
minAnomalyGrade: 0.1,
maxAnomalyGrade: 0.7,
avgAnomalyGrade: 0.4,
minConfidence: 0.86,
maxConfidence: 0.98,
lastAnomalyOccurrence: moment(1589313164793).format('MM/DD/YY hh:mm A'),
Expand Down
36 changes: 18 additions & 18 deletions public/pages/AnomalyCharts/utils/anomalyChartUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { Datum, PlotData } from 'plotly.js';
import moment from 'moment';
import { calculateTimeWindowsWithMaxDataPoints } from '../../utils/anomalyResultUtils';
import { HeatmapCell } from '../containers/AnomalyHeatmapChart';
import { toFixedNumberForAnomaly } from '../../../../server/utils/helpers';

export const convertAlerts = (response: any): MonitorAlert[] => {
const alerts = get(response, 'response.alerts', []);
Expand Down Expand Up @@ -73,31 +74,29 @@ const findLatestAnomaly = (anomalies: any[]) => {
return latestAnomaly;
};

const getAverageAnomalyGrade = (anomalyGrades: any[]) => {
return anomalyGrades.length > 0
? toFixedNumberForAnomaly(
anomalyGrades.reduce((prevGrade, curGrade) => prevGrade + curGrade, 0) /
anomalyGrades.length
)
: 0;
};

export const getAnomalySummary = (totalAnomalies: any[]): AnomalySummary => {
if (totalAnomalies == undefined || totalAnomalies.length === 0) {
return DEFAULT_ANOMALY_SUMMARY;
}
const anomalies = totalAnomalies.filter(
(anomaly) => anomaly.anomalyGrade > 0
);
const maxConfidence = Math.max(
...anomalies.map((anomaly) => anomaly.confidence),
0.0
);
const minConfidence = Math.min(
...anomalies.map((anomaly) => anomaly.confidence),
1.0
);

const maxAnomalyGrade = Math.max(
...anomalies.map((anomaly) => anomaly.anomalyGrade),
0.0
);
const minAnomalyGrade = Math.min(
...anomalies.map((anomaly) => anomaly.anomalyGrade),
1.0
);

const anomalyGrades = anomalies.map((anomaly) => anomaly.anomalyGrade);
const anomalyConfidences = anomalies.map((anomaly) => anomaly.confidence);
const maxConfidence = Math.max(...anomalyConfidences, 0.0);
const minConfidence = Math.min(...anomalyConfidences, 1.0);
const maxAnomalyGrade = Math.max(...anomalyGrades, 0.0);
const minAnomalyGrade = Math.min(...anomalyGrades, 1.0);
const avgAnomalyGrade = getAverageAnomalyGrade(anomalyGrades);
const lastAnomalyOccurrence =
anomalies.length > 0
? minuteDateFormatter(findLatestAnomaly(anomalies).endTime)
Expand All @@ -107,6 +106,7 @@ export const getAnomalySummary = (totalAnomalies: any[]): AnomalySummary => {
anomalyOccurrence: anomalies.length,
minAnomalyGrade: minAnomalyGrade > maxAnomalyGrade ? 0 : minAnomalyGrade,
maxAnomalyGrade: maxAnomalyGrade,
avgAnomalyGrade: avgAnomalyGrade,
minConfidence: minConfidence > maxConfidence ? 0 : minConfidence,
maxConfidence: maxConfidence,
lastAnomalyOccurrence: lastAnomalyOccurrence,
Expand Down
4 changes: 2 additions & 2 deletions public/pages/Dashboard/Components/AnomaliesDistribution.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,8 @@ export const AnomaliesDistributionChart = (
<EuiFlexItem>
<EuiText className={'anomaly-distribution-subtitle'}>
<p>
{'The inner circle shows the anomaly distribution by your indices. ' +
'The outer circle shows the anomaly distribution by your detectors.'}
{'The inner circle shows anomaly distribution by index. ' +
'The outer circle shows distribution by detector.'}
</p>
</EuiText>
</EuiFlexItem>
Expand Down
6 changes: 2 additions & 4 deletions public/pages/Dashboard/Components/AnomaliesLiveChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,7 @@ import {
} from '@elastic/charts';
import { EuiText, EuiTitle } from '@elastic/eui';
import React from 'react';
import {
TIME_NOW_LINE_STYLE
} from '../utils/constants';
import { TIME_NOW_LINE_STYLE } from '../utils/constants';
import { SHOW_DECIMAL_NUMBER_THRESHOLD } from '../../../../server/utils/helpers';
import {
visualizeAnomalyResultForXYChart,
Expand Down Expand Up @@ -278,7 +276,7 @@ export const AnomaliesLiveChart = (props: AnomaliesLiveChartProps) => {
</EuiFlexItem>
<EuiFlexItem style={{ minWidth: '310px' }}>
<EuiStat
description={'Detector with most recent anomaly occurrence'}
description={'Detector with the most recent anomaly'}
title={
lastAnomalyResult === undefined
? '-'
Expand Down
4 changes: 2 additions & 2 deletions public/pages/Dashboard/Container/DashboardOverview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import { AppState } from '../../../redux/reducers';
import { CatIndex, IndexAlias } from '../../../../server/models/types';
import { getVisibleOptions } from '../../utils/helpers';
import { BREADCRUMBS } from '../../../utils/constants';
import { DETECTOR_STATE } from '../../../../server/utils/constants'
import { DETECTOR_STATE } from '../../../../server/utils/constants';
import { getDetectorStateOptions } from '../../DetectorsList/utils/helpers';
import { DashboardHeader } from '../Components/utils/DashboardHeader';
import { EmptyDashboard } from '../Components/EmptyDashboard/EmptyDashboard';
Expand Down Expand Up @@ -186,7 +186,7 @@ export function DashboardOverview() {
typeof errorGettingDetectors === 'string' &&
errorGettingDetectors.includes(NO_PERMISSIONS_KEY_WORD)
? prettifyErrorMessage(errorGettingDetectors)
: 'Unable to get all detectors.'
: 'Unable to get all detectors'
);
setIsLoadingDetectors(false);
}
Expand Down
Loading