New perf dashboard shows too much space around interesting data points
authorrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 11 Feb 2015 22:56:31 +0000 (22:56 +0000)
committerrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 11 Feb 2015 22:56:31 +0000 (22:56 +0000)
https://bugs.webkit.org/show_bug.cgi?id=141487

Reviewed by Chris Dumez.

Revise the y-axis range adjustment algorithm in r179913. Instead of showing the entire moving average,
show the current time series excluding points in the series outside the moving average envelope.

* public/v2/app.js:
(App.Pane._computeChartData): Don't deal with missing moving average or enveloping strategy here.
(App.Pane._computeMovingAverageAndOutliers): Set isOutliner to true on all data points in the current
time series if the point lies outside the moving average envelope. Don't expose the moving average or
the envelope computed for this purpose if they're not set by the user.

* public/v2/data.js:
(TimeSeries.prototype.minMaxForTimeRange): Takes a boolean argument, ignoreOutlier. When the flag is set
to true, min/max computation will ignore any point in the series with non-falsy "isOutliner" property.

* public/v2/interactive-chart.js:
(App.InteractiveChartComponent._constructGraphIfPossible): Unsupport hideMovingAverage and hideEnvelope.
(App.InteractiveChartComponent._computeYAxisDomain): Removed the commented out code. Also moved the code
to deal with showFullYAxis here.
(App.InteractiveChartComponent._minMaxForAllTimeSeries): Rewrote the code. Takes ignoreOutliners as an
argument instead of directly inspecting showFullYAxis.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@179965 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Websites/perf.webkit.org/ChangeLog
Websites/perf.webkit.org/public/v2/app.js
Websites/perf.webkit.org/public/v2/data.js
Websites/perf.webkit.org/public/v2/interactive-chart.js

index 3990430a9cb1d9956bbe92a915e919d84f441f4d..9a46307c6460afc7535d1e8382b36b88090d6814 100644 (file)
@@ -1,3 +1,30 @@
+2015-02-11  Ryosuke Niwa  <rniwa@webkit.org>
+
+        New perf dashboard shows too much space around interesting data points
+        https://bugs.webkit.org/show_bug.cgi?id=141487
+
+        Reviewed by Chris Dumez.
+
+        Revise the y-axis range adjustment algorithm in r179913. Instead of showing the entire moving average,
+        show the current time series excluding points in the series outside the moving average envelope.
+
+        * public/v2/app.js:
+        (App.Pane._computeChartData): Don't deal with missing moving average or enveloping strategy here.
+        (App.Pane._computeMovingAverageAndOutliers): Set isOutliner to true on all data points in the current
+        time series if the point lies outside the moving average envelope. Don't expose the moving average or
+        the envelope computed for this purpose if they're not set by the user.
+
+        * public/v2/data.js:
+        (TimeSeries.prototype.minMaxForTimeRange): Takes a boolean argument, ignoreOutlier. When the flag is set
+        to true, min/max computation will ignore any point in the series with non-falsy "isOutliner" property.
+
+        * public/v2/interactive-chart.js:
+        (App.InteractiveChartComponent._constructGraphIfPossible): Unsupport hideMovingAverage and hideEnvelope.
+        (App.InteractiveChartComponent._computeYAxisDomain): Removed the commented out code. Also moved the code
+        to deal with showFullYAxis here.
+        (App.InteractiveChartComponent._minMaxForAllTimeSeries): Rewrote the code. Takes ignoreOutliners as an
+        argument instead of directly inspecting showFullYAxis.
+
 2015-02-10  Ryosuke Niwa  <rniwa@webkit.org>
 
         New perf dashboard shouldn't always show outliners
index f80e5e4a0ffdbccd6447241e01e4b9081d5c8c5d..4b065ad7fda918732656f882a7d9054a11853e51 100755 (executable)
@@ -484,38 +484,44 @@ App.Pane = Ember.Object.extend({
         var envelopingStrategy = this.get('chosenEnvelopingStrategy');
         this._updateStrategyConfigIfNeeded(envelopingStrategy, 'envelopingConfig');
 
-        if (!movingAverageStrategy || !movingAverageStrategy.execute) {
-            movingAverageStrategy = Statistics.MovingAverageStrategies[0];
-            chartData.hideMovingAverage = true;
-        }
-        if (!envelopingStrategy || !envelopingStrategy.execute) {
-            envelopingStrategy = Statistics.EnvelopingStrategies[0];
-            chartData.hideEnvelope = true;
-        }
-
-        chartData.movingAverage = this._computeMovingAverage(chartData, movingAverageStrategy, envelopingStrategy);
+        chartData.movingAverage = this._computeMovingAverageAndOutliers(chartData, movingAverageStrategy, envelopingStrategy);
 
         this.set('chartData', chartData);
     }.observes('chosenMovingAverageStrategy', 'chosenMovingAverageStrategy.parameterList.@each.value',
         'chosenEnvelopingStrategy', 'chosenEnvelopingStrategy.parameterList.@each.value'),
-    _computeMovingAverage: function (chartData, movingAverageStrategy, envelopingStrategy)
+    _computeMovingAverageAndOutliers: function (chartData, movingAverageStrategy, envelopingStrategy)
     {
         var currentTimeSeriesData = chartData.current.series();
-        var movingAverageValues = this._executeStrategy(movingAverageStrategy, currentTimeSeriesData);
+        var movingAverageIsSetByUser = movingAverageStrategy && movingAverageStrategy.execute;
+        var movingAverageValues = this._executeStrategy(
+            movingAverageIsSetByUser ? movingAverageStrategy : Statistics.MovingAverageStrategies[0], currentTimeSeriesData);
         if (!movingAverageValues)
             return null;
 
-        var envelopeDelta = this._executeStrategy(envelopingStrategy, currentTimeSeriesData, [movingAverageValues]);
+        var envelopeIsSetByUser = envelopingStrategy && envelopingStrategy.execute;
+        var envelopeDelta = this._executeStrategy(envelopeIsSetByUser ? envelopingStrategy : Statistics.EnvelopingStrategies[0],
+            currentTimeSeriesData, [movingAverageValues]);
 
-        return new TimeSeries(currentTimeSeriesData.map(function (point, index) {
-            var value = movingAverageValues[index];
-            return {
-                measurement: point.measurement,
-                time: point.time,
-                value: value,
-                interval: envelopeDelta !== null ? [value - envelopeDelta, value + envelopeDelta] : null,
-            }
-        }));
+        for (var i = 0; i < currentTimeSeriesData.length; i++) {
+            var currentValue = currentTimeSeriesData[i].value;
+            var movingAverageValue = movingAverageValues[i];
+            if (currentValue < movingAverageValue - envelopeDelta || movingAverageValue + envelopeDelta < currentValue)
+                currentTimeSeriesData[i].isOutlier = true;
+        }
+        if (!envelopeIsSetByUser)
+            envelopeDelta = null;
+
+        if (movingAverageIsSetByUser) {
+            return new TimeSeries(currentTimeSeriesData.map(function (point, index) {
+                var value = movingAverageValues[index];
+                return {
+                    measurement: point.measurement,
+                    time: point.time,
+                    value: value,
+                    interval: envelopeDelta !== null ? [value - envelopeDelta, value + envelopeDelta] : null,
+                }
+            }));            
+        }
     },
     _executeStrategy: function (strategy, currentTimeSeriesData, additionalArguments)
     {
index dfe3133d323746e1130835086753d4d782761a1b..208575e92ff3b14aff7bc8526461570f4a629f6c 100755 (executable)
@@ -372,7 +372,7 @@ TimeSeries.prototype.seriesBetweenPoints = function (startPoint, endPoint)
     return this._series.slice(startPoint.seriesIndex, endPoint.seriesIndex + 1);
 }
 
-TimeSeries.prototype.minMaxForTimeRange = function (startTime, endTime)
+TimeSeries.prototype.minMaxForTimeRange = function (startTime, endTime, ignoreOutlier)
 {
     var data = this._series;
     var i = 0;
@@ -389,6 +389,8 @@ TimeSeries.prototype.minMaxForTimeRange = function (startTime, endTime)
     var max = Number.MIN_VALUE;
     for (; i < data.length; i++) {
         var point = data[i];
+        if (point.isOutlier && ignoreOutlier)
+            continue;
         var currentMin = point.interval ? point.interval[0] : point.value;
         var currentMax = point.interval ? point.interval[1] : point.value;
 
index 68871697592d86f201920286e3f70c6866fa1ab9..1b65626a186786881e699400f3f454863f53ba1e 100644 (file)
@@ -128,7 +128,7 @@ App.InteractiveChartComponent = Ember.Component.extend({
                 .attr("class", "target"));
         }
 
-        var movingAverageIsVisible = this._movingAverageTimeSeries && !chartData.hideMovingAverage;
+        var movingAverageIsVisible = this._movingAverageTimeSeries;
         var foregroundClass = movingAverageIsVisible ? '' : ' foreground';
         this._areas.push(this._clippedContainer
             .append("path")
@@ -153,12 +153,10 @@ App.InteractiveChartComponent = Ember.Component.extend({
                 .datum(this._movingAverageTimeSeries.series())
                 .attr("class", "movingAverage"));
 
-            if (!chartData.hideEnvelope) {
-                this._areas.push(this._clippedContainer
-                    .append("path")
-                    .datum(this._movingAverageTimeSeries.series())
-                    .attr("class", "envelope"));
-            }
+            this._areas.push(this._clippedContainer
+                .append("path")
+                .datum(this._movingAverageTimeSeries.series())
+                .attr("class", "envelope"));
         }
 
         if (isInteractive) {
@@ -336,33 +334,33 @@ App.InteractiveChartComponent = Ember.Component.extend({
     },
     _computeYAxisDomain: function (startTime, endTime)
     {
-        var range = this._minMaxForAllTimeSeries(startTime, endTime);
+        var shouldShowFullYAxis = this.get('showFullYAxis');
+        var range = this._minMaxForAllTimeSeries(startTime, endTime, !shouldShowFullYAxis);
         var min = range[0];
         var max = range[1];
         if (max < min)
             min = max = 0;
+        else if (shouldShowFullYAxis)
+            min = Math.min(min, 0);
         var diff = max - min;
         var margin = diff * 0.05;
 
         yExtent = [min - margin, max + margin];
-//        if (yMin !== undefined)
-//            yExtent[0] = parseInt(yMin);
         return yExtent;
     },
-    _minMaxForAllTimeSeries: function (startTime, endTime)
+    _minMaxForAllTimeSeries: function (startTime, endTime, ignoreOutliners)
     {
-        var shouldShowFullYAxis = this.get('showFullYAxis');
-        var mainTimeSeries = this._movingAverageTimeSeries && !shouldShowFullYAxis ? this._movingAverageTimeSeries : this._currentTimeSeries;
-        var currentRange = mainTimeSeries.minMaxForTimeRange(startTime, endTime);
-        if (shouldShowFullYAxis)
-            currentRange[0] = Math.min(0, currentRange[0]);
-
-        var baselineRange = this._baselineTimeSeries ? this._baselineTimeSeries.minMaxForTimeRange(startTime, endTime) : [Number.MAX_VALUE, Number.MIN_VALUE];
-        var targetRange = this._targetTimeSeries ? this._targetTimeSeries.minMaxForTimeRange(startTime, endTime) : [Number.MAX_VALUE, Number.MIN_VALUE];
-        return [
-            Math.min(currentRange[0], baselineRange[0], targetRange[0]),
-            Math.max(currentRange[1], baselineRange[1], targetRange[1]),
-        ];
+        var seriesList = [this._currentTimeSeries, this._movingAverageTimeSeries, this._baselineTimeSeries, this._targetTimeSeries];
+        var min = Infinity;
+        var max = -Infinity;
+        for (var i = 0; i < seriesList.length; i++) {
+            if (seriesList[i]) {
+                var minMax = seriesList[i].minMaxForTimeRange(startTime, endTime, ignoreOutliners);
+                min = Math.min(min, minMax[0]);
+                max = Math.max(max, minMax[1]);
+            }
+        }
+        return [min, max];
     },
     _currentSelection: function ()
     {