From c5dc4a033552f29dc43dd283e3a5c30432c8facb Mon Sep 17 00:00:00 2001 From: Stephan Lee Date: Mon, 8 Oct 2018 15:34:46 -0700 Subject: [PATCH 1/4] Add true log scale to line chart Line chart was using Plottable.Scale.ModifiedLogScale which treated values near (0, 1] very differently than what log does. This handles negative value (wrong but data is presented) and sometimes present line chart very nicely but it works against researchers' expectation. --- tensorboard/components/vz_line_chart2/BUILD | 5 +- .../components/vz_line_chart2/line-chart.ts | 58 ++++--- .../components/vz_line_chart2/linear-scale.ts | 119 +++++++++++++ .../components/vz_line_chart2/log-scale.ts | 164 ++++++++++++++++++ .../components/vz_line_chart2/tf-scale.ts | 85 +++++++++ .../vz_line_chart2/vz-line-chart2.html | 3 + 6 files changed, 413 insertions(+), 21 deletions(-) create mode 100644 tensorboard/components/vz_line_chart2/linear-scale.ts create mode 100644 tensorboard/components/vz_line_chart2/log-scale.ts create mode 100644 tensorboard/components/vz_line_chart2/tf-scale.ts diff --git a/tensorboard/components/vz_line_chart2/BUILD b/tensorboard/components/vz_line_chart2/BUILD index 25f56dc1afd..45752b7ec5b 100644 --- a/tensorboard/components/vz_line_chart2/BUILD +++ b/tensorboard/components/vz_line_chart2/BUILD @@ -8,10 +8,13 @@ licenses(["notice"]) # Apache 2.0 tf_web_library( name = "vz_line_chart2", srcs = [ - "line-chart.ts", "line-chart-exporter.ts", + "line-chart.ts", + "linear-scale.ts", + "log-scale.ts", "panZoomDragLayer.html", "panZoomDragLayer.ts", + "tf-scale.ts", "vz-line-chart2.html", "vz-line-chart2.ts", ], diff --git a/tensorboard/components/vz_line_chart2/line-chart.ts b/tensorboard/components/vz_line_chart2/line-chart.ts index f4f16c4d1df..c2568be6023 100644 --- a/tensorboard/components/vz_line_chart2/line-chart.ts +++ b/tensorboard/components/vz_line_chart2/line-chart.ts @@ -31,6 +31,11 @@ enum TooltipColumnEvalType { DOM, } +enum YScaleType { + LOG = 'log', + LINEAR = 'linear', +} + export type LineChartStatus = { smoothingEnabled: boolean }; @@ -60,7 +65,7 @@ export class LineChart { private xAccessor: Plottable.IAccessor; private xScale: Plottable.QuantitativeScale; - private yScale: Plottable.QuantitativeScale; + private yScale: ITfScale; private gridlines: Plottable.Components.Gridlines; private center: Plottable.Components.Group; private xAxis: Plottable.Axes.Numeric|Plottable.Axes.Time; @@ -163,6 +168,9 @@ export class LineChart { this.xAxis.formatter(xAxisFormatter); } this.yScale = LineChart.getYScaleFromType(yScaleType); + this.yScale.setValueProviderForDomain( + () => this.getValuesForYAxisDomainCompute()); + this.yAxis = new Plottable.Axes.Numeric(this.yScale, 'left'); let yFormatter = vz_chart_helpers.multiscaleFormatter( vz_chart_helpers.Y_AXIS_FORMATTER_PRECISION); @@ -186,8 +194,11 @@ export class LineChart { this.gridlines = new Plottable.Components.Gridlines(this.xScale, this.yScale); - let xZeroLine = new Plottable.Components.GuideLineLayer('horizontal'); - xZeroLine.scale(this.yScale).value(0); + let xZeroLine = null; + if (yScaleType !== YScaleType.LOG) { + 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); @@ -299,10 +310,20 @@ export class LineChart { if (ignoreYOutliers !== this._ignoreYOutliers) { this._ignoreYOutliers = ignoreYOutliers; this.updateSpecialDatasets(); + this.yScale.ignoreOutlier(ignoreYOutliers); this.resetYDomain(); } } + private getValuesForYAxisDomainCompute(): number[] { + const accessors = this.getAccessorsForComputingYRange(); + let datasetToValues: (d: Plottable.Dataset) => number[][] = (d) => { + return accessors.map(accessor => d.data().map(x => accessor(x, -1, d))); + }; + return _.flattenDeep(this.datasets.map(datasetToValues)) + .filter(isFinite); + } + /** Constructs special datasets. Each special dataset contains exceptional * values from all of the regular datasets, e.g. last points in series, or * NaN values. Those points will have a `name` and `relative` property added @@ -388,21 +409,19 @@ export class LineChart { } private resetYDomain() { - let yDomain; if (this._defaultYRange != null) { // Use the range specified by the caller. - yDomain = this._defaultYRange; + this.yScale.domain(this._defaultYRange); } else { - // Generate a reasonable range. - const accessors = this.getAccessorsForComputingYRange(); - let datasetToValues: (d: Plottable.Dataset) => number[][] = (d) => { - return accessors.map(accessor => d.data().map(x => accessor(x, -1, d))); - }; - const vals = _.flattenDeep(this.datasets.map(datasetToValues)) - .filter(isFinite); - yDomain = vz_chart_helpers.computeDomain(vals, this._ignoreYOutliers); + // TfScale has all the logics for scaling and we manually trigger it with + // `autoDomain`. However, this enables the autoDomain mode which updates + // the domain on any dataset change and this is not desirably especially + // when a run is not finished yet; we don't want the graph to change in + // scale while user is inspecting the graph. By setting the `domain` + // explicitly, we can turn the feature off. + this.yScale.autoDomain(); + this.yScale.domain(this.yScale.domain()); } - this.yScale.domain(yDomain); } private getAccessorsForComputingYRange(): Plottable.IAccessor[] { @@ -721,12 +740,11 @@ export class LineChart { return this.name2datasets[name]; } - static getYScaleFromType(yScaleType: string): - Plottable.QuantitativeScale { - if (yScaleType === 'log') { - return new Plottable.Scales.ModifiedLog(); - } else if (yScaleType === 'linear') { - return new Plottable.Scales.Linear(); + static getYScaleFromType(yScaleType: string): ITfScale { + if (yScaleType === YScaleType.LOG) { + return new LogScale(); + } else if (yScaleType === YScaleType.LINEAR) { + return new LinearScale(); } else { throw new Error('Unrecognized yScale type ' + yScaleType); } diff --git a/tensorboard/components/vz_line_chart2/linear-scale.ts b/tensorboard/components/vz_line_chart2/linear-scale.ts new file mode 100644 index 00000000000..b4174e481a9 --- /dev/null +++ b/tensorboard/components/vz_line_chart2/linear-scale.ts @@ -0,0 +1,119 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ +namespace vz_line_chart2 { + +export class LinearScale extends Plottable.Scales.Linear implements ITfScale { + private _ignoreOutlier: boolean = false; + protected _valueProviderForDomain: ValueProviderForDomain; + + constructor() { + super(); + this.padProportion(.2); + } + + public setValueProviderForDomain(provider: ValueProviderForDomain): this { + this._valueProviderForDomain = provider; + return this; + } + + /** + * Adds some padding to a given domain. Specifically, it: + * - returns about [-0.1a, 2.1a] when a = b and a >= 0. + * - returns about [-2.1a, 0.1a] when a = b and a < 0. + * - returns [-0.1b, b + padProportion * (b-a)] if b > 2a and a > 0 + * - else, pads by `padProportion` + * @override + */ + protected _niceDomain(domain: number[], count?: number): number[] { + const [a, b] = domain; + let padding: number; + const span = b - a; + if (span === 0) { + // If b===a, we would create an empty range. We instead select the range + // [0, 2*a] if a > 0, or [-2*a, 0] if a < 0, plus a little bit of + // extra padding on the top and bottom of the plot. + padding = Math.abs(a) * 1.1 + 1.1; + } else { + padding = span * this.padProportion(); + } + + let lower: number; + if (a >= 0 && a < span) { + // We include the intercept (y = 0) if doing so less than doubles the span + // of the y-axis. (We actually select a lower bound that's slightly less + // than 0 so that 0.00 will clearly be written on the lower edge of the + // chart. The label on the lowest tick is often filtered out.) + lower = -0.1 * b; + } else { + lower = a - padding; + } + return super._niceDomain([lower, b + padding], count); + } + + /** + * @override to remove default padding logic. + */ + protected _getUnboundedExtent(ignoreAttachState): number[] { + const includedValues = this._getAllIncludedValues(ignoreAttachState); + let extent = this._defaultExtent(); + if (includedValues.length !== 0) { + const combinedExtent = [ + Plottable.Utils.Math.min(includedValues, extent[0]), + Plottable.Utils.Math.max(includedValues, extent[1]), + ]; + extent = this._niceDomain(combinedExtent); + } + return extent; + } + + /** + * @override + */ + protected _getAllIncludedValues(ignoreAttachState = false): number[] { + const values = this._valueProviderForDomain ? + this._valueProviderForDomain() : []; + return this.extentOfValues(values); + } + + /** + * @override to apply the outlier logic. + */ + public extentOfValues(values: number[]): number[] { + const legalValues = values + .filter(x => Plottable.Utils.Math.isValidNumber(x)); + let filteredValues = legalValues; + if (this.ignoreOutlier()) { + const sortedValues = legalValues.sort((a, b) => a - b); + const a = d3.quantile(sortedValues, 0.05); + const b = d3.quantile(sortedValues, 0.95); + filteredValues = legalValues.filter(x => x >= a && x <= b); + } + const extent = d3.extent(filteredValues); + return extent[0] == null || extent[1] == null ? [] : extent; + } + + public ignoreOutlier(): boolean; + public ignoreOutlier(ignore: boolean): this; + public ignoreOutlier(ignore?: boolean): any { + if (typeof ignore == 'boolean') { + this._ignoreOutlier = ignore; + return this; + } + return this._ignoreOutlier; + } + +} + +} // namespace vz_line_chart2 diff --git a/tensorboard/components/vz_line_chart2/log-scale.ts b/tensorboard/components/vz_line_chart2/log-scale.ts new file mode 100644 index 00000000000..0b07301aee5 --- /dev/null +++ b/tensorboard/components/vz_line_chart2/log-scale.ts @@ -0,0 +1,164 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ +namespace vz_line_chart2 { + +const MIN_VALUE = 1e-15; + +function log(x: number): number { + return Math.log(x) / Math.log(10); +} + +function pow(x: number): number { + return Math.pow(10, x); +} + +export class LogScale extends TfScale { + private _d3LogScale = d3.scaleLog(); + private _untransformedDomain: number[]; + + constructor() { + super(); + this.padProportion(.2); + } + + public scale(x: number): number { + // Returning NaN makes sure line plot does not plot illegal values. + if (x <= 0) return NaN; + return this._d3LogScale(x); + } + + public invert(x: number): number { + return this._d3LogScale.invert(x); + } + + public scaleTransformation(value: number) { + return this.scale(value); + } + + public invertedTransformation(value: number) { + return this.invert(value); + } + + public getTransformationDomain(): [number, number] { + return this.domain() as [number, number]; + } + + protected _getDomain() { + return this._untransformedDomain; + } + + protected _setDomain(values: number[]) { + this._untransformedDomain = values; + const [min, max] = values; + super._setDomain([Math.max(MIN_VALUE, min), max]); + } + + /** + * Given a domain, pad it and clip the lower bound to MIN_VALUE. + */ + protected _niceDomain(domain: number[], count?: number): number[] { + const [low, high] = domain; + const adjustedLogLow = Math.max(log(MIN_VALUE), log(low)); + const logHigh = log(high); + const pad = (logHigh - adjustedLogLow) * this.padProportion(); + const logLowFloor = Math.floor(adjustedLogLow); + const logHighCeil = Math.ceil(logHigh); + return [ + pow(Math.max(log(MIN_VALUE), adjustedLogLow - pad, logLowFloor)), + pow(Math.min(logHigh + pad, logHighCeil)), + ]; + } + + /** + * Generates a possible extent based on data from all plots the scale is + * connected to by taking the minimum and maximum values of all extents for + * lower and upper bound, respectively. + * @override to remove default padding logic. + */ + protected _getUnboundedExtent(ignoreAttachState): number[] { + const includedValues = this._getAllIncludedValues(ignoreAttachState); + let extent = this._defaultExtent(); + if (includedValues.length !== 0) { + const combinedExtent = [ + Plottable.Utils.Math.min(includedValues, extent[0]), + Plottable.Utils.Math.max(includedValues, extent[1]), + ]; + extent = this._niceDomain(combinedExtent); + } + return extent; + } + + protected _getAllIncludedValues(ignoreAttachState = false): number[] { + const values = super._getAllIncludedValues(); + // For log scale, the value cannot be smaller or equal to 0. They are + // negative infinity. + return values.map(x => x > 0 ? x : MIN_VALUE); + } + + protected _defaultExtent(): number[] { + return [1, 10]; + } + + protected _backingScaleDomain(): number[] + protected _backingScaleDomain(values: number[]): this + protected _backingScaleDomain(values?: number[]): any { + if (values == null) { + return this._d3LogScale.domain(); + } else { + this._d3LogScale.domain(values); + return this; + } + } + + protected _getRange() { + return this._d3LogScale.range(); + } + + protected _setRange(values: number[]) { + this._d3LogScale.range(values); + } + + public defaultTicks(): number[] { + return this._d3LogScale.ticks(1); + } + + public ticks(): number[] { + return this._d3LogScale.ticks(); + } + + /** + * Returns an `extent` for a data series. In log-scale, we must omit all + * non-positive values when computing a `domain`. + * @override + */ + public extentOfValues(values: number[]): number[] { + // Log can only take positive values. + const legalValues = values + .filter(x => Plottable.Utils.Math.isValidNumber(x) && x > 0); + let filteredValues = legalValues; + if (this.ignoreOutlier()) { + const logValues = legalValues.map(log); + const sortedLogValues = logValues.sort((a, b) => a - b); + const a = d3.quantile(sortedLogValues, 0.05); + const b = d3.quantile(sortedLogValues, 0.95); + filteredValues = sortedLogValues.filter(x => x >= a && x <= b).map(pow); + } + const extent = d3.extent(filteredValues); + return extent[0] == null || extent[1] == null ? [] : extent; + } + +} + +} // namespace vz_line_chart2 diff --git a/tensorboard/components/vz_line_chart2/tf-scale.ts b/tensorboard/components/vz_line_chart2/tf-scale.ts new file mode 100644 index 00000000000..ad819f37a6e --- /dev/null +++ b/tensorboard/components/vz_line_chart2/tf-scale.ts @@ -0,0 +1,85 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ +namespace vz_line_chart2 { + +export type ValueProviderForDomain = () => number[]; + +/** + * Plottable.Scale is a class that wraps the d3.scale that adds many utility + * methods that work with the Plottable's `dataset` concept. Here, we will + * attempt to explain few basic concepts in plain English. + * - domain: [f(min(x)), f(max(x))] + * - range: pixel values of the chart + * + * Plottable.Scale provides some cool feature where a scale is bound to set of + * plots (i.e., line, scatter, smooth line chart, etc...) and, when a dataset + * of a plot changes, updates the domain based on minimum and maximum values of + * each charts. In some Plottable functions, a word `extent` is used to refer to + * a possible value for a domain and it often is the minimum and maximum value + * of a dataset of a plot. + * + * Above binding is quite useful in most cases but is rather harmful for the + * line-chart. The line-chart draws multiple plots -- a line plot for raw data, + * another line plot for smoothed data, a scatter plot for tooltip, and etc... + * These plots all derive data from the raw data series, so it is rather odd to + * compute `extent` for each plot separately. Moreover, we want to set the + * domain with respect to a solid colored line (when using smoothing, it is the + * smoothed line plot) regardless of the extent of the raw data. Hence, we need + * an ability to disregard dataset of certain plots when computed domain but + * such capability is not opened from the Plottable. + * + * To mitigate the issue, TfScale overrides few methods and receives data from + * the LineChart instead of a respective plots the chart draws. + */ +export interface ITfScale extends Plottable.QuantitativeScale { + setValueProviderForDomain(provider: ValueProviderForDomain): this; + + ignoreOutlier(): boolean; + ignoreOutlier(ignore: boolean): this; +} + +export abstract class TfScale extends Plottable.QuantitativeScale implements ITfScale { + protected _ignoreOutlier: boolean = false; + protected _valueProviderForDomain: ValueProviderForDomain; + + public setValueProviderForDomain(provider: ValueProviderForDomain): this { + this._valueProviderForDomain = provider; + return this; + } + + public ignoreOutlier(): boolean; + public ignoreOutlier(ignore: boolean): this; + public ignoreOutlier(ignore?: boolean): any { + if (typeof ignore == 'boolean') { + this._ignoreOutlier = ignore; + return this; + } + return this._ignoreOutlier; + } + + /** + * Returns possible `extent`s for a dataset. Note that a dataset can contain + * multiple series. + * Unlike the method name suggests, it uses `values` to return `extent`s. + * @override + */ + protected _getAllIncludedValues(ignoreAttachState = false): number[] { + const values = this._valueProviderForDomain ? + this._valueProviderForDomain() : []; + return this.extentOfValues(values); + } +} + +} // namespace vz_line_chart2 diff --git a/tensorboard/components/vz_line_chart2/vz-line-chart2.html b/tensorboard/components/vz_line_chart2/vz-line-chart2.html index 03034f45a68..7f919d452b8 100644 --- a/tensorboard/components/vz_line_chart2/vz-line-chart2.html +++ b/tensorboard/components/vz_line_chart2/vz-line-chart2.html @@ -85,6 +85,9 @@ } + + + From 878eb7a99cd764439c47c5c26f97ba6fcc26f556 Mon Sep 17 00:00:00 2001 From: Stephan Lee Date: Thu, 18 Oct 2018 14:51:37 -0700 Subject: [PATCH 2/4] Post CR address --- .../components/vz_line_chart2/linear-scale.ts | 14 ++++++++------ tensorboard/components/vz_line_chart2/log-scale.ts | 2 +- tensorboard/components/vz_line_chart2/tf-scale.ts | 8 +++----- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/tensorboard/components/vz_line_chart2/linear-scale.ts b/tensorboard/components/vz_line_chart2/linear-scale.ts index b4174e481a9..2ec68030f9b 100644 --- a/tensorboard/components/vz_line_chart2/linear-scale.ts +++ b/tensorboard/components/vz_line_chart2/linear-scale.ts @@ -30,10 +30,12 @@ export class LinearScale extends Plottable.Scales.Linear implements ITfScale { /** * Adds some padding to a given domain. Specifically, it: - * - returns about [-0.1a, 2.1a] when a = b and a >= 0. - * - returns about [-2.1a, 0.1a] when a = b and a < 0. + * - returns about [-0.1a - c, 2.1a + c] when a = b and a >= 0. + * - returns about [-2.1|a| - c, -0.1|a| + c] when a = b and a < 0. * - returns [-0.1b, b + padProportion * (b-a)] if b > 2a and a > 0 * - else, pads by `padProportion` + * Note that `c` is a constant offset which specifically is 1.1. Please refer + * to [1] for its rationale. * @override */ protected _niceDomain(domain: number[], count?: number): number[] { @@ -51,10 +53,10 @@ export class LinearScale extends Plottable.Scales.Linear implements ITfScale { let lower: number; if (a >= 0 && a < span) { - // We include the intercept (y = 0) if doing so less than doubles the span - // of the y-axis. (We actually select a lower bound that's slightly less - // than 0 so that 0.00 will clearly be written on the lower edge of the - // chart. The label on the lowest tick is often filtered out.) + // [1]: We include the intercept (y = 0) if doing so less than doubles the + // span of the y-axis. (We actually select a lower bound that's slightly + // less than 0 so that 0.00 will clearly be written on the lower edge of + // the chart. The label on the lowest tick is often filtered out.) lower = -0.1 * b; } else { lower = a - padding; diff --git a/tensorboard/components/vz_line_chart2/log-scale.ts b/tensorboard/components/vz_line_chart2/log-scale.ts index 0b07301aee5..035ee2ffcc2 100644 --- a/tensorboard/components/vz_line_chart2/log-scale.ts +++ b/tensorboard/components/vz_line_chart2/log-scale.ts @@ -17,7 +17,7 @@ namespace vz_line_chart2 { const MIN_VALUE = 1e-15; function log(x: number): number { - return Math.log(x) / Math.log(10); + return Math.log10(x); } function pow(x: number): number { diff --git a/tensorboard/components/vz_line_chart2/tf-scale.ts b/tensorboard/components/vz_line_chart2/tf-scale.ts index ad819f37a6e..c34f221e211 100644 --- a/tensorboard/components/vz_line_chart2/tf-scale.ts +++ b/tensorboard/components/vz_line_chart2/tf-scale.ts @@ -18,10 +18,7 @@ export type ValueProviderForDomain = () => number[]; /** * Plottable.Scale is a class that wraps the d3.scale that adds many utility - * methods that work with the Plottable's `dataset` concept. Here, we will - * attempt to explain few basic concepts in plain English. - * - domain: [f(min(x)), f(max(x))] - * - range: pixel values of the chart + * methods that work with the Plottable's `dataset` concept. * * Plottable.Scale provides some cool feature where a scale is bound to set of * plots (i.e., line, scatter, smooth line chart, etc...) and, when a dataset @@ -72,7 +69,8 @@ export abstract class TfScale extends Plottable.QuantitativeScale implem /** * Returns possible `extent`s for a dataset. Note that a dataset can contain * multiple series. - * Unlike the method name suggests, it uses `values` to return `extent`s. + * Unlike the method name suggests, it uses values from each series to + * return `extent`s. * @override */ protected _getAllIncludedValues(ignoreAttachState = false): number[] { From 7ced0b6303062589901cd78528a929a1023bb162 Mon Sep 17 00:00:00 2001 From: Stephan Lee Date: Thu, 18 Oct 2018 15:53:34 -0700 Subject: [PATCH 3/4] Adjust min value --- .../components/vz_line_chart2/log-scale.ts | 15 +++++++++------ tensorboard/components/vz_line_chart2/tf-scale.ts | 5 ++--- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/tensorboard/components/vz_line_chart2/log-scale.ts b/tensorboard/components/vz_line_chart2/log-scale.ts index 035ee2ffcc2..1738d2ac46e 100644 --- a/tensorboard/components/vz_line_chart2/log-scale.ts +++ b/tensorboard/components/vz_line_chart2/log-scale.ts @@ -14,7 +14,10 @@ limitations under the License. ==============================================================================*/ namespace vz_line_chart2 { -const MIN_VALUE = 1e-15; +// Smallest positive non-zero value represented by IEEE 754 binary (64 bit) +// floating-point number. +// https://www.ecma-international.org/ecma-262/5.1/#sec-8.5 +const MIN_POSITIVE_VALUE = Math.pow(2, -1074); function log(x: number): number { return Math.log10(x); @@ -62,21 +65,21 @@ export class LogScale extends TfScale { protected _setDomain(values: number[]) { this._untransformedDomain = values; const [min, max] = values; - super._setDomain([Math.max(MIN_VALUE, min), max]); + super._setDomain([Math.max(MIN_POSITIVE_VALUE, min), max]); } /** - * Given a domain, pad it and clip the lower bound to MIN_VALUE. + * Given a domain, pad it and clip the lower bound to MIN_POSITIVE_VALUE. */ protected _niceDomain(domain: number[], count?: number): number[] { const [low, high] = domain; - const adjustedLogLow = Math.max(log(MIN_VALUE), log(low)); + const adjustedLogLow = Math.max(log(MIN_POSITIVE_VALUE), log(low)); const logHigh = log(high); const pad = (logHigh - adjustedLogLow) * this.padProportion(); const logLowFloor = Math.floor(adjustedLogLow); const logHighCeil = Math.ceil(logHigh); return [ - pow(Math.max(log(MIN_VALUE), adjustedLogLow - pad, logLowFloor)), + pow(Math.max(log(MIN_POSITIVE_VALUE), adjustedLogLow - pad, logLowFloor)), pow(Math.min(logHigh + pad, logHighCeil)), ]; } @@ -104,7 +107,7 @@ export class LogScale extends TfScale { const values = super._getAllIncludedValues(); // For log scale, the value cannot be smaller or equal to 0. They are // negative infinity. - return values.map(x => x > 0 ? x : MIN_VALUE); + return values.map(x => x > 0 ? x : MIN_POSITIVE_VALUE); } protected _defaultExtent(): number[] { diff --git a/tensorboard/components/vz_line_chart2/tf-scale.ts b/tensorboard/components/vz_line_chart2/tf-scale.ts index c34f221e211..ecfa4837c6c 100644 --- a/tensorboard/components/vz_line_chart2/tf-scale.ts +++ b/tensorboard/components/vz_line_chart2/tf-scale.ts @@ -68,9 +68,8 @@ export abstract class TfScale extends Plottable.QuantitativeScale implem /** * Returns possible `extent`s for a dataset. Note that a dataset can contain - * multiple series. - * Unlike the method name suggests, it uses values from each series to - * return `extent`s. + * multiple series. Unlike the method name suggests, it uses values from each + * series to return `extent`s. * @override */ protected _getAllIncludedValues(ignoreAttachState = false): number[] { From 5d32f2a3cb17d5c13fa8283399e85e1743cf64be Mon Sep 17 00:00:00 2001 From: Stephan Lee Date: Fri, 19 Oct 2018 08:12:44 -0700 Subject: [PATCH 4/4] Added todo --- tensorboard/components/BUILD | 1 - tensorboard/components/tf_tensorboard/BUILD | 1 - tensorboard/components/tf_tensorboard/default-plugins.html | 1 - tensorboard/components/vz_line_chart2/linear-scale.ts | 1 + 4 files changed, 1 insertion(+), 3 deletions(-) diff --git a/tensorboard/components/BUILD b/tensorboard/components/BUILD index 2b01033d2ee..76e29d01708 100644 --- a/tensorboard/components/BUILD +++ b/tensorboard/components/BUILD @@ -21,7 +21,6 @@ tf_web_library( tensorboard_html_binary( name = "index", - compile = True, input_path = "/tensorboard.html", output_path = "/index.html", deps = [":tensorboard"], diff --git a/tensorboard/components/tf_tensorboard/BUILD b/tensorboard/components/tf_tensorboard/BUILD index 425532540ed..491b5f3550f 100644 --- a/tensorboard/components/tf_tensorboard/BUILD +++ b/tensorboard/components/tf_tensorboard/BUILD @@ -60,7 +60,6 @@ tf_web_library( "//tensorboard/plugins/graph/tf_graph_dashboard", "//tensorboard/plugins/histogram/tf_histogram_dashboard", "//tensorboard/plugins/image/tf_image_dashboard", - "//tensorboard/plugins/interactive_inference/tf_interactive_inference_dashboard", "//tensorboard/plugins/pr_curve/tf_pr_curve_dashboard", "//tensorboard/plugins/profile/tf_profile_dashboard", "//tensorboard/plugins/projector/vz_projector", diff --git a/tensorboard/components/tf_tensorboard/default-plugins.html b/tensorboard/components/tf_tensorboard/default-plugins.html index fb2d42f1ddb..8e85419bbf5 100644 --- a/tensorboard/components/tf_tensorboard/default-plugins.html +++ b/tensorboard/components/tf_tensorboard/default-plugins.html @@ -38,4 +38,3 @@ - diff --git a/tensorboard/components/vz_line_chart2/linear-scale.ts b/tensorboard/components/vz_line_chart2/linear-scale.ts index 2ec68030f9b..6cdab0015b9 100644 --- a/tensorboard/components/vz_line_chart2/linear-scale.ts +++ b/tensorboard/components/vz_line_chart2/linear-scale.ts @@ -29,6 +29,7 @@ export class LinearScale extends Plottable.Scales.Linear implements ITfScale { } /** + * TODO(nickfelt): Examine whether we truly require `c`. * Adds some padding to a given domain. Specifically, it: * - returns about [-0.1a - c, 2.1a + c] when a = b and a >= 0. * - returns about [-2.1|a| - c, -0.1|a| + c] when a = b and a < 0.