in tensorflow_model_analysis/frontend/tfma-metrics-histogram/tfma-metrics-histogram.js [328:431]
renderOverview_() {
const svg = d3.select(this.$[ElementId.OVERVIEW]);
const width = this.getOverviewWidth_();
const svgNode = svg.node();
svgNode.setAttribute('width', width);
svgNode.setAttribute(
'height', OVERVIEW_HEIGHT_PX * (this.type == Type.BOTH ? 2 : 1));
svgNode.style.marginLeft = OVERVIEW_MARGIN_LEFT_PX + 'px';
const height = OVERVIEW_HEIGHT_PX;
const range = this.data.getColumnRange(this.metric);
const plotData = this.prepareHistogram_(
this.data, OVERVIEW_NUM_BUCKETS, range.min, range.max);
const dataTableArray = plotData.dataTableArray;
const unweightedSvg = svg.select('.' + Type.UNWEIGHTED);
const weightedSvg = svg.select('.' + Type.WEIGHTED);
// Clear the previous drawing.
unweightedSvg.selectAll('*').remove();
weightedSvg.selectAll('*').remove();
if (this.type != Type.WEIGHTED) {
this.drawOverview_(
unweightedSvg, dataTableArray.map((row) => {
return [row[0], row[1]];
}),
getDataTableColumnRange(dataTableArray, 1));
}
if (this.type != Type.UNWEIGHTED) {
this.drawOverview_(
weightedSvg, dataTableArray.map((row) => {
return [row[0], row[2]];
}),
getDataTableColumnRange(dataTableArray, 2));
}
unweightedSvg.select('path').attr('class', 'blue');
weightedSvg.select('path').attr(
'class', this.type == Type.BOTH ? 'red' : 'blue');
if (this.type == Type.BOTH) {
weightedSvg.attr('transform', 'translate(0,' + height + ')');
}
this.drawOverviewFocus_(this.focusRange[0], this.focusRange[1]);
let dragRange = [];
const drag = d3.drag();
let focusLeft;
let focusRight;
/**
* Retrieves the beginning and ending positions of the mouse drag, and
* computes the corresponding focus range coordinates on the histogram
* overview.
* @this {!Element}
*/
const dragHandler = () => {
const x = d3.mouse(/** @type {!Element} */ (svg.node()))[0];
if (dragRange[0] == undefined) {
dragRange[0] = x;
} else {
dragRange[1] = x;
focusLeft = Math.max(0, Math.min(dragRange[0], dragRange[1]) / width);
focusRight = Math.min(1, Math.max(dragRange[0], dragRange[1]) / width);
this.drawOverviewFocus_(focusLeft, focusRight);
if (this.realTimeFocus) {
// Updating this.focusRange will immediately update
// detailsData and visualization because of data binding.
this.updateFocusRange(focusLeft, focusRight);
}
}
};
/**
* Resets the drag range to empty range when the mouse drag is released.
* @this {!Element}
*/
const dragendHandler = () => {
if (dragRange[0] == undefined || dragRange[1] == undefined) {
// Mouse did not move.
return;
}
this.updateFocusRange(focusLeft, focusRight);
dragRange = [];
this.dispatchEvent(new CustomEvent(tfma.Event.UPDATE_FOCUS_RANGE, {
detail: {'focusLeft': focusLeft, 'focusRight': focusRight},
bubbles: true,
composed: true
}));
};
drag.on('drag', dragHandler).on('end', dragendHandler);
svg.call(drag);
svg.on(tfma.Event.DOUBLE_CLICK, () => {
this.resetFocusRange_();
this.dispatchEvent(new CustomEvent(tfma.Event.UPDATE_FOCUS_RANGE, {
detail: {'focusLeft': 0, 'focusRight': 1},
bubbles: true,
composed: true
}));
});
}