Skip to content

Commit

Permalink
[ML] Extend population preview chart to show actual and typical value (
Browse files Browse the repository at this point in the history
…elastic#67569)

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
  • Loading branch information
qn895 and elasticmachine committed Jun 4, 2020
1 parent 2ca71b1 commit 31cd163
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
getTickValues,
numTicksForDateFormat,
removeLabelOverlap,
chartExtendedLimits,
} from '../../util/chart_utils';
import { LoadingIndicator } from '../../components/loading_indicator/loading_indicator';
import { getTimeBucketsFromCache } from '../../util/time_buckets';
Expand Down Expand Up @@ -98,7 +99,7 @@ export class ExplorerChartDistribution extends React.Component {
const filteredChartData = init(config);
drawRareChart(filteredChartData);

function init({ chartData }) {
function init({ chartData, functionDescription }) {
const $el = $('.ml-explorer-chart');

// Clear any existing elements from the visualization,
Expand Down Expand Up @@ -137,22 +138,24 @@ export class ExplorerChartDistribution extends React.Component {
});

if (chartType === CHART_TYPE.POPULATION_DISTRIBUTION) {
const focusData = chartData
.filter((d) => {
return d.entity === highlight;
})
.map((d) => d.value);
const focusExtent = d3.extent(focusData);

const focusData = chartData.filter((d) => {
return d.entity === highlight;
});
// calculate the max y domain based on value, typical, and actual
// also sets the min to be at least 0 if the series function type is `count`
const { min: yScaleDomainMin, max: yScaleDomainMax } = chartExtendedLimits(
focusData,
functionDescription
);
// now again filter chartData to include only the data points within the domain
chartData = chartData.filter((d) => {
return d.value <= focusExtent[1];
return d.value <= yScaleDomainMax;
});

lineChartYScale = d3.scale
.linear()
.range([chartHeight, 0])
.domain([0, focusExtent[1]])
.domain([yScaleDomainMin < 0 ? yScaleDomainMin : 0, yScaleDomainMax])
.nice();
} else if (chartType === CHART_TYPE.EVENT_DISTRIBUTION) {
// avoid overflowing the border of the highlighted area
Expand Down
38 changes: 38 additions & 0 deletions x-pack/plugins/ml/public/application/util/chart_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,44 @@ export function chartLimits(data = []) {
return limits;
}

export function chartExtendedLimits(data = [], functionDescription) {
let _min = Infinity;
let _max = -Infinity;
data.forEach((d) => {
let metricValue = d.value;
const actualValue = Array.isArray(d.actual) ? d.actual[0] : d.actual;
const typicalValue = Array.isArray(d.typical) ? d.typical[0] : d.typical;

if (metricValue === null && d.anomalyScore !== undefined && d.actual !== undefined) {
// If an anomaly coincides with a gap in the data, use the anomaly actual value.
metricValue = actualValue;
}

if (d.anomalyScore !== undefined) {
_min = Math.min(_min, metricValue, actualValue, typicalValue);
_max = Math.max(_max, metricValue, actualValue, typicalValue);
} else {
_min = Math.min(_min, metricValue);
_max = Math.max(_max, metricValue);
}
});
const limits = { max: _max, min: _min };

// add padding of 5% of the difference between max and min
// if we ended up with the same value for both of them
if (limits.max === limits.min) {
const padding = limits.max * 0.05;
limits.max += padding;
limits.min -= padding;
}

// makes sure the domain starts at 0 if the aggregation is by count
// since the number should always be positive
if (functionDescription === 'count' && limits.min < 0) {
limits.min = 0;
}
return limits;
}
export function drawLineChartDots(data, lineChartGroup, lineChartValuesLine, radius = 1.5) {
// We need to do this because when creating a line for a chart which has data gaps,
// if there are single datapoints without any valid data before and after them,
Expand Down

0 comments on commit 31cd163

Please sign in to comment.