aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Dandelion Mané <dandelion@google.com>2017-03-16 12:41:30 -0800
committerGravatar TensorFlower Gardener <gardener@tensorflow.org>2017-03-16 14:06:32 -0700
commitf73a90a38ea33fb32647fb97027991709d483b0d (patch)
tree3fa674ac1658729636ef0a3c7d229c4687cc1cb5
parentbc1763c4ac8bfc43a4e7dc31da8ee8f0cd1b6987 (diff)
Improve TensorBoard scalar dashboard domain calculation.
- Add an "ignore y-outliers" option (default true). When true, the domain is calculated based on the middle 8 deciles of the y range, i.e. the lowest 10% of data and highest 10% of data is ignored for domain calculation purposes. Also, this is done with the smoothed data rather than the raw data. This means that brief spikes or an initially high loss value will not distort the chart. This can be disabled to view the full data domain. - If the y values are all in the range [0, 1], then the domain is automatically set to be approximately [0, 1]. That makes it easy to compare proportional values. - Added bold gridlines at the origin (0,0) to make the charts easier to understand at a glance. Change: 150362432
-rw-r--r--tensorflow/tensorboard/components/tf_dashboard_common/dashboard-style.html2
-rw-r--r--tensorflow/tensorboard/components/tf_dashboard_common/tf-categorizer.html2
-rw-r--r--tensorflow/tensorboard/components/tf_scalar_dashboard/tf-scalar-dashboard.html21
-rw-r--r--tensorflow/tensorboard/components/vz_line_chart/dragZoomInteraction.ts22
-rw-r--r--tensorflow/tensorboard/components/vz_line_chart/vz-chart-helpers.ts34
-rw-r--r--tensorflow/tensorboard/components/vz_line_chart/vz-line-chart.html23
-rw-r--r--tensorflow/tensorboard/components/vz_line_chart/vz-line-chart.ts29
7 files changed, 111 insertions, 22 deletions
diff --git a/tensorflow/tensorboard/components/tf_dashboard_common/dashboard-style.html b/tensorflow/tensorboard/components/tf_dashboard_common/dashboard-style.html
index b6225ba5b2..d7e303056a 100644
--- a/tensorflow/tensorboard/components/tf_dashboard_common/dashboard-style.html
+++ b/tensorflow/tensorboard/components/tf_dashboard_common/dashboard-style.html
@@ -30,7 +30,7 @@ limitations under the License.
.sidebar-section {
border-top: solid 1px rgba(0, 0, 0, 0.12);
- padding: 20px 0px 20px 30px;
+ padding: 15px 0px 15px 30px;
}
.sidebar-section:first-child {
diff --git a/tensorflow/tensorboard/components/tf_dashboard_common/tf-categorizer.html b/tensorflow/tensorboard/components/tf_dashboard_common/tf-categorizer.html
index 969b6f46fb..64f43f9e24 100644
--- a/tensorflow/tensorboard/components/tf_dashboard_common/tf-categorizer.html
+++ b/tensorflow/tensorboard/components/tf_dashboard_common/tf-categorizer.html
@@ -49,7 +49,7 @@ categories are exclusive.
<style>
:host {
display: block;
- padding-bottom: 15px;
+ padding-bottom: 5px;
}
paper-checkbox {
--paper-checkbox-checked-color: var(--paper-grey-600);
diff --git a/tensorflow/tensorboard/components/tf_scalar_dashboard/tf-scalar-dashboard.html b/tensorflow/tensorboard/components/tf_scalar_dashboard/tf-scalar-dashboard.html
index d4688bb7c4..35f2f2b94a 100644
--- a/tensorflow/tensorboard/components/tf_scalar_dashboard/tf-scalar-dashboard.html
+++ b/tensorflow/tensorboard/components/tf_scalar_dashboard/tf-scalar-dashboard.html
@@ -67,10 +67,18 @@ contains vz-line-charts embedded inside tf-panes-helper's.
selected-runs="{{_selectedRuns}}"
>
<div class="extend-first-section">
- <paper-checkbox
+ <div class="line-item">
+ <paper-checkbox
id="download-option"
checked="{{_showDownloadLinks}}"
- >Data download links</paper-checkbox>
+ >Show data download links</paper-checkbox>
+ </div>
+ <div class="line-item">
+ <paper-checkbox
+ id="outliersCheckbox"
+ checked="{{_ignoreYOutliers}}"
+ >Ignore outliers in chart scaling</paper-checkbox>
+ </div>
<div id="tooltip-sorting">
<div id="tooltip-sorting-label">Tooltip sorting method:</div>
<paper-dropdown-menu
@@ -125,6 +133,7 @@ contains vz-line-charts embedded inside tf-panes-helper's.
smoothing-enabled="[[_smoothingEnabled]]"
smoothing-weight="[[_smoothingWeight]]"
tooltip-sorting-method="[[_tooltipSortingMethod]]"
+ ignore-y-outliers="[[_ignoreYOutliers]]"
></vz-line-chart>
<paper-icon-button
class="log-button"
@@ -171,6 +180,10 @@ contains vz-line-charts embedded inside tf-panes-helper's.
--paper-input-container-focus-color: var(--tb-orange-strong);
width: 105px;
}
+ .line-item {
+ display: block;
+ padding-top: 5px;
+ }
</style>
</template>
@@ -210,6 +223,10 @@ contains vz-line-charts embedded inside tf-panes-helper's.
type: Boolean,
computed: '_computeSmoothingEnabled(_smoothingWeight)'
},
+ _ignoreYOutliers: {
+ type: Boolean,
+ value: true,
+ },
_xType: {
type: String,
value: "step"
diff --git a/tensorflow/tensorboard/components/vz_line_chart/dragZoomInteraction.ts b/tensorflow/tensorboard/components/vz_line_chart/dragZoomInteraction.ts
index 6e8b9c6879..0e5a7c1d5b 100644
--- a/tensorflow/tensorboard/components/vz_line_chart/dragZoomInteraction.ts
+++ b/tensorflow/tensorboard/components/vz_line_chart/dragZoomInteraction.ts
@@ -22,6 +22,7 @@ export class DragZoomLayer extends Components.SelectionBoxLayer {
private _animationTime = 750;
private onStart: Function;
private onEnd: Function;
+ private unzoomMethod: Function;
/**
* Constructs a SelectionBoxLayer with an attached DragInteraction and
@@ -35,8 +36,10 @@ export class DragZoomLayer extends Components.SelectionBoxLayer {
* Component Group.
* TODO(danmane) - merge this into Plottable
*/
- constructor(xScale: QuantitativeScale<number | { valueOf(): number }>,
- yScale: QuantitativeScale<number | { valueOf(): number }>) {
+ constructor(
+ xScale: QuantitativeScale<number|{valueOf(): number}>,
+ yScale: QuantitativeScale<number|{valueOf(): number}>,
+ unzoomMethod: Function) {
super();
this.xScale(xScale);
this.yScale(yScale);
@@ -45,6 +48,7 @@ export class DragZoomLayer extends Components.SelectionBoxLayer {
this._doubleClickInteraction = new Interactions.DoubleClick();
this._doubleClickInteraction.attachTo(this);
this.setupCallbacks();
+ this.unzoomMethod = unzoomMethod;
}
/**
@@ -141,22 +145,12 @@ export class DragZoomLayer extends Components.SelectionBoxLayer {
return;
}
this.isZoomed = false;
-
- // Some Plottable magic follows which ensures that when we un-zoom, we
- // un-zoom to the current extent of the data; i.e. if new data was loaded
- // since we zoomed, we should un-zoom to the extent of the new data.
- // this basically replicates the autoDomain logic in Plottable.
- // it uses the internal methods to get the same boundaries that autoDomain
- // would, but allows us to interpolate the zoom with a nice animation.
let xScale = this.xScale() as any;
- let yScale = this.yScale() as any;
xScale._domainMin = null;
xScale._domainMax = null;
- yScale._domainMin = null;
- yScale._domainMax = null;
let xDomain = xScale._getExtent();
- let yDomain = yScale._getExtent();
- this.interpolateZoom(xDomain[0], xDomain[1], yDomain[0], yDomain[1]);
+ this.xScale().domain(xDomain);
+ this.unzoomMethod();
}
// If we are zooming, disable interactions, to avoid contention
diff --git a/tensorflow/tensorboard/components/vz_line_chart/vz-chart-helpers.ts b/tensorflow/tensorboard/components/vz_line_chart/vz-chart-helpers.ts
index 839f0fb8b2..a4b8739590 100644
--- a/tensorflow/tensorboard/components/vz_line_chart/vz-chart-helpers.ts
+++ b/tensorflow/tensorboard/components/vz_line_chart/vz-chart-helpers.ts
@@ -66,6 +66,40 @@ module VZ.ChartHelpers {
};
}
+ /* Compute an appropriate domain given an array of all the values that are
+ * going to be displayed. If ignoreOutliers is true, it will ignore the
+ * lowest 10% and highest 10% of the data when computing a domain.
+ * It has n log n performance when ignoreOutliers is true, as it needs to
+ * sort the data.
+ */
+ export function computeDomain(values: number[], ignoreOutliers: boolean) {
+ if (values.length === 0) {
+ return [-0.1, 1.1];
+ }
+ let a: number;
+ let b: number;
+ if (ignoreOutliers) {
+ let sorted = _.sortBy(values);
+ a = d3.quantile(sorted, 0.10);
+ b = d3.quantile(sorted, 0.90);
+ } else {
+ a = d3.min(values);
+ b = d3.max(values);
+ }
+ // When the data all fits into the unit interval, we switch to a consistent
+ // domain for unit data. This is helpful for proportional parameters like
+ // error rates or % of queue that is full. This way, users can meaningfully
+ // compare charts and see information at a glance (if the value is always
+ // 1, it appears at top of the chart, 0 is bottom, etc.)
+ if (a >= 0 && b <= 1) {
+ return [-0.1, 1.1];
+ }
+ let padding = (b - a) * 0.20;
+ let domain = [a - padding, b + padding];
+ domain = d3.scale.linear().domain(domain).nice().domain();
+ return domain;
+ }
+
export function accessorize(key: string): Plottable.Accessor<number> {
return (d: any, index: number, dataset: Plottable.Dataset) => d[key];
}
diff --git a/tensorflow/tensorboard/components/vz_line_chart/vz-line-chart.html b/tensorflow/tensorboard/components/vz_line_chart/vz-line-chart.html
index 0d160795e8..ada6c0fd47 100644
--- a/tensorflow/tensorboard/components/vz_line_chart/vz-line-chart.html
+++ b/tensorflow/tensorboard/components/vz_line_chart/vz-line-chart.html
@@ -117,6 +117,11 @@ such as different X scales (linear and temporal), tooltips and smoothing.
stroke-width: 1px;
}
+ #chartsvg line.guide-line {
+ stroke: #999;
+ stroke-width: 1.5px;
+ }
+
</style>
</template>
<script src="dragZoomInteraction.js"></script>
@@ -204,6 +209,15 @@ such as different X scales (linear and temporal), tooltips and smoothing.
},
/**
+ * Whether to ignore outlier data when computing the yScale domain.
+ */
+
+ ignoreYOutliers: {
+ type: Boolean,
+ value: true,
+ },
+
+ /**
* Change how the tooltip is sorted. Allows:
* - "default" - Sort the tooltip by input order.
* - "ascending" - Sort the tooltip by ascending value.
@@ -245,7 +259,8 @@ such as different X scales (linear and temporal), tooltips and smoothing.
"_reloadFromCache(_chart)",
"_smoothingChanged(smoothingEnabled, smoothingWeight, _chart)",
"_tooltipSortingMethodChanged(tooltipSortingMethod, _chart)",
- "_tooltipPositionChanged(tooltipPosition, _chart)"
+ "_tooltipPositionChanged(tooltipPosition, _chart)",
+ "_outliersChanged(ignoreYOutliers, _chart)"
],
/**
@@ -333,6 +348,12 @@ such as different X scales (linear and temporal), tooltips and smoothing.
this._chart.smoothingDisable();
}
},
+ _outliersChanged: function() {
+ if (!this._chart) {
+ return;
+ }
+ this._chart.ignoreYOutliers(this.ignoreYOutliers);
+ },
_tooltipSortingMethodChanged: function() {
if(this._chart) {
this._chart.setTooltipSortingMethod(this.tooltipSortingMethod);
diff --git a/tensorflow/tensorboard/components/vz_line_chart/vz-line-chart.ts b/tensorflow/tensorboard/components/vz_line_chart/vz-line-chart.ts
index 1be2a8f913..b1ad5ac9b3 100644
--- a/tensorflow/tensorboard/components/vz_line_chart/vz-line-chart.ts
+++ b/tensorflow/tensorboard/components/vz_line_chart/vz-line-chart.ts
@@ -45,6 +45,7 @@ module VZ {
private smoothingEnabled: Boolean;
private tooltipSortingMethod: string;
private tooltipPosition: string;
+ private _ignoreYOutliers: boolean;
private targetSVG: d3.Selection<any>;
@@ -56,6 +57,7 @@ module VZ {
this.colorScale = colorScale;
this.tooltip = tooltip;
this.datasets = [];
+ this._ignoreYOutliers = true;
// lastPointDataset is a dataset that contains just the last point of
// every dataset we're currently drawing.
this.lastPointsDataset = new Plottable.Dataset();
@@ -82,15 +84,21 @@ module VZ {
this.yAxis.margin(0).tickLabelPadding(5).formatter(yFormatter);
this.yAxis.usesTextWidthApproximation(true);
- this.dzl = new Plottable.DragZoomLayer(this.xScale, this.yScale);
+ this.dzl = new Plottable.DragZoomLayer(
+ this.xScale, this.yScale, this.updateSpecialDatasets.bind(this));
let center = this.buildPlot(this.xAccessor, this.xScale, this.yScale);
this.gridlines =
new Plottable.Components.Gridlines(this.xScale, this.yScale);
- this.center =
- new Plottable.Components.Group([this.gridlines, center, this.dzl]);
+ let xZeroLine = new Plottable.Components.GuideLineLayer('horizontal');
+ xZeroLine.scale(this.yScale).value(0);
+ let yZeroLine = new Plottable.Components.GuideLineLayer('vertical');
+ yZeroLine.scale(this.xScale).value(0);
+
+ this.center = new Plottable.Components.Group(
+ [this.gridlines, xZeroLine, yZeroLine, center, this.dzl]);
this.outer = new Plottable.Components.Table([
[this.yAxis, this.center],
[null, this.xAxis]
@@ -155,6 +163,13 @@ module VZ {
this.updateSpecialDatasets();
}
+ public ignoreYOutliers(ignoreYOutliers: boolean) {
+ if (ignoreYOutliers !== this._ignoreYOutliers) {
+ this._ignoreYOutliers = ignoreYOutliers;
+ this.updateSpecialDatasets();
+ }
+ }
+
private updateSpecialDatasets() {
if (this.smoothingEnabled) {
this.updateSpecialDatasetsWithAccessor(this.smoothedAccessor);
@@ -221,6 +236,14 @@ module VZ {
};
let nanData = _.flatten(this.datasets.map(datasetToNaNData));
this.nanDataset.data(nanData);
+
+ let datasetToValues: (d: Plottable.Dataset) => number[] = (d) => {
+ return d.data().map((x) => accessor(x, -1, d));
+ };
+ let vals = _.flatten(this.datasets.map(datasetToValues));
+ vals = vals.filter((x) => x === x && x !== Infinity && x !== -Infinity);
+ let domain = VZ.ChartHelpers.computeDomain(vals, this._ignoreYOutliers);
+ this.yScale.domain(domain);
}
private setupTooltips(plot: Plottable.XYPlot<number|Date, number>):