From 6cb0788111bb00f939dd62ad6b58dbdc2cae785b Mon Sep 17 00:00:00 2001 From: Yannick Assogba Date: Thu, 14 Feb 2019 16:46:46 -0500 Subject: [PATCH 1/9] add render function code snippets and doc annotations --- src/render/barchart.ts | 14 +++++++++++++ src/render/confusion_matrix.ts | 37 ++++++++++++++++++++++++++++++++++ src/render/heatmap.ts | 31 ++++++++++++++++++++++++++++ src/render/histogram.ts | 14 +++++++++++++ src/render/linechart.ts | 29 ++++++++++++++++++++++++++ src/render/scatterplot.ts | 17 ++++++++++++++++ src/render/table.ts | 18 +++++++++++++++++ 7 files changed, 160 insertions(+) diff --git a/src/render/barchart.ts b/src/render/barchart.ts index 9b43d17..39c25fa 100644 --- a/src/render/barchart.ts +++ b/src/render/barchart.ts @@ -39,7 +39,21 @@ import {getDrawArea, nextFrame, shallowEquals} from './render_utils'; * @param opts.fontSize fontSize in pixels for text in the chart * * @returns Promise - indicates completion of rendering + * + * ```js + * const data = [ + * { index: 0, value: 50 }, + * { index: 1, value: 100 }, + * { index: 2, value: 150 }, + * ]; + * + * // Render to visor + * const surface = { name: 'Bar chart', tab: 'Charts' }; + * tfvis.render.barchart(data, surface, {}); + * ``` + * */ +/** @doc {heading: 'render.*', namespace: 'render'} */ export async function renderBarchart( data: Array<{index: number; value: number;}>, container: Drawable, opts: VisOptions = {}): Promise { diff --git a/src/render/confusion_matrix.ts b/src/render/confusion_matrix.ts index e427d4d..20c07b4 100644 --- a/src/render/confusion_matrix.ts +++ b/src/render/confusion_matrix.ts @@ -52,7 +52,44 @@ import {getDrawArea} from './render_utils'; * @param opts.width width of chart in px * @param opts.height height of chart in px * @param opts.fontSize fontSize in pixels for text in the chart + * + * ```js + * const rows = 5; + * const cols = 5; + * const values = []; + * for (let i = 0; i < rows; i++) { + * const row = [] + * for (let j = 0; j < cols; j++) { + * row.push(Math.round(Math.random() * 50)); + * } + * values.push(row); + * } + * const data = { values }; + * + * // Render to visor + * const surface = { name: 'Confusion Matrix', tab: 'Charts' }; + * tfvis.render.confusionMatrix(data, surface); + * ``` + * + * ```js + * // The diagonal can be excluded from shading. + * + * const data = { + * values: [[4, 2, 8], [1, 7, 2], [3, 3, 20]], + * // We also generate 'labels' if none are passed. + * } + * + * // Render to visor + * const surface = { + * name: 'Confusion Matrix with Excluded Diagonal', tab: 'Charts' + * }); + * + * tfvis.render.confusionMatrix(data, surface, { + * shadeDiagonal: false + * }); + * ``` */ +/** @doc {heading: 'render.*', namespace: 'render'} */ export async function renderConfusionMatrix( data: ConfusionMatrixData, container: Drawable, opts: VisOptions& diff --git a/src/render/heatmap.ts b/src/render/heatmap.ts index 62356cc..0c57122 100644 --- a/src/render/heatmap.ts +++ b/src/render/heatmap.ts @@ -54,7 +54,38 @@ import {getDrawArea} from './render_utils'; * @param opts.width width of chart in px * @param opts.height height of chart in px * @param opts.fontSize fontSize in pixels for text in the chart + * + * ```js + * const rows = 50; + * const cols = 20; + * const values = []; + * for (let i = 0; i < rows; i++) { + * const row = [] + * for (let j = 0; j < cols; j++) { + * row.push(i * j) + * } + * values.push(row); + * } + * const data = { values }; + * + * // Render to visor + * const surface = { name: 'Heatmap', tab: 'Charts' }; + * tfvis.render.heatmap(data, surface); + * ``` + * + * ```js + * const data = { + * values: [[4, 2, 8, 20], [1, 7, 2, 10], [3, 3, 20, 13]], + * xLabels: ['cheese', 'pig', 'font'], + * yLabels: ['speed', 'smoothness', 'dexterity', 'mana'], + * } + * + * // Render to visor + * const surface = { name: 'Heatmap w Custom Labels', tab: 'Charts' }; + * tfvis.render.heatmap(data, surface); + * ``` */ +/** @doc {heading: 'render.*', namespace: 'render'} */ export async function renderHeatmap( data: HeatmapData, container: Drawable, opts: HeatmapOptions = {}): Promise { diff --git a/src/render/histogram.ts b/src/render/histogram.ts index 66345eb..0bf722e 100644 --- a/src/render/histogram.ts +++ b/src/render/histogram.ts @@ -53,7 +53,21 @@ const defaultOpts = { * numZeros?: number, * numNans?: number * } + * + * ```js + * const data = Array(100).fill(0) + * .map(x => Math.random() * 100 - (Math.random() * 50)) + * + * // Push some special values for the stats table. + * data.push(Infinity); + * data.push(NaN); + * data.push(0); + * + * const surface = { name: 'Histogram', tab: 'Charts' }; + * tfvis.render.histogram(data, surface); + * ``` */ +/** @doc {heading: 'render.*', namespace: 'render'} */ export async function renderHistogram( data: Array<{value: number}>|number[]|TypedArray, container: HTMLElement, opts: HistogramOpts = {}) { diff --git a/src/render/linechart.ts b/src/render/linechart.ts index 255a7a7..ecfc21b 100644 --- a/src/render/linechart.ts +++ b/src/render/linechart.ts @@ -48,7 +48,36 @@ import {getDrawArea} from './render_utils'; * the plot. * @param opts.yAxisDomain array of two numbers indicating the domain of the y * axis. This is overriden by zoomToFit + * + * ```js + * const series1 = Array(100).fill(0) + * .map(y => Math.random() * 100 - (Math.random() * 50)) + * .map((y, x) => ({ x, y, })); + * + * const series2 = Array(100).fill(0) + * .map(y => Math.random() * 100 - (Math.random() * 150)) + * .map((y, x) => ({ x, y, })); + * + * const series = ['First', 'Second']; + * const data = { values: [series1, series2], series } + * + * const surface = tfvis.visor().surface({ name: 'Line chart', tab: 'Charts' }); + * tfvis.render.linechart(data, surface); + * ``` + * + * ```js + * const series1 = Array(100).fill(0) + * .map(y => Math.random() * 100 + 50) + * .map((y, x) => ({ x, y, })); + * + * const data = { values: [series1] } + * + * // Render to visor + * const surface = { name: 'Zoomed Line Chart', tab: 'Charts' }; + * tfvis.render.linechart(data, surface, { zoomToFit: true }); + * ``` */ +/** @doc {heading: 'render.*', namespace: 'render'} */ export async function renderLinechart( data: {values: Point2D[][]|Point2D[], series?: string[]}, container: Drawable, opts: XYPlotOptions = {}): Promise { diff --git a/src/render/scatterplot.ts b/src/render/scatterplot.ts index 6716594..81ff589 100644 --- a/src/render/scatterplot.ts +++ b/src/render/scatterplot.ts @@ -50,7 +50,24 @@ import {getDrawArea} from './render_utils'; * axis. This is overriden by zoomToFit * @param opts.yAxisDomain array of two numbers indicating the domain of the y * axis. This is overriden by zoomToFit + * + * ```js + * const series1 = Array(100).fill(0) + * .map(y => Math.random() * 100 - (Math.random() * 50)) + * .map((y, x) => ({ x, y, })); + * + * const series2 = Array(100).fill(0) + * .map(y => Math.random() * 100 - (Math.random() * 150)) + * .map((y, x) => ({ x, y, })); + * + * const series = ['First', 'Second']; + * const data = { values: [series1, series2], series } + * + * const surface = { name: 'Scatterplot', tab: 'Charts' }; + * tfvis.render.scatterplot(data, surface); + * ``` */ +/** @doc {heading: 'render.*', namespace: 'render'} */ export async function renderScatterplot( data: {values: Point2D[][]|Point2D[], series?: string[]}, container: Drawable, opts: XYPlotOptions = {}): Promise { diff --git a/src/render/table.ts b/src/render/table.ts index babd1ac..b4778cd 100644 --- a/src/render/table.ts +++ b/src/render/table.ts @@ -41,7 +41,25 @@ import {getDrawArea} from './render_utils'; * the contents of the container and can clear its contents * at will. * @param opts.fontSize fontSize in pixels for text in the chart. + * + * ```js + * const headers = [ + * 'Col 1', + * 'Col 2', + * 'Col 3', + * ]; + * + * const values = [ + * [1, 2, 3], + * ['4', '5', '6'], + * ['strong>7', true, false], + * ]; + * + * const surface = { name: 'Table', tab: 'Charts' }; + * tfvis.render.table({ headers, values }, surface); + * ``` */ +/** @doc {heading: 'render.*', namespace: 'render'} */ export function renderTable( // tslint:disable-next-line:no-any data: {headers: string[], values: any[][]}, container: Drawable, From 8f5df8a30ddd592cf80e1087a7bb8bb1e01acbd7 Mon Sep 17 00:00:00 2001 From: Yannick Assogba Date: Thu, 14 Feb 2019 18:08:57 -0500 Subject: [PATCH 2/9] add show.* and metrics.* doc annotations and code snippets --- src/show/history.ts | 103 ++++++++++++++++++++++++++++++++++++++++++++ src/show/model.ts | 30 +++++++++++++ src/show/quality.ts | 27 ++++++++++++ src/show/tensor.ts | 10 +++++ src/util/math.ts | 32 ++++++++++++++ 5 files changed, 202 insertions(+) diff --git a/src/show/history.ts b/src/show/history.ts index f03ff5b..7d4c3ab 100644 --- a/src/show/history.ts +++ b/src/show/history.ts @@ -41,6 +41,76 @@ import {subSurface} from '../util/dom'; * to exactly 0-1 is desireable most of the time. However there may be cases, * such as when doing transfer learning, where more resolution is desired. Set * zoomToFitAccuracy to true to turn on zoomToFit for accuracy plots. + * + * ```js + * const model = tf.sequential({ + * layers: [ + * tf.layers.dense({inputShape: [784], units: 32, activation: 'relu'}), + * tf.layers.dense({units: 10, activation: 'softmax'}), + * ] + * }); + * + * model.compile({ + * optimizer: 'sgd', + * loss: 'categoricalCrossentropy', + * metrics: ['accuracy'] + * }); + * + * const data = tf.randomNormal([100, 784]); + * const labels = tf.randomUniform([100, 10]); + * + * function onBatchEnd(batch, logs) { + * console.log('Accuracy', logs.acc); + * } + * + * const surface = { name: 'show.history', tab: 'Training' }; + * // Train for 5 epochs with batch size of 32. + * const history = await model.fit(data, labels, { + * epochs: 5, + * batchSize: 32 + * }); + * + * tfvis.show.history(surface, history, ['loss', 'acc']); + * ``` + * + * ```js + * const model = tf.sequential({ + * layers: [ + * tf.layers.dense({inputShape: [784], units: 32, activation: 'relu'}), + * tf.layers.dense({units: 10, activation: 'softmax'}), + * ] + * }); + * + * model.compile({ + * optimizer: 'sgd', + * loss: 'categoricalCrossentropy', + * metrics: ['accuracy'] + * }); + * + * const data = tf.randomNormal([100, 784]); + * const labels = tf.randomUniform([100, 10]); + * + * function onBatchEnd(batch, logs) { + * console.log('Accuracy', logs.acc); + * } + * + * const surface = { name: 'show.history live', tab: 'Training' }; + * // Train for 5 epochs with batch size of 32. + * const history = []; + * await model.fit(data, labels, { + * epochs: 5, + * batchSize: 32, + * callbacks: { + * onEpochEnd: (epoch, log) => { + * history.push(log); + * tfvis.show.history(surface, history, ['loss', 'acc']); + * } + * } + * }); + * ``` + */ +/** + * @doc {heading: 'show.*', subheading: ' Model Training', namespace: 'show'} */ export async function history( container: Drawable, history: HistoryLike, metrics: string[], @@ -169,6 +239,39 @@ function getValues( * zoomToFitAccuracy to true to turn on zoomToFit for accuracy plots. * @param opts.callbacks Array of strings with callback names. Valid options * are 'onEpochEnd' and 'onBatchEnd'. Defaults to ['onEpochEnd', 'onBatchEnd']. + * + * ```js + * const model = tf.sequential({ + * layers: [ + * tf.layers.dense({inputShape: [784], units: 32, activation: 'relu'}), + * tf.layers.dense({units: 10, activation: 'softmax'}), + * ] + * }); + * + * model.compile({ + * optimizer: 'sgd', + * loss: 'categoricalCrossentropy', + * metrics: ['accuracy'] + * }); + * + * const data = tf.randomNormal([100, 784]); + * const labels = tf.randomUniform([100, 10]); + * + * function onBatchEnd(batch, logs) { + * console.log('Accuracy', logs.acc); + * } + * + * const surface = { name: 'show.fitCallbacks', tab: 'Training' }; + * // Train for 5 epochs with batch size of 32. + * model.fit(data, labels, { + * epochs: 5, + * batchSize: 32, + * callbacks: tfvis.show.fitCallbacks(surface, ['loss', 'acc']), + * }); + * ``` + */ +/** + * @doc {heading: 'show.*', subheading: ' Model Training', namespace: 'show'} */ export function fitCallbacks( container: Drawable, metrics: string[], diff --git a/src/show/model.ts b/src/show/model.ts index e3c66ec..1db3c66 100644 --- a/src/show/model.ts +++ b/src/show/model.ts @@ -31,6 +31,21 @@ import {tensorStats} from '../util/math'; * @param container A `{name: string, tab?: string}` object specifying which * surface to render to. * @param model + * + * ```js + * const model = tf.sequential({ + * layers: [ + * tf.layers.dense({inputShape: [784], units: 32, activation: 'relu'}), + * tf.layers.dense({units: 10, activation: 'softmax'}), + * ] + * }); + * + * const surface = { name: 'Model Summary', tab: 'Model Inspection'}; + * tfvis.show.modelSummary(surface, model); + * ``` + */ +/** + * @doc {heading: 'show.*', subheading: ' Model Inspection', namespace: 'show'} */ export async function modelSummary(container: Drawable, model: tf.Model) { const drawArea = getDrawArea(container); @@ -61,6 +76,21 @@ export async function modelSummary(container: Drawable, model: tf.Model) { * @param container A `{name: string, tab?: string}` object specifying which * surface to render to. * @param layer a `tf.layers.Layer` + * + * ```js + * const model = tf.sequential({ + * layers: [ + * tf.layers.dense({inputShape: [784], units: 32, activation: 'relu'}), + * tf.layers.dense({units: 10, activation: 'softmax'}), + * ] + * }); + * + * const surface = { name: 'Model Summary', tab: 'Model Inspection'}; + * tfvis.show.layer(surface, model.getLayer(undefined, 1)); + * ``` + */ +/** + * @doc {heading: 'show.*', subheading: ' Model Inspection', namespace: 'show'} */ export async function layer(container: Drawable, layer: Layer) { const drawArea = getDrawArea(container); diff --git a/src/show/quality.ts b/src/show/quality.ts index eb647d9..adc3a89 100644 --- a/src/show/quality.ts +++ b/src/show/quality.ts @@ -30,6 +30,18 @@ import {ConfusionMatrixData, Drawable} from '../types'; * generate this object. * @param classLabels An array of string labels for the classes in * `classAccuracy`. Optional. + * + * ```js + * const labels = tf.tensor1d([0, 0, 1, 2, 2, 2]); + * const predictions = tf.tensor1d([0, 0, 0, 2, 1, 1]); + * + * const result = await tfvis.metrics.perClassAccuracy(labels, predictions); + * console.log(result) + * + * const container = {name: 'Per Class Accuracy', tab: 'Evaluation'}; + * const categories = ['cat', 'dog', 'mouse']; + * await tfvis.show.perClassAccuracy(container, result, categories); + * ``` */ export async function showPerClassAccuracy( container: Drawable, @@ -62,6 +74,21 @@ export async function showPerClassAccuracy( * values. See metrics.confusionMatrix for details on how to generate this. * @param classLabels An array of string labels for the classes in * `confusionMatrix`. Optional. + * + * ```js + * const labels = tf.tensor1d([0, 0, 1, 1, 2, 2, 2, 3 ,3 ,3, 4, 4]); + * const predictions = tf.tensor1d([0, 0, 1, 0, 2, 3, 1, 3 ,4 ,3, 2, 2]); + * + * const matrix = await tfvis.metrics.confusionMatrix(labels, predictions); + * + * const container = {name: 'Confusion Matrix', tab: 'Evaluation'}; + * const categories = ['cat', 'dog', 'mouse', 'bird', 'fish']; + * await tfvis.show.confusionMatrix(container, matrix, categories); + * ``` + */ +/** + * @doc {heading: 'show.*', subheadring: 'Model Evaluation', namespace: + * 'show'} */ export async function showConfusionMatrix( container: Drawable, confusionMatrix: number[][], classLabels?: string[]) { diff --git a/src/show/tensor.ts b/src/show/tensor.ts index d56d5ea..f869254 100644 --- a/src/show/tensor.ts +++ b/src/show/tensor.ts @@ -28,6 +28,16 @@ import {tensorStats} from '../util/math'; * @param container A `{name: string, tab?: string}` object specifying which * surface to render to. * @param tensor the input tensor + * + * ```js + * const tensor = tf.tensor1d([0, 0, 0, 0, 2, 3, 4]); + * + * const surface = {name: 'Values Distribution', tab: 'Model Inspection'}; + * await tfvis.show.valuesDistribution(surface, tensor); + * ``` + */ +/** + * @doc {heading: 'show.*', subheading: ' Model Inspection', namespace: 'show'} */ export async function valuesDistribution(container: Drawable, tensor: Tensor) { const drawArea = getDrawArea(container); diff --git a/src/util/math.ts b/src/util/math.ts index 592cc8c..30774b2 100644 --- a/src/util/math.ts +++ b/src/util/math.ts @@ -159,6 +159,16 @@ export async function tensorStats(input: Tensor): Promise { * @param weights 1d tensor that is the same size as predictions. * If weights is passed in then each prediction contributes its corresponding * weight to the total value of the confusion matrix cell. + * + * ```js + * const labels = tf.tensor1d([1, 2, 4]); + * const predictions = tf.tensor1d([2, 2, 4]); + * const result = await tfvis.metrics.confusionMatrix(labels, predictions); + * console.log(result); + * ``` + */ +/** + * @doc {heading: 'metrics', namespace: 'metrics'} */ export async function confusionMatrix( labels: Tensor1D, predictions: Tensor1D, numClasses?: number, @@ -220,6 +230,17 @@ export async function confusionMatrix( * * @param labels tensor of true values * @param predictions tensor of predicted values + * + * ```js + * const labels = tf.tensor1d([0, 0, 1, 2, 2, 2]); + * const predictions = tf.tensor1d([0, 0, 0, 2, 1, 1]); + * + * const result = await tfvis.metrics.accuracy(labels, predictions); + * console.log(result) + * ``` + */ +/** + * @doc {heading: 'metrics', namespace: 'metrics'} */ export async function accuracy( labels: Tensor, predictions: Tensor): Promise { @@ -248,6 +269,17 @@ export async function accuracy( * @param numClasses Number of distinct classes. Optional. If not passed in * numClasses will equal the highest number in either labels or predictions * plus 1 + * + * ```js + * const labels = tf.tensor1d([0, 0, 1, 2, 2, 2]); + * const predictions = tf.tensor1d([0, 0, 0, 2, 1, 1]); + * + * const result = await tfvis.metrics.perClassAccuracy(labels, predictions); + * console.log(result) + * ``` + */ +/** + * @doc {heading: 'metrics', namespace: 'metrics'} */ export async function perClassAccuracy( labels: Tensor1D, predictions: Tensor1D, From 7caa94bc989dd133684928d139583cbd1f751d30 Mon Sep 17 00:00:00 2001 From: Yannick Assogba Date: Thu, 14 Feb 2019 19:13:04 -0500 Subject: [PATCH 3/9] typos --- src/show/history.ts | 4 ++-- src/show/model.ts | 4 ++-- src/show/quality.ts | 2 +- src/show/tensor.ts | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/show/history.ts b/src/show/history.ts index 7d4c3ab..a936828 100644 --- a/src/show/history.ts +++ b/src/show/history.ts @@ -110,7 +110,7 @@ import {subSurface} from '../util/dom'; * ``` */ /** - * @doc {heading: 'show.*', subheading: ' Model Training', namespace: 'show'} + * @doc {heading: 'show.*', subheading: 'Model Training', namespace: 'show'} */ export async function history( container: Drawable, history: HistoryLike, metrics: string[], @@ -271,7 +271,7 @@ function getValues( * ``` */ /** - * @doc {heading: 'show.*', subheading: ' Model Training', namespace: 'show'} + * @doc {heading: 'show.*', subheading: 'Model Training', namespace: 'show'} */ export function fitCallbacks( container: Drawable, metrics: string[], diff --git a/src/show/model.ts b/src/show/model.ts index 1db3c66..d4d13c3 100644 --- a/src/show/model.ts +++ b/src/show/model.ts @@ -45,7 +45,7 @@ import {tensorStats} from '../util/math'; * ``` */ /** - * @doc {heading: 'show.*', subheading: ' Model Inspection', namespace: 'show'} + * @doc {heading: 'show.*', subheading: 'Model Inspection', namespace: 'show'} */ export async function modelSummary(container: Drawable, model: tf.Model) { const drawArea = getDrawArea(container); @@ -90,7 +90,7 @@ export async function modelSummary(container: Drawable, model: tf.Model) { * ``` */ /** - * @doc {heading: 'show.*', subheading: ' Model Inspection', namespace: 'show'} + * @doc {heading: 'show.*', subheading: 'Model Inspection', namespace: 'show'} */ export async function layer(container: Drawable, layer: Layer) { const drawArea = getDrawArea(container); diff --git a/src/show/quality.ts b/src/show/quality.ts index adc3a89..33f7cee 100644 --- a/src/show/quality.ts +++ b/src/show/quality.ts @@ -87,7 +87,7 @@ export async function showPerClassAccuracy( * ``` */ /** - * @doc {heading: 'show.*', subheadring: 'Model Evaluation', namespace: + * @doc {heading: 'show.*', subheading: 'Model Evaluation', namespace: * 'show'} */ export async function showConfusionMatrix( diff --git a/src/show/tensor.ts b/src/show/tensor.ts index f869254..2f5aa9f 100644 --- a/src/show/tensor.ts +++ b/src/show/tensor.ts @@ -37,7 +37,7 @@ import {tensorStats} from '../util/math'; * ``` */ /** - * @doc {heading: 'show.*', subheading: ' Model Inspection', namespace: 'show'} + * @doc {heading: 'show.*', subheading: 'Model Inspection', namespace: 'show'} */ export async function valuesDistribution(container: Drawable, tensor: Tensor) { const drawArea = getDrawArea(container); From 3134315e72af86cb626adff737d6f292678769af Mon Sep 17 00:00:00 2001 From: Yannick Assogba Date: Thu, 14 Feb 2019 19:25:50 -0500 Subject: [PATCH 4/9] re-order code snippets --- src/render/barchart.ts | 23 ++++++------ src/render/confusion_matrix.ts | 51 +++++++++++++------------- src/render/heatmap.ts | 59 +++++++++++++++--------------- src/render/histogram.ts | 25 ++++++------- src/render/linechart.ts | 51 +++++++++++++------------- src/render/scatterplot.ts | 17 +++++++++ src/render/table.ts | 33 ++++++++--------- src/show/history.ts | 66 +++++++++++++++++----------------- src/show/model.ts | 18 +++++----- src/show/quality.ts | 32 +++++++++-------- src/show/tensor.ts | 9 ++--- src/util/math.ts | 42 +++++++++++----------- 12 files changed, 229 insertions(+), 197 deletions(-) diff --git a/src/render/barchart.ts b/src/render/barchart.ts index 39c25fa..7d0ac2e 100644 --- a/src/render/barchart.ts +++ b/src/render/barchart.ts @@ -25,6 +25,18 @@ import {getDrawArea, nextFrame, shallowEquals} from './render_utils'; /** * Renders a barchart. * + * ```js + * const data = [ + * { index: 0, value: 50 }, + * { index: 1, value: 100 }, + * { index: 2, value: 150 }, + * ]; + * + * // Render to visor + * const surface = { name: 'Bar chart', tab: 'Charts' }; + * tfvis.render.barchart(data, surface, {}); + * ``` + * * @param data Data in the following format, (an array of objects) * [ {index: number, value: number} ... ] * @param container An `HTMLElement` or `Surface` in which to draw the bar @@ -40,17 +52,6 @@ import {getDrawArea, nextFrame, shallowEquals} from './render_utils'; * * @returns Promise - indicates completion of rendering * - * ```js - * const data = [ - * { index: 0, value: 50 }, - * { index: 1, value: 100 }, - * { index: 2, value: 150 }, - * ]; - * - * // Render to visor - * const surface = { name: 'Bar chart', tab: 'Charts' }; - * tfvis.render.barchart(data, surface, {}); - * ``` * */ /** @doc {heading: 'render.*', namespace: 'render'} */ diff --git a/src/render/confusion_matrix.ts b/src/render/confusion_matrix.ts index 20c07b4..ebb6496 100644 --- a/src/render/confusion_matrix.ts +++ b/src/render/confusion_matrix.ts @@ -28,31 +28,6 @@ import {getDrawArea} from './render_utils'; * is perfect (i.e. only the diagonal has values) then the diagonal will always * be shaded. * - * @param data Data consists of an object with a 'values' property - * and a 'labels' property. - * { - * // a matrix of numbers representing counts for each (label, prediction) - * // pair - * values: number[][], - * - * // Human readable labels for each class in the matrix. Optional - * labels?: string[] - * } - * e.g. - * { - * values: [[80, 23], [56, 94]], - * labels: ['dog', 'cat'], - * } - * @param container An `HTMLElement` or `Surface` in which to draw the chart - * @param opts optional parameters - * @param opts.shadeDiagonal boolean that controls whether or not to color cells - * on the diagonal. Defaults to true - * @param opts.showTextOverlay boolean that controls whether or not to render - * the values of each cell as text. Defaults to true - * @param opts.width width of chart in px - * @param opts.height height of chart in px - * @param opts.fontSize fontSize in pixels for text in the chart - * * ```js * const rows = 5; * const cols = 5; @@ -88,6 +63,32 @@ import {getDrawArea} from './render_utils'; * shadeDiagonal: false * }); * ``` + * + * @param data Data consists of an object with a 'values' property + * and a 'labels' property. + * { + * // a matrix of numbers representing counts for each (label, prediction) + * // pair + * values: number[][], + * + * // Human readable labels for each class in the matrix. Optional + * labels?: string[] + * } + * e.g. + * { + * values: [[80, 23], [56, 94]], + * labels: ['dog', 'cat'], + * } + * @param container An `HTMLElement` or `Surface` in which to draw the chart + * @param opts optional parameters + * @param opts.shadeDiagonal boolean that controls whether or not to color cells + * on the diagonal. Defaults to true + * @param opts.showTextOverlay boolean that controls whether or not to render + * the values of each cell as text. Defaults to true + * @param opts.width width of chart in px + * @param opts.height height of chart in px + * @param opts.fontSize fontSize in pixels for text in the chart + * */ /** @doc {heading: 'render.*', namespace: 'render'} */ export async function renderConfusionMatrix( diff --git a/src/render/heatmap.ts b/src/render/heatmap.ts index 0c57122..5c5a017 100644 --- a/src/render/heatmap.ts +++ b/src/render/heatmap.ts @@ -26,35 +26,6 @@ import {getDrawArea} from './render_utils'; /** * Renders a heatmap. * - * @param data Data consists of an object with a 'values' property - * and a 'labels' property. - * { - * // a matrix of numbers - * values: number[][]|Tensor2D, - * - * // Human readable labels for each class in the matrix. Optional - * xLabels?: string[] - * yLabels?: string[] - * } - * e.g. - * { - * values: [[80, 23, 50], [56, 94, 39]], - * xLabels: ['dog', 'cat'], - * yLabels: ['size', 'temperature', 'agility'], - * } - * @param container An `HTMLElement` or `Surface` in which to draw the chart - * @param opts optional parameters - * @param opts.colorMap which colormap to use. One of viridis|blues|greyscale. - * Defaults to viridis - * @param opts.domain a two element array representing a custom output domain - * for the color scale. Useful if you want to plot multiple heatmaps using - * the same scale. - * @param opts.xLabel label for x axis - * @param opts.yLabel label for y axis - * @param opts.width width of chart in px - * @param opts.height height of chart in px - * @param opts.fontSize fontSize in pixels for text in the chart - * * ```js * const rows = 50; * const cols = 20; @@ -84,6 +55,36 @@ import {getDrawArea} from './render_utils'; * const surface = { name: 'Heatmap w Custom Labels', tab: 'Charts' }; * tfvis.render.heatmap(data, surface); * ``` + * + * @param data Data consists of an object with a 'values' property + * and a 'labels' property. + * { + * // a matrix of numbers + * values: number[][]|Tensor2D, + * + * // Human readable labels for each class in the matrix. Optional + * xLabels?: string[] + * yLabels?: string[] + * } + * e.g. + * { + * values: [[80, 23, 50], [56, 94, 39]], + * xLabels: ['dog', 'cat'], + * yLabels: ['size', 'temperature', 'agility'], + * } + * @param container An `HTMLElement` or `Surface` in which to draw the chart + * @param opts optional parameters + * @param opts.colorMap which colormap to use. One of viridis|blues|greyscale. + * Defaults to viridis + * @param opts.domain a two element array representing a custom output domain + * for the color scale. Useful if you want to plot multiple heatmaps using + * the same scale. + * @param opts.xLabel label for x axis + * @param opts.yLabel label for y axis + * @param opts.width width of chart in px + * @param opts.height height of chart in px + * @param opts.fontSize fontSize in pixels for text in the chart + * */ /** @doc {heading: 'render.*', namespace: 'render'} */ export async function renderHeatmap( diff --git a/src/render/histogram.ts b/src/render/histogram.ts index 0bf722e..cfb2c96 100644 --- a/src/render/histogram.ts +++ b/src/render/histogram.ts @@ -32,6 +32,19 @@ const defaultOpts = { /** * Renders a histogram of values * + * ```js + * const data = Array(100).fill(0) + * .map(x => Math.random() * 100 - (Math.random() * 50)) + * + * // Push some special values for the stats table. + * data.push(Infinity); + * data.push(NaN); + * data.push(0); + * + * const surface = { name: 'Histogram', tab: 'Charts' }; + * tfvis.render.histogram(data, surface); + * ``` + * * @param data Data in the following format: * `[ {value: number}, ... ]` or `[number]` or `TypedArray` * @param container An `HTMLElement`|`Surface` in which to draw the histogram @@ -54,18 +67,6 @@ const defaultOpts = { * numNans?: number * } * - * ```js - * const data = Array(100).fill(0) - * .map(x => Math.random() * 100 - (Math.random() * 50)) - * - * // Push some special values for the stats table. - * data.push(Infinity); - * data.push(NaN); - * data.push(0); - * - * const surface = { name: 'Histogram', tab: 'Charts' }; - * tfvis.render.histogram(data, surface); - * ``` */ /** @doc {heading: 'render.*', namespace: 'render'} */ export async function renderHistogram( diff --git a/src/render/linechart.ts b/src/render/linechart.ts index ecfc21b..047fec5 100644 --- a/src/render/linechart.ts +++ b/src/render/linechart.ts @@ -24,31 +24,6 @@ import {getDrawArea} from './render_utils'; /** * Renders a line chart * - * @param data Data in the following format - * { - * // A nested array of objects each with an x and y property, - * // one per series. - * // If you only have one series to render you can just pass an array - * // of objects with x, y properties - * values: {x: number, y: number}[][] - * - * // An array of strings with the names of each series passed above. - * // Optional - * series: string[] - * } - * @param container An HTMLElement in which to draw the chart - * @param opts optional parameters - * @param opts.width width of chart in px - * @param opts.height height of chart in px - * @param opts.xLabel label for x axis - * @param opts.yLabel label for y axis - * @param opts.fontSize fontSize in pixels for text in the chart - * @param opts.zoomToFit a boolean indicating whether to allow non-zero - * baselines setting this to true allows the line chart to take up more room in - * the plot. - * @param opts.yAxisDomain array of two numbers indicating the domain of the y - * axis. This is overriden by zoomToFit - * * ```js * const series1 = Array(100).fill(0) * .map(y => Math.random() * 100 - (Math.random() * 50)) @@ -76,6 +51,32 @@ import {getDrawArea} from './render_utils'; * const surface = { name: 'Zoomed Line Chart', tab: 'Charts' }; * tfvis.render.linechart(data, surface, { zoomToFit: true }); * ``` + * + * @param data Data in the following format + * { + * // A nested array of objects each with an x and y property, + * // one per series. + * // If you only have one series to render you can just pass an array + * // of objects with x, y properties + * values: {x: number, y: number}[][] + * + * // An array of strings with the names of each series passed above. + * // Optional + * series: string[] + * } + * @param container An HTMLElement in which to draw the chart + * @param opts optional parameters + * @param opts.width width of chart in px + * @param opts.height height of chart in px + * @param opts.xLabel label for x axis + * @param opts.yLabel label for y axis + * @param opts.fontSize fontSize in pixels for text in the chart + * @param opts.zoomToFit a boolean indicating whether to allow non-zero + * baselines setting this to true allows the line chart to take up more room in + * the plot. + * @param opts.yAxisDomain array of two numbers indicating the domain of the y + * axis. This is overriden by zoomToFit + * */ /** @doc {heading: 'render.*', namespace: 'render'} */ export async function renderLinechart( diff --git a/src/render/scatterplot.ts b/src/render/scatterplot.ts index 81ff589..900edb3 100644 --- a/src/render/scatterplot.ts +++ b/src/render/scatterplot.ts @@ -24,6 +24,23 @@ import {getDrawArea} from './render_utils'; /** * Renders a scatter plot * + * ```js + * const headers = [ + * 'Col 1', + * 'Col 2', + * 'Col 3', + * ]; + * + * const values = [ + * [1, 2, 3], + * ['4', '5', '6'], + * ['strong>7', true, false], + * ]; + * + * const surface = { name: 'Table', tab: 'Charts' }; + * tfvis.render.table({ headers, values }, surface); + * ``` + * * @param data Data in the following format * { * // A nested array of objects each with an x and y property, diff --git a/src/render/table.ts b/src/render/table.ts index b4778cd..4859e0c 100644 --- a/src/render/table.ts +++ b/src/render/table.ts @@ -25,6 +25,23 @@ import {getDrawArea} from './render_utils'; /** * Renders a table * + * ```js + * const headers = [ + * 'Col 1', + * 'Col 2', + * 'Col 3', + * ]; + * + * const values = [ + * [1, 2, 3], + * ['4', '5', '6'], + * ['strong>7', true, false], + * ]; + * + * const surface = { name: 'Table', tab: 'Charts' }; + * tfvis.render.table({ headers, values }, surface); + * ``` + * * @param data Data in the following format * { * headers: string[], @@ -42,22 +59,6 @@ import {getDrawArea} from './render_utils'; * at will. * @param opts.fontSize fontSize in pixels for text in the chart. * - * ```js - * const headers = [ - * 'Col 1', - * 'Col 2', - * 'Col 3', - * ]; - * - * const values = [ - * [1, 2, 3], - * ['4', '5', '6'], - * ['strong>7', true, false], - * ]; - * - * const surface = { name: 'Table', tab: 'Charts' }; - * tfvis.render.table({ headers, values }, surface); - * ``` */ /** @doc {heading: 'render.*', namespace: 'render'} */ export function renderTable( diff --git a/src/show/history.ts b/src/show/history.ts index a936828..86d2d1a 100644 --- a/src/show/history.ts +++ b/src/show/history.ts @@ -25,23 +25,6 @@ import {subSurface} from '../util/dom'; /** * Renders a tf.Model training 'History'. * - * @param container A `{name: string, tab?: string}` object specifying which - * surface to render to. - * @param history A history like object. Either a tfjs-layers `History` object - * or an array of tfjs-layers `Logs` objects. - * @param metrics An array of strings for each metric to plot from the history - * object. Using this allows you to control which metrics appear on the same - * plot. - * @param opts Optional parameters for the line charts. See the opts parameter - * for render.linechart for details. Notably for 'accuracy' related plots - * the domain of the yAxis will always by 0-1, i.e. zoomToFit and yAxisDomain - * options are ignored. - * @param opts.zoomToFitAccuracy a boolean controlling whether to 'zoomToFit' - * accuracy plots as well. Constraining the y axis domain of an accuracy plot - * to exactly 0-1 is desireable most of the time. However there may be cases, - * such as when doing transfer learning, where more resolution is desired. Set - * zoomToFitAccuracy to true to turn on zoomToFit for accuracy plots. - * * ```js * const model = tf.sequential({ * layers: [ @@ -108,6 +91,24 @@ import {subSurface} from '../util/dom'; * } * }); * ``` + * + * @param container A `{name: string, tab?: string}` object specifying which + * surface to render to. + * @param history A history like object. Either a tfjs-layers `History` object + * or an array of tfjs-layers `Logs` objects. + * @param metrics An array of strings for each metric to plot from the history + * object. Using this allows you to control which metrics appear on the same + * plot. + * @param opts Optional parameters for the line charts. See the opts parameter + * for render.linechart for details. Notably for 'accuracy' related plots + * the domain of the yAxis will always by 0-1, i.e. zoomToFit and yAxisDomain + * options are ignored. + * @param opts.zoomToFitAccuracy a boolean controlling whether to 'zoomToFit' + * accuracy plots as well. Constraining the y axis domain of an accuracy plot + * to exactly 0-1 is desireable most of the time. However there may be cases, + * such as when doing transfer learning, where more resolution is desired. Set + * zoomToFitAccuracy to true to turn on zoomToFit for accuracy plots. + * */ /** * @doc {heading: 'show.*', subheading: 'Model Training', namespace: 'show'} @@ -225,21 +226,6 @@ function getValues( * Returns a collection of callbacks to pass to tf.Model.fit. Callbacks are * returned for the following events, `onBatchEnd` & `onEpochEnd`. * - * @param container A `{name: string, tab?: string}` object specifying which - * surface to render to. - * @param metrics List of metrics to plot. - * @param opts Optional parameters for the line charts. See the opts parameter - * for render.linechart for details. Notably for 'accuracy' related plots - * the domain of the yAxis will always by 0-1, i.e. zoomToFit and yAxisDomain - * options are ignored. - * @param opts.zoomToFitAccuracy a boolean controlling whether to 'zoomToFit' - * accuracy plots as well. Constraining the y axis domain of an accuracy plot - * to exactly 0-1 is desireable most of the time. However there may be cases, - * such as when doing transfer learning, where more resolution is desired. Set - * zoomToFitAccuracy to true to turn on zoomToFit for accuracy plots. - * @param opts.callbacks Array of strings with callback names. Valid options - * are 'onEpochEnd' and 'onBatchEnd'. Defaults to ['onEpochEnd', 'onBatchEnd']. - * * ```js * const model = tf.sequential({ * layers: [ @@ -269,6 +255,22 @@ function getValues( * callbacks: tfvis.show.fitCallbacks(surface, ['loss', 'acc']), * }); * ``` + * + * @param container A `{name: string, tab?: string}` object specifying which + * surface to render to. + * @param metrics List of metrics to plot. + * @param opts Optional parameters for the line charts. See the opts parameter + * for render.linechart for details. Notably for 'accuracy' related plots + * the domain of the yAxis will always by 0-1, i.e. zoomToFit and yAxisDomain + * options are ignored. + * @param opts.zoomToFitAccuracy a boolean controlling whether to 'zoomToFit' + * accuracy plots as well. Constraining the y axis domain of an accuracy plot + * to exactly 0-1 is desireable most of the time. However there may be cases, + * such as when doing transfer learning, where more resolution is desired. Set + * zoomToFitAccuracy to true to turn on zoomToFit for accuracy plots. + * @param opts.callbacks Array of strings with callback names. Valid options + * are 'onEpochEnd' and 'onBatchEnd'. Defaults to ['onEpochEnd', 'onBatchEnd']. + * */ /** * @doc {heading: 'show.*', subheading: 'Model Training', namespace: 'show'} diff --git a/src/show/model.ts b/src/show/model.ts index d4d13c3..56cff48 100644 --- a/src/show/model.ts +++ b/src/show/model.ts @@ -28,10 +28,6 @@ import {tensorStats} from '../util/math'; /** * Renders a summary of a tf.Model. Displays a table with layer information. * - * @param container A `{name: string, tab?: string}` object specifying which - * surface to render to. - * @param model - * * ```js * const model = tf.sequential({ * layers: [ @@ -43,6 +39,11 @@ import {tensorStats} from '../util/math'; * const surface = { name: 'Model Summary', tab: 'Model Inspection'}; * tfvis.show.modelSummary(surface, model); * ``` + * + * @param container A `{name: string, tab?: string}` object specifying which + * surface to render to. + * @param model + * */ /** * @doc {heading: 'show.*', subheading: 'Model Inspection', namespace: 'show'} @@ -73,10 +74,6 @@ export async function modelSummary(container: Drawable, model: tf.Model) { * Renders summary information about a layer and a histogram of parameters in * that layer. * - * @param container A `{name: string, tab?: string}` object specifying which - * surface to render to. - * @param layer a `tf.layers.Layer` - * * ```js * const model = tf.sequential({ * layers: [ @@ -88,6 +85,11 @@ export async function modelSummary(container: Drawable, model: tf.Model) { * const surface = { name: 'Model Summary', tab: 'Model Inspection'}; * tfvis.show.layer(surface, model.getLayer(undefined, 1)); * ``` + * + * @param container A `{name: string, tab?: string}` object specifying which + * surface to render to. + * @param layer a `tf.layers.Layer` + * */ /** * @doc {heading: 'show.*', subheading: 'Model Inspection', namespace: 'show'} diff --git a/src/show/quality.ts b/src/show/quality.ts index 33f7cee..f8fc6d8 100644 --- a/src/show/quality.ts +++ b/src/show/quality.ts @@ -23,14 +23,6 @@ import {ConfusionMatrixData, Drawable} from '../types'; /** * Renders a per class accuracy table for classification task evaluation * - * @param container A `{name: string, tab?: string}` object specifying which - * surface to render to. - * @param classAccuracy An `Array<{accuracy: number, count: number}>` array with - * the accuracy data. See metrics.perClassAccuracy for details on how to - * generate this object. - * @param classLabels An array of string labels for the classes in - * `classAccuracy`. Optional. - * * ```js * const labels = tf.tensor1d([0, 0, 1, 2, 2, 2]); * const predictions = tf.tensor1d([0, 0, 0, 2, 1, 1]); @@ -42,6 +34,15 @@ import {ConfusionMatrixData, Drawable} from '../types'; * const categories = ['cat', 'dog', 'mouse']; * await tfvis.show.perClassAccuracy(container, result, categories); * ``` + * + * @param container A `{name: string, tab?: string}` object specifying which + * surface to render to. + * @param classAccuracy An `Array<{accuracy: number, count: number}>` array with + * the accuracy data. See metrics.perClassAccuracy for details on how to + * generate this object. + * @param classLabels An array of string labels for the classes in + * `classAccuracy`. Optional. + * */ export async function showPerClassAccuracy( container: Drawable, @@ -68,13 +69,6 @@ export async function showPerClassAccuracy( /** * Renders a confusion matrix for classification task evaluation * - * @param container A `{name: string, tab?: string}` object specifying which - * surface to render to. - * @param confusionMatrix A nested array of numbers with the confusion matrix - * values. See metrics.confusionMatrix for details on how to generate this. - * @param classLabels An array of string labels for the classes in - * `confusionMatrix`. Optional. - * * ```js * const labels = tf.tensor1d([0, 0, 1, 1, 2, 2, 2, 3 ,3 ,3, 4, 4]); * const predictions = tf.tensor1d([0, 0, 1, 0, 2, 3, 1, 3 ,4 ,3, 2, 2]); @@ -85,6 +79,14 @@ export async function showPerClassAccuracy( * const categories = ['cat', 'dog', 'mouse', 'bird', 'fish']; * await tfvis.show.confusionMatrix(container, matrix, categories); * ``` + * + * @param container A `{name: string, tab?: string}` object specifying which + * surface to render to. + * @param confusionMatrix A nested array of numbers with the confusion matrix + * values. See metrics.confusionMatrix for details on how to generate this. + * @param classLabels An array of string labels for the classes in + * `confusionMatrix`. Optional. + * */ /** * @doc {heading: 'show.*', subheading: 'Model Evaluation', namespace: diff --git a/src/show/tensor.ts b/src/show/tensor.ts index 2f5aa9f..9fddd9d 100644 --- a/src/show/tensor.ts +++ b/src/show/tensor.ts @@ -25,16 +25,17 @@ import {tensorStats} from '../util/math'; /** * Shows a histogram with the distribution of all values in a given tensor. * - * @param container A `{name: string, tab?: string}` object specifying which - * surface to render to. - * @param tensor the input tensor - * * ```js * const tensor = tf.tensor1d([0, 0, 0, 0, 2, 3, 4]); * * const surface = {name: 'Values Distribution', tab: 'Model Inspection'}; * await tfvis.show.valuesDistribution(surface, tensor); * ``` + * + * @param container A `{name: string, tab?: string}` object specifying which + * surface to render to. + * @param tensor the input tensor + * */ /** * @doc {heading: 'show.*', subheading: 'Model Inspection', namespace: 'show'} diff --git a/src/util/math.ts b/src/util/math.ts index 30774b2..f983f56 100644 --- a/src/util/math.ts +++ b/src/util/math.ts @@ -151,6 +151,13 @@ export async function tensorStats(input: Tensor): Promise { * labels and predictions should correspond to some output class. It is assumed * that these values go from 0 to numClasses - 1. * + * ```js + * const labels = tf.tensor1d([1, 2, 4]); + * const predictions = tf.tensor1d([2, 2, 4]); + * const result = await tfvis.metrics.confusionMatrix(labels, predictions); + * console.log(result); + * ``` + * * @param labels 1D tensor of true values * @param predictions 1D tensor of predicted values * @param numClasses Number of distinct classes. Optional. If not passed in @@ -160,15 +167,9 @@ export async function tensorStats(input: Tensor): Promise { * If weights is passed in then each prediction contributes its corresponding * weight to the total value of the confusion matrix cell. * - * ```js - * const labels = tf.tensor1d([1, 2, 4]); - * const predictions = tf.tensor1d([2, 2, 4]); - * const result = await tfvis.metrics.confusionMatrix(labels, predictions); - * console.log(result); - * ``` */ /** - * @doc {heading: 'metrics', namespace: 'metrics'} + * @doc {heading: 'Metrics', namespace: 'metrics'} */ export async function confusionMatrix( labels: Tensor1D, predictions: Tensor1D, numClasses?: number, @@ -228,9 +229,6 @@ export async function confusionMatrix( /** * Computes how often predictions matches labels * - * @param labels tensor of true values - * @param predictions tensor of predicted values - * * ```js * const labels = tf.tensor1d([0, 0, 1, 2, 2, 2]); * const predictions = tf.tensor1d([0, 0, 0, 2, 1, 1]); @@ -238,9 +236,12 @@ export async function confusionMatrix( * const result = await tfvis.metrics.accuracy(labels, predictions); * console.log(result) * ``` + * + * @param labels tensor of true values + * @param predictions tensor of predicted values */ /** - * @doc {heading: 'metrics', namespace: 'metrics'} + * @doc {heading: 'Metrics', namespace: 'metrics'} */ export async function accuracy( labels: Tensor, predictions: Tensor): Promise { @@ -261,25 +262,26 @@ export async function accuracy( * labels and predictions should correspond to some output class. It is assumed * that these values go from 0 to numClasses - 1. * + * ```js + * const labels = tf.tensor1d([0, 0, 1, 2, 2, 2]); + * const predictions = tf.tensor1d([0, 0, 0, 2, 1, 1]); + * + * const result = await tfvis.metrics.perClassAccuracy(labels, predictions); + * console.log(result) + * ``` + * * Returns an array of objects that each have an an `accuracy` and a `count` * property for each class. * + * * @param labels 1D tensor of true values * @param predictions 1D tensor of predicted values * @param numClasses Number of distinct classes. Optional. If not passed in * numClasses will equal the highest number in either labels or predictions * plus 1 - * - * ```js - * const labels = tf.tensor1d([0, 0, 1, 2, 2, 2]); - * const predictions = tf.tensor1d([0, 0, 0, 2, 1, 1]); - * - * const result = await tfvis.metrics.perClassAccuracy(labels, predictions); - * console.log(result) - * ``` */ /** - * @doc {heading: 'metrics', namespace: 'metrics'} + * @doc {heading: 'Metrics', namespace: 'metrics'} */ export async function perClassAccuracy( labels: Tensor1D, predictions: Tensor1D, From c7319a659862350bc53c7c739bdb301f459b3827 Mon Sep 17 00:00:00 2001 From: Yannick Assogba Date: Thu, 14 Feb 2019 20:09:33 -0500 Subject: [PATCH 5/9] save --- src/render/barchart.ts | 2 +- src/render/confusion_matrix.ts | 5 ++--- src/render/heatmap.ts | 2 +- src/render/histogram.ts | 2 +- src/render/linechart.ts | 2 +- src/render/scatterplot.ts | 40 ++++++++++------------------------ src/render/table.ts | 2 +- src/show/history.ts | 6 +++-- src/show/model.ts | 8 ++++--- src/show/quality.ts | 2 +- src/show/tensor.ts | 3 ++- src/util/math.ts | 4 ++-- 12 files changed, 33 insertions(+), 45 deletions(-) diff --git a/src/render/barchart.ts b/src/render/barchart.ts index 7d0ac2e..52259ce 100644 --- a/src/render/barchart.ts +++ b/src/render/barchart.ts @@ -54,7 +54,7 @@ import {getDrawArea, nextFrame, shallowEquals} from './render_utils'; * * */ -/** @doc {heading: 'render.*', namespace: 'render'} */ +/** @doc {heading: 'Charts', namespace: 'render'} */ export async function renderBarchart( data: Array<{index: number; value: number;}>, container: Drawable, opts: VisOptions = {}): Promise { diff --git a/src/render/confusion_matrix.ts b/src/render/confusion_matrix.ts index ebb6496..736fb8e 100644 --- a/src/render/confusion_matrix.ts +++ b/src/render/confusion_matrix.ts @@ -51,13 +51,12 @@ import {getDrawArea} from './render_utils'; * * const data = { * values: [[4, 2, 8], [1, 7, 2], [3, 3, 20]], - * // We also generate 'labels' if none are passed. * } * * // Render to visor * const surface = { * name: 'Confusion Matrix with Excluded Diagonal', tab: 'Charts' - * }); + * }; * * tfvis.render.confusionMatrix(data, surface, { * shadeDiagonal: false @@ -90,7 +89,7 @@ import {getDrawArea} from './render_utils'; * @param opts.fontSize fontSize in pixels for text in the chart * */ -/** @doc {heading: 'render.*', namespace: 'render'} */ +/** @doc {heading: 'Charts', namespace: 'render'} */ export async function renderConfusionMatrix( data: ConfusionMatrixData, container: Drawable, opts: VisOptions& diff --git a/src/render/heatmap.ts b/src/render/heatmap.ts index 5c5a017..e9739a3 100644 --- a/src/render/heatmap.ts +++ b/src/render/heatmap.ts @@ -86,7 +86,7 @@ import {getDrawArea} from './render_utils'; * @param opts.fontSize fontSize in pixels for text in the chart * */ -/** @doc {heading: 'render.*', namespace: 'render'} */ +/** @doc {heading: 'Charts', namespace: 'render'} */ export async function renderHeatmap( data: HeatmapData, container: Drawable, opts: HeatmapOptions = {}): Promise { diff --git a/src/render/histogram.ts b/src/render/histogram.ts index cfb2c96..67338cc 100644 --- a/src/render/histogram.ts +++ b/src/render/histogram.ts @@ -68,7 +68,7 @@ const defaultOpts = { * } * */ -/** @doc {heading: 'render.*', namespace: 'render'} */ +/** @doc {heading: 'Charts', namespace: 'render'} */ export async function renderHistogram( data: Array<{value: number}>|number[]|TypedArray, container: HTMLElement, opts: HistogramOpts = {}) { diff --git a/src/render/linechart.ts b/src/render/linechart.ts index 047fec5..88040af 100644 --- a/src/render/linechart.ts +++ b/src/render/linechart.ts @@ -78,7 +78,7 @@ import {getDrawArea} from './render_utils'; * axis. This is overriden by zoomToFit * */ -/** @doc {heading: 'render.*', namespace: 'render'} */ +/** @doc {heading: 'Charts', namespace: 'render'} */ export async function renderLinechart( data: {values: Point2D[][]|Point2D[], series?: string[]}, container: Drawable, opts: XYPlotOptions = {}): Promise { diff --git a/src/render/scatterplot.ts b/src/render/scatterplot.ts index 900edb3..501b62d 100644 --- a/src/render/scatterplot.ts +++ b/src/render/scatterplot.ts @@ -25,20 +25,19 @@ import {getDrawArea} from './render_utils'; * Renders a scatter plot * * ```js - * const headers = [ - * 'Col 1', - * 'Col 2', - * 'Col 3', - * ]; + * const series1 = Array(100).fill(0) + * .map(y => Math.random() * 100 - (Math.random() * 50)) + * .map((y, x) => ({ x, y, })); * - * const values = [ - * [1, 2, 3], - * ['4', '5', '6'], - * ['strong>7', true, false], - * ]; + * const series2 = Array(100).fill(0) + * .map(y => Math.random() * 100 - (Math.random() * 150)) + * .map((y, x) => ({ x, y, })); * - * const surface = { name: 'Table', tab: 'Charts' }; - * tfvis.render.table({ headers, values }, surface); + * const series = ['First', 'Second']; + * const data = { values: [series1, series2], series } + * + * const surface = { name: 'Scatterplot', tab: 'Charts' }; + * tfvis.render.scatterplot(data, surface); * ``` * * @param data Data in the following format @@ -68,23 +67,8 @@ import {getDrawArea} from './render_utils'; * @param opts.yAxisDomain array of two numbers indicating the domain of the y * axis. This is overriden by zoomToFit * - * ```js - * const series1 = Array(100).fill(0) - * .map(y => Math.random() * 100 - (Math.random() * 50)) - * .map((y, x) => ({ x, y, })); - * - * const series2 = Array(100).fill(0) - * .map(y => Math.random() * 100 - (Math.random() * 150)) - * .map((y, x) => ({ x, y, })); - * - * const series = ['First', 'Second']; - * const data = { values: [series1, series2], series } - * - * const surface = { name: 'Scatterplot', tab: 'Charts' }; - * tfvis.render.scatterplot(data, surface); - * ``` */ -/** @doc {heading: 'render.*', namespace: 'render'} */ +/** @doc {heading: 'Charts', namespace: 'render'} */ export async function renderScatterplot( data: {values: Point2D[][]|Point2D[], series?: string[]}, container: Drawable, opts: XYPlotOptions = {}): Promise { diff --git a/src/render/table.ts b/src/render/table.ts index 4859e0c..200aa9b 100644 --- a/src/render/table.ts +++ b/src/render/table.ts @@ -60,7 +60,7 @@ import {getDrawArea} from './render_utils'; * @param opts.fontSize fontSize in pixels for text in the chart. * */ -/** @doc {heading: 'render.*', namespace: 'render'} */ +/** @doc {heading: 'Charts', namespace: 'render'} */ export function renderTable( // tslint:disable-next-line:no-any data: {headers: string[], values: any[][]}, container: Drawable, diff --git a/src/show/history.ts b/src/show/history.ts index 86d2d1a..2cfb5f8 100644 --- a/src/show/history.ts +++ b/src/show/history.ts @@ -111,7 +111,8 @@ import {subSurface} from '../util/dom'; * */ /** - * @doc {heading: 'show.*', subheading: 'Model Training', namespace: 'show'} + * @doc {heading: 'Models & Tensors', subheading: 'Model Training', namespace: + * 'show'} */ export async function history( container: Drawable, history: HistoryLike, metrics: string[], @@ -273,7 +274,8 @@ function getValues( * */ /** - * @doc {heading: 'show.*', subheading: 'Model Training', namespace: 'show'} + * @doc {heading: 'Models & Tensors', subheading: 'Model Training', namespace: + * 'show'} */ export function fitCallbacks( container: Drawable, metrics: string[], diff --git a/src/show/model.ts b/src/show/model.ts index 56cff48..2569e7d 100644 --- a/src/show/model.ts +++ b/src/show/model.ts @@ -46,7 +46,8 @@ import {tensorStats} from '../util/math'; * */ /** - * @doc {heading: 'show.*', subheading: 'Model Inspection', namespace: 'show'} + * @doc {heading: 'Models & Tensors', subheading: 'Model Inspection', namespace: + * 'show'} */ export async function modelSummary(container: Drawable, model: tf.Model) { const drawArea = getDrawArea(container); @@ -82,7 +83,7 @@ export async function modelSummary(container: Drawable, model: tf.Model) { * ] * }); * - * const surface = { name: 'Model Summary', tab: 'Model Inspection'}; + * const surface = { name: 'Layer Summary', tab: 'Model Inspection'}; * tfvis.show.layer(surface, model.getLayer(undefined, 1)); * ``` * @@ -92,7 +93,8 @@ export async function modelSummary(container: Drawable, model: tf.Model) { * */ /** - * @doc {heading: 'show.*', subheading: 'Model Inspection', namespace: 'show'} + * @doc {heading: 'Models & Tensors', subheading: 'Model Inspection', namespace: + * 'show'} */ export async function layer(container: Drawable, layer: Layer) { const drawArea = getDrawArea(container); diff --git a/src/show/quality.ts b/src/show/quality.ts index f8fc6d8..03c25dc 100644 --- a/src/show/quality.ts +++ b/src/show/quality.ts @@ -89,7 +89,7 @@ export async function showPerClassAccuracy( * */ /** - * @doc {heading: 'show.*', subheading: 'Model Evaluation', namespace: + * @doc {heading: 'Models & Tensors', subheading: 'Model Evaluation', namespace: * 'show'} */ export async function showConfusionMatrix( diff --git a/src/show/tensor.ts b/src/show/tensor.ts index 9fddd9d..c8abe19 100644 --- a/src/show/tensor.ts +++ b/src/show/tensor.ts @@ -38,7 +38,8 @@ import {tensorStats} from '../util/math'; * */ /** - * @doc {heading: 'show.*', subheading: 'Model Inspection', namespace: 'show'} + * @doc {heading: 'Models & Tensors', subheading: 'Model Inspection', namespace: + * 'show'} */ export async function valuesDistribution(container: Drawable, tensor: Tensor) { const drawArea = getDrawArea(container); diff --git a/src/util/math.ts b/src/util/math.ts index f983f56..4847392 100644 --- a/src/util/math.ts +++ b/src/util/math.ts @@ -155,7 +155,7 @@ export async function tensorStats(input: Tensor): Promise { * const labels = tf.tensor1d([1, 2, 4]); * const predictions = tf.tensor1d([2, 2, 4]); * const result = await tfvis.metrics.confusionMatrix(labels, predictions); - * console.log(result); + * console.log(JSON.stringify(result, null, 2)) * ``` * * @param labels 1D tensor of true values @@ -267,7 +267,7 @@ export async function accuracy( * const predictions = tf.tensor1d([0, 0, 0, 2, 1, 1]); * * const result = await tfvis.metrics.perClassAccuracy(labels, predictions); - * console.log(result) + * console.log(JSON.stringify(result, null, 2)) * ``` * * Returns an array of objects that each have an an `accuracy` and a `count` From d6efc1baec17d01dfee9b83cc44718867d726547 Mon Sep 17 00:00:00 2001 From: Yannick Assogba Date: Fri, 22 Feb 2019 11:44:23 -0500 Subject: [PATCH 6/9] make visor a class rather than an interface. add docs. --- src/types.ts | 61 ----------------- src/visor.ts | 187 +++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 143 insertions(+), 105 deletions(-) diff --git a/src/types.ts b/src/types.ts index b1cc532..4ceddcc 100644 --- a/src/types.ts +++ b/src/types.ts @@ -19,67 +19,6 @@ import {Tensor2D} from '@tensorflow/tfjs'; // Types shared across the project and that users will commonly interact with -/** - * Visor public API - */ -export interface Visor { - /** - * The containing HTMLElement - */ - el: HTMLElement; - - /** - * Returns a surface, creating one if necessary - */ - surface: (options: SurfaceInfo) => Surface; - - /** - * Returns true if the visor is in fullscreen mode. Note that the visor - * may be in a closed state even if it is in fullscreen mode - */ - isFullscreen: () => boolean; - - /** - * Returns true if the visor is currently open/visible false otherwise - */ - isOpen: () => boolean; - - /** - * Opens the visor - */ - open: () => void; - - /** - * Closes the visor - */ - close: () => void; - - /** - * toggles the visor open and closed - */ - toggle: () => void; - - /** - * toggles the fullscreen mode of the visor - */ - toggleFullScreen: () => void; - - /** - * Unbinds the default keyboard shortcuts - */ - unbindKeys: () => void; - - /** - * Binds the default keyboard shortcuts - */ - bindKeys: () => void; - - /** - * Set the current tab - */ - setActiveTab: (tabName: string) => void; -} - /** * The public api of a 'surface' */ diff --git a/src/visor.ts b/src/visor.ts index 0d355fc..3e9b2dc 100644 --- a/src/visor.ts +++ b/src/visor.ts @@ -16,7 +16,7 @@ */ import {VisorComponent} from './components/visor'; -import {SurfaceInfo, SurfaceInfoStrict, Visor} from './types'; +import {SurfaceInfo, SurfaceInfoStrict} from './types'; let visorSingleton: Visor; const DEFAULT_TAB = 'Visor'; @@ -25,9 +25,13 @@ const VISOR_CONTAINER_ID = 'tfjs-visor-container'; /** * The primary interface to the visor is the visor() function. * - * This returns a singleton object with the public API of the visor. The + * This returns a singleton instance of the Visor class. The * singleton object will be replaced if the visor is removed from the DOM for * some reason. + * + */ +/** + * @doc {heading: 'Visor & Surfaces'} */ export function visor(): Visor { if (typeof document === 'undefined') { @@ -67,50 +71,145 @@ export function visor(): Visor { const visorComponentInstance: VisorComponent = renderVisor(visorEl, surfaceList); - // Singleton visor instance. Implements public API of the visor. - visorSingleton = { - el: visorEl, - surface: (options: SurfaceInfo) => { - const {name} = options; - const tab = options.tab == null ? DEFAULT_TAB : options.tab; + visorSingleton = + new Visor(visorComponentInstance, visorEl, surfaceList, renderVisor); + + return visorSingleton; +} + +/** + * An instance of the visor. An instance of this class is created using the + * `visor()` function. + */ +/** + * @doc {heading: 'Visor & Surfaces', namespace: 'visor()'} + */ +export class Visor { + private visorComponent: VisorComponent; + private surfaceList: Map; + private renderVisor: + (domNode: HTMLElement, + surfaceList: Map) => VisorComponent; + + /** + * The underlying html element of the visor. + */ + public el: HTMLElement; + + constructor( + visorComponent: VisorComponent, visorEl: HTMLElement, + surfaceList: Map, + renderVisor: + (domNode: HTMLElement, + surfaceList: Map) => VisorComponent) { + this.visorComponent = visorComponent; + this.el = visorEl; + this.surfaceList = surfaceList; + this.renderVisor = renderVisor; + } + + /** + * Creates a surface on the visor + * + * Most methods in tfjs-vis that take a surface also take a SurfaceInfo + * so you rarely need to call this method unless you want to make a custom + * plot. + * + * @param options + */ + /** + * @doc {heading: 'Visor & Surfaces', subheading: 'Visor Methods'} + */ + surface(options: SurfaceInfo) { + const {name} = options; + const tab = options.tab == null ? DEFAULT_TAB : options.tab; - if (name == null || + if (name == null || + // tslint:disable-next-line + !(typeof name === 'string' || name as any instanceof String)) { + throw new Error( // tslint:disable-next-line - !(typeof name === 'string' || name as any instanceof String)) { - throw new Error( - // tslint:disable-next-line - 'You must pass a config object with a \'name\' property to create or retrieve a surface'); - } - - const finalOptions: SurfaceInfoStrict = { - ...options, - tab, - }; - - const key = `${name}-${tab}`; - if (!surfaceList.has(key)) { - surfaceList.set(key, finalOptions); - } - - renderVisor(visorEl as HTMLElement, surfaceList); - return visorComponentInstance.getSurface(name, tab); - }, - isFullscreen: () => visorComponentInstance.isFullscreen(), - isOpen: () => visorComponentInstance.isOpen(), - close: () => visorComponentInstance.close(), - open: () => visorComponentInstance.open(), - toggle: () => visorComponentInstance.toggle(), - toggleFullScreen: () => visorComponentInstance.toggleFullScreen(), - bindKeys: () => visorComponentInstance.bindKeys(), - unbindKeys: () => visorComponentInstance.unbindKeys(), - setActiveTab: (tabName: string) => { - const tabs = visorComponentInstance.state.tabs; - if (!tabs.has(tabName)) { - throw new Error(`Tab '${tabName}' does not exist`); - } - visorComponentInstance.setState({activeTab: tabName}); + 'You must pass a config object with a \'name\' property to create or retrieve a surface'); } - }; - return visorSingleton; + const finalOptions: SurfaceInfoStrict = { + ...options, + tab, + }; + + const key = `${name}-${tab}`; + if (!this.surfaceList.has(key)) { + this.surfaceList.set(key, finalOptions); + } + + this.renderVisor(this.el as HTMLElement, this.surfaceList); + return this.visorComponent.getSurface(name, tab); + } + + /** + * @doc {heading: 'Visor & Surfaces', subheading: 'Visor Methods'} + */ + isFullscreen() { + return this.visorComponent.isFullscreen(); + } + + /** + * @doc {heading: 'Visor & Surfaces', subheading: 'Visor Methods'} + */ + isOpen() { + return this.visorComponent.isOpen(); + } + + /** + * @doc {heading: 'Visor & Surfaces', subheading: 'Visor Methods'} + */ + close() { + return this.visorComponent.close(); + } + + /** + * @doc {heading: 'Visor & Surfaces', subheading: 'Visor Methods'} + */ + open() { + return this.visorComponent.open(); + } + + /** + * @doc {heading: 'Visor & Surfaces', subheading: 'Visor Methods'} + */ + toggle() { + return this.visorComponent.toggle(); + } + + /** + * @doc {heading: 'Visor & Surfaces', subheading: 'Visor Methods'} + */ + toggleFullScreen() { + return this.visorComponent.toggleFullScreen(); + } + + /** + * @doc {heading: 'Visor & Surfaces', subheading: 'Visor Methods'} + */ + bindKeys() { + return this.visorComponent.bindKeys(); + } + + /** + * @doc {heading: 'Visor & Surfaces', subheading: 'Visor Methods'} + */ + unbindKeys() { + return this.visorComponent.unbindKeys(); + } + + /** + * @doc {heading: 'Visor & Surfaces', subheading: 'Visor Methods'} + */ + setActiveTab(tabName: string) { + const tabs = this.visorComponent.state.tabs; + if (!tabs.has(tabName)) { + throw new Error(`Tab '${tabName}' does not exist`); + } + this.visorComponent.setState({activeTab: tabName}); + } } From 4743f64545ccfa827d3b2547898b81ebdfdf4b61 Mon Sep 17 00:00:00 2001 From: Yannick Assogba Date: Fri, 22 Feb 2019 11:47:30 -0500 Subject: [PATCH 7/9] save --- src/visor.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/visor.ts b/src/visor.ts index 3e9b2dc..820d55c 100644 --- a/src/visor.ts +++ b/src/visor.ts @@ -82,7 +82,7 @@ export function visor(): Visor { * `visor()` function. */ /** - * @doc {heading: 'Visor & Surfaces', namespace: 'visor()'} + * @doc {heading: 'Visor & Surfaces', subheading: 'Visor Methods'} */ export class Visor { private visorComponent: VisorComponent; From eb2ee9d558d3174a81e1772d2af0b075b353d07d Mon Sep 17 00:00:00 2001 From: Yannick Assogba Date: Fri, 22 Feb 2019 13:51:21 -0500 Subject: [PATCH 8/9] save --- src/visor.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/visor.ts b/src/visor.ts index 820d55c..15d5bbd 100644 --- a/src/visor.ts +++ b/src/visor.ts @@ -29,6 +29,11 @@ const VISOR_CONTAINER_ID = 'tfjs-visor-container'; * singleton object will be replaced if the visor is removed from the DOM for * some reason. * + * ```js + * // Show the visor + * tfvis.visor(); + * ``` + * */ /** * @doc {heading: 'Visor & Surfaces'} @@ -115,6 +120,18 @@ export class Visor { * so you rarely need to call this method unless you want to make a custom * plot. * + * ```js + * // Create a surface on a tab + * tfvis.visor().surface({name: 'My Surface', tab: 'My Tab'}); + * ``` + * + * ```js + * // Create a surface and specify its height + * tfvis.visor().surface({name: 'Custom Height', tab: 'My Tab', styles: { + * height: 500 + * }}) + * ``` + * * @param options */ /** From 659b563328ec0ec6817948893969bd9d186226fa Mon Sep 17 00:00:00 2001 From: Yannick Assogba Date: Tue, 26 Feb 2019 13:45:26 -0500 Subject: [PATCH 9/9] code review fixes --- src/show/model.ts | 14 ++++++++++---- src/visor.ts | 48 ++++++++++++----------------------------------- 2 files changed, 22 insertions(+), 40 deletions(-) diff --git a/src/show/model.ts b/src/show/model.ts index 2569e7d..a39a078 100644 --- a/src/show/model.ts +++ b/src/show/model.ts @@ -46,8 +46,11 @@ import {tensorStats} from '../util/math'; * */ /** - * @doc {heading: 'Models & Tensors', subheading: 'Model Inspection', namespace: - * 'show'} + * @doc { + * heading: 'Models & Tensors', + * subheading: 'Model Inspection', + * namespace: 'show' + * } */ export async function modelSummary(container: Drawable, model: tf.Model) { const drawArea = getDrawArea(container); @@ -93,8 +96,11 @@ export async function modelSummary(container: Drawable, model: tf.Model) { * */ /** - * @doc {heading: 'Models & Tensors', subheading: 'Model Inspection', namespace: - * 'show'} + * @doc { + * heading: 'Models & Tensors', + * subheading: 'Model Inspection', + * namespace: 'show' + * } */ export async function layer(container: Drawable, layer: Layer) { const drawArea = getDrawArea(container); diff --git a/src/visor.ts b/src/visor.ts index 15d5bbd..ac9e1d3 100644 --- a/src/visor.ts +++ b/src/visor.ts @@ -35,9 +35,7 @@ const VISOR_CONTAINER_ID = 'tfjs-visor-container'; * ``` * */ -/** - * @doc {heading: 'Visor & Surfaces'} - */ +/** @doc {heading: 'Visor & Surfaces'} */ export function visor(): Visor { if (typeof document === 'undefined') { throw new Error( @@ -86,9 +84,7 @@ export function visor(): Visor { * An instance of the visor. An instance of this class is created using the * `visor()` function. */ -/** - * @doc {heading: 'Visor & Surfaces', subheading: 'Visor Methods'} - */ +/** @doc {heading: 'Visor & Surfaces', subheading: 'Visor Methods'} */ export class Visor { private visorComponent: VisorComponent; private surfaceList: Map; @@ -134,9 +130,7 @@ export class Visor { * * @param options */ - /** - * @doc {heading: 'Visor & Surfaces', subheading: 'Visor Methods'} - */ + /** @doc {heading: 'Visor & Surfaces', subheading: 'Visor Methods'} */ surface(options: SurfaceInfo) { const {name} = options; const tab = options.tab == null ? DEFAULT_TAB : options.tab; @@ -163,65 +157,47 @@ export class Visor { return this.visorComponent.getSurface(name, tab); } - /** - * @doc {heading: 'Visor & Surfaces', subheading: 'Visor Methods'} - */ + /** @doc {heading: 'Visor & Surfaces', subheading: 'Visor Methods'} */ isFullscreen() { return this.visorComponent.isFullscreen(); } - /** - * @doc {heading: 'Visor & Surfaces', subheading: 'Visor Methods'} - */ + /** @doc {heading: 'Visor & Surfaces', subheading: 'Visor Methods'} */ isOpen() { return this.visorComponent.isOpen(); } - /** - * @doc {heading: 'Visor & Surfaces', subheading: 'Visor Methods'} - */ + /** @doc {heading: 'Visor & Surfaces', subheading: 'Visor Methods'} */ close() { return this.visorComponent.close(); } - /** - * @doc {heading: 'Visor & Surfaces', subheading: 'Visor Methods'} - */ + /** @doc {heading: 'Visor & Surfaces', subheading: 'Visor Methods'} */ open() { return this.visorComponent.open(); } - /** - * @doc {heading: 'Visor & Surfaces', subheading: 'Visor Methods'} - */ + /** @doc {heading: 'Visor & Surfaces', subheading: 'Visor Methods'} */ toggle() { return this.visorComponent.toggle(); } - /** - * @doc {heading: 'Visor & Surfaces', subheading: 'Visor Methods'} - */ + /** @doc {heading: 'Visor & Surfaces', subheading: 'Visor Methods'} */ toggleFullScreen() { return this.visorComponent.toggleFullScreen(); } - /** - * @doc {heading: 'Visor & Surfaces', subheading: 'Visor Methods'} - */ + /** @doc {heading: 'Visor & Surfaces', subheading: 'Visor Methods'} */ bindKeys() { return this.visorComponent.bindKeys(); } - /** - * @doc {heading: 'Visor & Surfaces', subheading: 'Visor Methods'} - */ + /** @doc {heading: 'Visor & Surfaces', subheading: 'Visor Methods'} */ unbindKeys() { return this.visorComponent.unbindKeys(); } - /** - * @doc {heading: 'Visor & Surfaces', subheading: 'Visor Methods'} - */ + /** @doc {heading: 'Visor & Surfaces', subheading: 'Visor Methods'} */ setActiveTab(tabName: string) { const tabs = this.visorComponent.state.tabs; if (!tabs.has(tabName)) {