renderOverview_()

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
      }));
    });
  }