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 (Drawable) A {name: string, tab?: string} object specifying which surface to render to.
  • layer (Layer) a tf.layers.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 (Drawable) A {name: string, tab?: string} object specifying which surface to render to.
  • 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 (Drawable) A {name: string, tab?: string} object specifying which surface to render to.
  • tensor (Tensor) the input 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.
model.fit(data, labels, {
   epochs: 5,
   batchSize: 32,
   callbacks: tfvis.show.fitCallbacks(surface, ['loss', 'acc']),
});
Parameters:
  • container (Drawable) A {name: string, tab?: string} object specifying which surface to render to.
  • metrics (string[]) List of metrics to plot.
  • opts (Object) 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. Optional
  • callbacks (string[])
  • zoomToFitAccuracy (boolean)
  • xAxisDomain ([number, number])
  • yAxisDomain ([number, number])
  • zoomToFit (boolean)
  • width (number)
  • height (number)
  • xLabel (string)
  • yLabel (string)
  • xType ('quantitative'|'ordinal'|'nominal')
  • yType ('quantitative'|'ordinal'|'nominal')
  • fontSize (number)
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 (Drawable) A {name: string, tab?: string} object specifying which surface to render to.
  • 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. 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. Optional
  • zoomToFitAccuracy (boolean)
  • xAxisDomain ([number, number])
  • yAxisDomain ([number, number])
  • zoomToFit (boolean)
  • width (number)
  • height (number)
  • xLabel (string)
  • yLabel (string)
  • xType ('quantitative'|'ordinal'|'nominal')
  • yType ('quantitative'|'ordinal'|'nominal')
  • fontSize (number)
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 (Drawable) An HTMLElement or Surface in which to draw the bar chart. Note that the chart expects to have complete control over the contents of the container and can clear its contents at will.
  • data (Array) Data in the following format, (an array of objects) [ {index: number, value: number} ... ]
  • opts (Object) optional parameters Optional
  • width (number)
  • height (number)
  • xLabel (string)
  • yLabel (string)
  • xType ('quantitative'|'ordinal'|'nominal')
  • yType ('quantitative'|'ordinal'|'nominal')
  • fontSize (number)
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 (Drawable) An HTMLElement or Surface in which to draw the chart
  • data (Object) 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 tickLabels?: string[] } e.g. { values: [[80, 23], [56, 94]], tickLabels: ['dog', 'cat'], }

  • values (number[][])
  • tickLabels (string[])
  • opts (VisOptions& {shadeDiagonal?: boolean, showTextOverlay?: boolean}) optional parameters Optional
Returns: Promise<void>
tfvis.render.heatmap (container, data, opts?) function Source

Renders a heatmap.

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(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 (Drawable) An HTMLElement or Surface in which to draw the chart
  • data (Object) 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 xTickLabels?: string[] yTickLabels?: string[] } e.g. { values: [[80, 23, 50], [56, 94, 39]], xTickLabels: ['dog', 'cat'], yTickLabels: ['size', 'temperature', 'agility'], }

  • values (number[][]|Tensor2D)
  • xTickLabels (string[])
  • yTickLabels (string[])
  • opts (Object) optional parameters Optional
  • colorMap (NamedColorMap)
  • domain (number[])
  • width (number)
  • height (number)
  • xLabel (string)
  • yLabel (string)
  • xType ('quantitative'|'ordinal'|'nominal')
  • yType ('quantitative'|'ordinal'|'nominal')
  • fontSize (number)
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) An HTMLElement|Surface in which to draw the histogram
  • data (Array|number[]|TypedArray) Data in the following format: [ {value: number}, ... ] or [number] or TypedArray
  • opts (HistogramOpts) optional parameters Optional
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 (Drawable) An HTMLElement in which to draw the chart
  • data ({values: Point2D[][]|Point2D[], series?: string[]}) 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[] }

  • opts (Object) optional parameters Optional
  • xAxisDomain ([number, number])
  • yAxisDomain ([number, number])
  • zoomToFit (boolean)
  • width (number)
  • height (number)
  • xLabel (string)
  • yLabel (string)
  • xType ('quantitative'|'ordinal'|'nominal')
  • yType ('quantitative'|'ordinal'|'nominal')
  • fontSize (number)
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 (Drawable) An HTMLElement in which to draw the chart
  • data ({values: Point2D[][]|Point2D[], series?: string[]}) 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[] }

  • opts (Object) optional parameters Optional
  • xAxisDomain ([number, number])
  • yAxisDomain ([number, number])
  • zoomToFit (boolean)
  • width (number)
  • height (number)
  • xLabel (string)
  • yLabel (string)
  • xType ('quantitative'|'ordinal'|'nominal')
  • yType ('quantitative'|'ordinal'|'nominal')
  • fontSize (number)
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 (Drawable) An HTMLElement or Surface in which to draw the table. Note that the chart expects to have complete control over the contents of the container and can clear its contents at will.
  • data ({headers: string[], values: any[][]}) Data in the following format { headers: string[], values: any[][], } data.headers are the column names data.values is an array of arrays (one for each row). The inner array length usually matches the length of data.headers. Usually the values are strings or numbers, these are inserted as html content so html strings are also supported.
  • 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>