tfjs-vis provides some UI helpers to make it easier to render visualizations in an unobtrusive way.

tfvis.visor () function Source

The primary interface to the visor is the visor() function.

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.

// Show the visor
tfvis.visor();
Returns: tfvis.Visor

An instance of the visor. An instance of this class is created using the visor() function.

surface (options) method Source

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.

// Create a surface on a tab
tfvis.visor().surface({name: 'My Surface', tab: 'My Tab'});
// Create a surface and specify its height
tfvis.visor().surface({name: 'Custom Height', tab: 'My Tab', styles: {
   height: 500
}})
Parameters:
  • options (Object)
  • name (string) The name / label of this surface
  • tab (string) The name of the tab this surface should appear on
  • styles (StyleOptions) Display Styles for the surface
Returns: { container: any; label: any; drawArea: any; }

Returns a boolean indicating if the visor is in 'fullscreen' mode

Returns: boolean
isOpen () method Source

Returns a boolean indicating if the visor is open

Returns: boolean
close () method Source

Closes the visor.

Returns: void
open () method Source

Opens the visor.

Returns: void
toggle () method Source

Toggles the visor (closed vs open).

Returns: void
Returns: void
bindKeys () method Source

Binds the ~ (tilde) key to toggle the visor.

This is called by default when the visor is initially created.

Returns: void
unbindKeys () method Source

Unbinds the keyboard control to toggle the visor.

Returns: void
setActiveTab (tabName) method Source

Sets the active tab for the visor.

Parameters:
  • tabName (string)
Returns: void

This library exposes a show namespace that provides a number of higher level functions useful for rendering tfjs concepts. They lean towards being opinionated rather than flexible but are generally combinations of Renderers (see below), so one can easily roll their own.

These functions are useful for examing models, layers and tensors

tfvis.show.layer (container, layer) function Source

Renders summary information about a layer and a histogram of parameters in that layer.

const model = tf.sequential({
 layers: [
   tf.layers.dense({inputShape: [784], units: 32, activation: 'relu'}),
   tf.layers.dense({units: 10, activation: 'softmax'}),
 ]
});

const surface = { name: 'Layer Summary', tab: 'Model Inspection'};
tfvis.show.layer(surface, model.getLayer(undefined, 1));
Parameters:
  • container (HTMLElement|{name: string, tab?: string}|Surface|{drawArea: HTMLElement})
  • layer (Layer)
Returns: any
tfvis.show.modelSummary (container, model) function Source

Renders a summary of a tf.Model. Displays a table with layer information.

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);
Parameters:
  • container (HTMLElement|{name: string, tab?: string}|Surface|{drawArea: HTMLElement})
  • model (tf.LayersModel)
Returns: any
tfvis.show.valuesDistribution (container, tensor) function Source

Shows a histogram with the distribution of all values in a given tensor.

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);
Parameters:
  • container (HTMLElement|{name: string, tab?: string}|Surface|{drawArea: HTMLElement})
  • tensor (Tensor)
Returns: any

These functions are useful for monitoring training.

tfvis.show.fitCallbacks (container, metrics, opts?) function Source

Returns a collection of callbacks to pass to tf.Model.fit. Callbacks are returned for the following events, onBatchEnd & onEpochEnd.

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.
await model.fit(data, labels, {
   epochs: 5,
   batchSize: 32,
   callbacks: tfvis.show.fitCallbacks(surface, ['loss', 'acc']),
});
Parameters:
  • container (HTMLElement|{name: string, tab?: string}|Surface|{drawArea: HTMLElement})
  • metrics (string[]) List of metrics to plot.
  • opts (Object) Optional parameters Optional
  • callbacks (string[]) Array of callback names. Valid options are 'onEpochEnd' and 'onBatchEnd'. Defaults to ['onEpochEnd', 'onBatchEnd'].
  • zoomToFitAccuracy (boolean)
  • xAxisDomain ([number, number]) domain of the x axis. Overriden by zoomToFit
  • yAxisDomain ([number, number]) domain of the y axis. Overriden by zoomToFit
  • zoomToFit (boolean) Set the chart bounds to just fit the data. This may modify the axis scales but allows fitting more data into view.
  • seriesColors (string[]) Colors to for each series plotted. An array of valid CSS color strings.
  • width (number) Width of chart in px
  • height (number) Height of chart in px
  • xLabel (string) Label for xAxis
  • yLabel (string) Label for yAxis
  • fontSize (number) Fontsize in px
  • xType ('quantitative'|'ordinal'|'nominal') Will be set automatically
  • yType ('quantitative'|'ordinal'|'nominal') Will be set automatically
Returns: FitCallbackHandlers
tfvis.show.history (container, history, metrics, opts?) function Source

Renders a tf.Model training 'History'.

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']);
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']);
     }
   }
});
Parameters:
  • container (HTMLElement|{name: string, tab?: string}|Surface|{drawArea: HTMLElement})
  • history (HistoryLike) A history like object. Either a tfjs-layers History object or an array of tfjs-layers Logs objects.
  • metrics (string[]) 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.
  • opts (Object) Optional parameters for the line charts. Optional
  • zoomToFitAccuracy (boolean)
  • xAxisDomain ([number, number]) domain of the x axis. Overriden by zoomToFit
  • yAxisDomain ([number, number]) domain of the y axis. Overriden by zoomToFit
  • zoomToFit (boolean) Set the chart bounds to just fit the data. This may modify the axis scales but allows fitting more data into view.
  • seriesColors (string[]) Colors to for each series plotted. An array of valid CSS color strings.
  • width (number) Width of chart in px
  • height (number) Height of chart in px
  • xLabel (string) Label for xAxis
  • yLabel (string) Label for yAxis
  • fontSize (number) Fontsize in px
  • xType ('quantitative'|'ordinal'|'nominal') Will be set automatically
  • yType ('quantitative'|'ordinal'|'nominal') Will be set automatically
Returns: Promise<void>

These functions are useful for evaluating the quality of a model.

The library exposes a render namespace that provides a number of functions that plot particular visualizations. Most of these functions take regular JavaScript objects

tfvis.render.barchart (container, data, opts?) function Source

Renders a barchart.

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(surface, data);
Parameters:
  • container (HTMLElement|{name: string, tab?: string}|Surface|{drawArea: HTMLElement})
  • data (Array) Data in the following format, (an array of objects) [ {index: number, value: number} ... ]
  • opts (Object) Optional
  • color (string|string[]) Fill color for bars. Should be a valid CSS color string
  • width (number) Width of chart in px
  • height (number) Height of chart in px
  • xLabel (string) Label for xAxis
  • yLabel (string) Label for yAxis
  • fontSize (number) Fontsize in px
  • xType ('quantitative'|'ordinal'|'nominal') Will be set automatically
  • yType ('quantitative'|'ordinal'|'nominal') Will be set automatically
Returns: Promise<void>
tfvis.render.confusionMatrix (container, data, opts?) function Source

Renders a confusion matrix.

Can optionally exclude the diagonal from being shaded if one wants the visual focus to be on the incorrect classifications. Note that if the classification is perfect (i.e. only the diagonal has values) then the diagonal will always be shaded.

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(surface, data);
// The diagonal can be excluded from shading.

const data = {
  values: [[4, 2, 8], [1, 7, 2], [3, 3, 20]],
}

// Render to visor
const surface = {
 name: 'Confusion Matrix with Excluded Diagonal', tab: 'Charts'
};

tfvis.render.confusionMatrix(surface, data, {
  shadeDiagonal: false
});
Parameters:
  • container (HTMLElement|{name: string, tab?: string}|Surface|{drawArea: HTMLElement})
  • data (Object)
  • values (number[][]) a square matrix of numbers representing counts for each (label, prediction) pair
  • tickLabels (string[]) Human readable labels for each class in the matrix. Optional
  • opts (Object) Optional
  • shadeDiagonal (boolean) Color cells on the diagonal. Defaults to true
  • showTextOverlay (boolean) render the values of each cell as text. Defaults to true
  • colorMap ('greyscale'|'viridis'|'blues'|[string, string]) Output range of color scale. Either a 2 element array of valid css color or one of 'greyscale'|'viridis'|'blues'
  • width (number) Width of chart in px
  • height (number) Height of chart in px
  • xLabel (string) Label for xAxis
  • yLabel (string) Label for yAxis
  • fontSize (number) Fontsize in px
  • xType ('quantitative'|'ordinal'|'nominal') Will be set automatically
  • yType ('quantitative'|'ordinal'|'nominal') Will be set automatically
Returns: Promise<void>
tfvis.render.heatmap (container, data, opts?) function Source

Renders a heatmap.

const cols = 50;
const rows = 20;
const values = [];
for (let i = 0; i < cols; i++) {
  const col = []
  for (let j = 0; j < rows; j++) {
    col.push(i * j)
  }
  values.push(col);
}
const data = { values };

// Render to visor
const surface = { name: 'Heatmap', tab: 'Charts' };
tfvis.render.heatmap(surface, data);
const data = {
  values: [[4, 2, 8, 20], [1, 7, 2, 10], [3, 3, 20, 13]],
  xTickLabels: ['cheese', 'pig', 'font'],
  yTickLabels: ['speed', 'smoothness', 'dexterity', 'mana'],
}

// Render to visor
const surface = { name: 'Heatmap w Custom Labels', tab: 'Charts' };
tfvis.render.heatmap(surface, data);
Parameters:
  • container (HTMLElement|{name: string, tab?: string}|Surface|{drawArea: HTMLElement})
  • data (Object)
  • values (number[][]|Tensor2D) Matrix of values in column-major order.

    Row major order is supported by setting a boolean in options.

  • xTickLabels (string[]) x axis tick labels
  • yTickLabels (string[]) y axis tick labels
  • opts (Object) Optional
  • colorMap ('greyscale'|'viridis'|'blues') Defaults to viridis
  • domain (number[]) Custom input domain for the color scale. Useful if you want to plot multiple heatmaps using the same scale.
  • rowMajor (boolean) Pass in data values in row-major order.

    Internally this will transpose the data values before rendering.

  • width (number) Width of chart in px
  • height (number) Height of chart in px
  • xLabel (string) Label for xAxis
  • yLabel (string) Label for yAxis
  • fontSize (number) Fontsize in px
  • xType ('quantitative'|'ordinal'|'nominal') Will be set automatically
  • yType ('quantitative'|'ordinal'|'nominal') Will be set automatically
Returns: Promise<void>
tfvis.render.histogram (container, data, opts?) function Source

Renders a histogram of values

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(surface, data);
Parameters:
  • container (HTMLElement|{name: string, tab?: string}|Surface|{drawArea: HTMLElement})
  • data (Array|number[]|TypedArray)
  • opts (Object) Optional
  • stats (HistogramStats|false) By default a histogram will also compute and display summary statistics. If stats is set to false then summary statistics will not be displayed.

    Pre computed stats can also be passed in and should have the following format: { numVals?: number, min?: number, max?: number, numNans?: number, numZeros?: number, numInfs?: number, }

  • maxBins (number) Maximum number of bins in histogram.
  • color (string) Fill color for bars. Should be a valid CSS color string
  • width (number) Width of chart in px
  • height (number) Height of chart in px
  • xLabel (string) Label for xAxis
  • yLabel (string) Label for yAxis
  • fontSize (number) Fontsize in px
  • xType ('quantitative'|'ordinal'|'nominal') Will be set automatically
  • yType ('quantitative'|'ordinal'|'nominal') Will be set automatically
Returns: {}
tfvis.render.linechart (container, data, opts?) function Source

Renders a line chart

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: 'Line chart', tab: 'Charts' };
tfvis.render.linechart(surface, data);
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(surface, data, { zoomToFit: true });
Parameters:
  • container (HTMLElement|{name: string, tab?: string}|Surface|{drawArea: HTMLElement})
  • data (Object)
  • values (Point2D[][]|Point2D[]) An array (or nested array) of {x, y} tuples.
  • series (string[]) Series names/labels
  • opts (Object) Optional
  • xAxisDomain ([number, number]) domain of the x axis. Overriden by zoomToFit
  • yAxisDomain ([number, number]) domain of the y axis. Overriden by zoomToFit
  • zoomToFit (boolean) Set the chart bounds to just fit the data. This may modify the axis scales but allows fitting more data into view.
  • seriesColors (string[]) Colors to for each series plotted. An array of valid CSS color strings.
  • width (number) Width of chart in px
  • height (number) Height of chart in px
  • xLabel (string) Label for xAxis
  • yLabel (string) Label for yAxis
  • fontSize (number) Fontsize in px
  • xType ('quantitative'|'ordinal'|'nominal') Will be set automatically
  • yType ('quantitative'|'ordinal'|'nominal') Will be set automatically
Returns: Promise<void>
tfvis.render.scatterplot (container, data, opts?) function Source

Renders a scatter plot

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(surface, data);
Parameters:
  • container (HTMLElement|{name: string, tab?: string}|Surface|{drawArea: HTMLElement})
  • data (Object)
  • values (Point2D[][]|Point2D[]) An array (or nested array) of {x, y} tuples.
  • series (string[]) Series names/labels
  • opts (Object) Optional
  • xAxisDomain ([number, number]) domain of the x axis. Overriden by zoomToFit
  • yAxisDomain ([number, number]) domain of the y axis. Overriden by zoomToFit
  • zoomToFit (boolean) Set the chart bounds to just fit the data. This may modify the axis scales but allows fitting more data into view.
  • seriesColors (string[]) Colors to for each series plotted. An array of valid CSS color strings.
  • width (number) Width of chart in px
  • height (number) Height of chart in px
  • xLabel (string) Label for xAxis
  • yLabel (string) Label for yAxis
  • fontSize (number) Fontsize in px
  • xType ('quantitative'|'ordinal'|'nominal') Will be set automatically
  • yType ('quantitative'|'ordinal'|'nominal') Will be set automatically
Returns: Promise<void>
tfvis.render.table (container, data, opts?) function Source

Renders a table

const headers = [
 'Col 1',
 'Col 2',
 'Col 3',
];

const values = [
 [1, 2, 3],
 ['4', '5', '6'],
 ['strong>7</strong>', true, false],
];

const surface = { name: 'Table', tab: 'Charts' };
tfvis.render.table(surface, { headers, values });
Parameters:
  • container (HTMLElement|{name: string, tab?: string}|Surface|{drawArea: HTMLElement})
  • data (Object)
  • headers (string[]) Column names
  • values (any[][]) An array of arrays (one for each row). The inner array length usually matches the length of data.headers.

    Typically the values are numbers or strings.

  • opts ({fontSize?: number}) Optional
Returns: void

The metrics namespace contains a few utility functions for computing quality metrics like accuracy or creating confusion matrices.

tfvis.metrics.accuracy (labels, predictions) function Source

Computes how often predictions matches labels

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)
Parameters:
  • labels (Tensor) tensor of true values
  • predictions (Tensor) tensor of predicted values
Returns: Promise<number>
tfvis.metrics.confusionMatrix (labels, predictions, numClasses?, weights?) function Source

Computes a confusion matrix from predictions and labels. Each value in labels and predictions should correspond to some output class. It is assumed that these values go from 0 to numClasses - 1.

const labels = tf.tensor1d([1, 2, 4]);
const predictions = tf.tensor1d([2, 2, 4]);
const result = await tfvis.metrics.confusionMatrix(labels, predictions);
console.log(JSON.stringify(result, null, 2))
Parameters:
  • labels (Tensor1D) 1D tensor of true values
  • predictions (Tensor1D) 1D tensor of predicted values
  • numClasses (number) Number of distinct classes. Optional. If not passed in numClasses will equal the highest number in either labels or predictions plus 1 Optional
  • weights (Tensor1D) 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. Optional
Returns: Promise<number[][]>
tfvis.metrics.perClassAccuracy (labels, predictions, numClasses?) function Source

Computes per class accuracy between prediction and labels. Each value in labels and predictions should correspond to some output class. It is assumed that these values go from 0 to numClasses - 1.

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(JSON.stringify(result, null, 2))

Returns an array of objects that each have an an accuracy and a count property for each class.

Parameters:
  • labels (Tensor1D) 1D tensor of true values
  • predictions (Tensor1D) 1D tensor of predicted values
  • numClasses (number) Number of distinct classes. Optional. If not passed in numClasses will equal the highest number in either labels or predictions plus 1 Optional
Returns: Promise<Array>