This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Custom charts

Custom charts are visualizations you create explicitly. Use custom charts to visualize complex data relationships and have greater control over the appearance and behavior of the chart.

To create a custom chart, you can either:

Create a custom chart in the W&B App

To create a custom chart in the W&B App, you must first log data to one or more runs. This data can come from key-value pairs logged with wandb.Run.log(), or more complex data structures like wandb.Table. Once you log data, you can create a custom chart by pulling in the data using a GraphQL query.

Suppose you want to create a line plot that shows the accuracy as a function of training step. To do this, you first log accuracy values to a run using the following code snippet:

import wandb
import math

with wandb.init() as run:
  offset = random.random()
  for run_step in range(20):
    run.log({
        "acc": math.log(1 + random.random() + run_step) + offset,
        "val_acc": math.log(1 + random.random() + run_step) + offset * random.random(),
    })

Each call to wandb.Run.log() creates a new entry in the run’s history. The step value is automatically tracked by W&B and increments with each log call.

Once the code snippet completes, navigate to your project’s workspace:

  1. Click the Add panels button in the top right corner, then select Custom chart.
  2. Select Line plot from the list of chart types.
  3. Within the query editor, select history as the data source. Next, select acc and type in _step as keys.
  4. Within the chart editor, select _step for the X field and acc for the Y field. Optionally, set a title for the chart. Your settings should look similar to the following: Custom line plot settings

Your custom line plot should now appear in the panel, showing the accuracy values over training steps.

Custom line plot example

Query data sources

When you create a custom chart, you can pull in data from your runs using a GraphQL query. The data you can query comes from:

  • config: Initial settings of your experiment (your independent variables). This includes any named fields you’ve logged as keys to wandb.Run.config at the start of your training. For example: wandb.Run.config.learning_rate = 0.0001
  • summary: A single-value metrics that summarize a run. It’s populated by the final value of metrics logged with wandb.Run.log() or by directly updating the run.summary object. Think of it as a key-value store for your run’s final results.
  • history: Time series data logged with wandb.Run.log(). Each call to log() creates a new row in the history table. This is ideal for tracking metrics that change over time, like training and validation loss.
  • summaryTable: A table of summary metrics. It’s populated by logging a wandb.Table to the summary field. This is useful for logging metrics that are best represented in a tabular format, like confusion matrices or classification reports.
  • historyTable: A table of time series data. It’s populated by logging a wandb.Table to the history field. This is useful for logging complex metrics that change over time, like per-epoch evaluation metrics.

To recap, summary and history are the general locations for your run data, while summaryTable and historyTable are the specific query types needed to access tabular data stored in those respective locations.

Query editor

Within the query editor, you can define a GraphQL query to pull in the data from available data sources. The query editor consists of dropdowns and text fields that allow you to construct the query without needing to write raw GraphQL. You can include any combination of available data sources, depending on the data you want to visualize.

The keys argument acts as a filter to specify exactly which pieces of data you want to retrieve from a larger data object such as summary. The sub-fields are dictionary-like or key-value pairs.

The general structure of the query is as follows:

query {
    runSets: (runSets: "${runSets}", limit: 500 ) {
        id: 
        name: 
        summary:
            (keys: [""])
        history:
            (keys: [""])
        summaryTable:
            (keys: [""])
        historyTable:
            (keys: [""])
    }
}

Here’s a breakdown of the components:

  • runSets: Top-level object, representing the set of runs you are currently viewing or have filtered in the UI.
  • summary(...), history(...), summaryTable(...), historyTable(...): This tells the query to fetch data from the respective objects of each run.
  • keys: [""]: An array of strings where each string is the name (or key) of the metric or object you want to retrieve.

Log charts from a script

You can programmatically create a custom chart from your script by logging a wandb.Table of the data you want to visualize, then calling wandb.plot.* to create the chart.

For example, consider the following code snippet:

import wandb
import math

with wandb.init() as run:
    offset = random.random()

    # Set up data to log in custom charts
    data = []
    for i in range(100):
    data.append([i, random.random() + math.log(1 + i) + offset + random.random()])

    # Create a table with the columns to plot
    table = wandb.Table(data=data, columns=["step", "height"])

    # Use the table to populate various custom charts
    line_plot = wandb.plot.line(table, x='step', y='height', title='Line Plot')
    histogram = wandb.plot.histogram(table, value='height', title='Histogram')
    scatter = wandb.plot.scatter(table, x='step', y='height', title='Scatter Plot')

    # Log custom tables, which will show up in customizable charts in the UI
    run.log({'line_1': line_plot, 
                'histogram_1': histogram, 
                'scatter_1': scatter})

Within the W&B app, navigate to the Workspace tab. Within the Custom Charts panel, there are three charts with the following titles: Scatter Plot, Histogram, and Line Plot. These correspond to the three charts created in the script above. The x-axis and y-axis are set to the columns specified in the wandb.plot.* function calls (height and step).

The following image shows the three custom charts created from the script:

Custom charts from script

Built-in chart types

W&B has a number of built-in chart presets that you can log directly from your script. These include line plots, scatter plots, bar charts, histograms, PR curves, and ROC curves. The following tabs show how to log each type of chart.

wandb.plot.line()

Log a custom line plot—a list of connected and ordered points (x,y) on arbitrary axes x and y.

with wandb.init() as run:
  data = [[x, y] for (x, y) in zip(x_values, y_values)]
  table = wandb.Table(data=data, columns=["x", "y"])
  run.log(
      {
          "my_custom_plot_id": wandb.plot.line(
              table, "x", "y", title="Custom Y vs X Line Plot"
          )
      }
  )

A line plot logs curves on any two dimensions. If you plot two lists of values against each other, the number of values in the lists must match exactly (for example, each point must have an x and a y).

Custom line plot

See an example report or try an example Google Colab notebook.

wandb.plot.scatter()

Log a custom scatter plot—a list of points (x, y) on a pair of arbitrary axes x and y.

with wandb.init() as run:
  data = [[x, y] for (x, y) in zip(class_x_prediction_scores, class_y_prediction_scores)]
  table = wandb.Table(data=data, columns=["class_x", "class_y"])
  run.log({"my_custom_id": wandb.plot.scatter(table, "class_x", "class_y")})

You can use this to log scatter points on any two dimensions. Note that if you’re plotting two lists of values against each other, the number of values in the lists must match exactly (for example, each point must have an x and a y).

Scatter plot

See an example report or try an example Google Colab notebook.

wandb.plot.bar()

Log a custom bar chart—a list of labeled values as bars—natively in a few lines:

with wandb.init() as run:
  data = [[label, val] for (label, val) in zip(labels, values)]
  table = wandb.Table(data=data, columns=["label", "value"])
  run.log(
      {
          "my_bar_chart_id": wandb.plot.bar(
              table, "label", "value", title="Custom Bar Chart"
          )
      }
  )

You can use this to log arbitrary bar charts. Note that the number of labels and values in the lists must match exactly (for example, each data point must have both).

Demo bar plot

See an example report or try an example Google Colab notebook.

wandb.plot.histogram()

Log a custom histogram—sort list of values into bins by count/frequency of occurrence—natively in a few lines. Let’s say I have a list of prediction confidence scores (scores) and want to visualize their distribution:

with wandb.init() as run:
  data = [[s] for s in scores]
  table = wandb.Table(data=data, columns=["scores"])
  run.log({"my_histogram": wandb.plot.histogram(table, "scores", title=None)})

You can use this to log arbitrary histograms. Note that data is a list of lists, intended to support a 2D array of rows and columns.

Custom histogram

See an example report or try an example Google Colab notebook.

wandb.plot.pr_curve()

Create a Precision-Recall curve in one line:

with wandb.init() as run:
  plot = wandb.plot.pr_curve(ground_truth, predictions, labels=None, classes_to_plot=None)

  run.log({"pr": plot})

You can log this whenever your code has access to:

  • a model’s predicted scores (predictions) on a set of examples
  • the corresponding ground truth labels (ground_truth) for those examples
  • (optionally) a list of the labels/class names (labels=["cat", "dog", "bird"...] if label index 0 means cat, 1 = dog, 2 = bird, etc.)
  • (optionally) a subset (still in list format) of the labels to visualize in the plot
Precision-recall curves

See an example report or try an example Google Colab notebook.

wandb.plot.roc_curve()

Create an ROC curve in one line:

with wandb.init() as run:
  # ground_truth is a list of true labels, predictions is a list of predicted scores
  ground_truth = [0, 1, 0, 1, 0, 1]
  predictions = [0.1, 0.4, 0.35, 0.8, 0.7, 0.9]

  # Create the ROC curve plot
  # labels is an optional list of class names, classes_to_plot is an optional subset of those labels to visualize
  plot = wandb.plot.roc_curve(
      ground_truth, predictions, labels=None, classes_to_plot=None
  )

  run.log({"roc": plot})

You can log this whenever your code has access to:

  • a model’s predicted scores (predictions) on a set of examples
  • the corresponding ground truth labels (ground_truth) for those examples
  • (optionally) a list of the labels/ class names (labels=["cat", "dog", "bird"...] if label index 0 means cat, 1 = dog, 2 = bird, etc.)
  • (optionally) a subset (still in list format) of these labels to visualize on the plot
ROC curve

See an example report or try an example Google Colab notebook.

Additional resources

1 - Tutorial: Use custom charts

Tutorial of using the custom charts feature in the W&B UI

Use custom charts to control the data you’re loading in to a panel and its visualization.

1. Log data to W&B

First, log data in your script. Use wandb.Run.config for single points set at the beginning of training, like hyperparameters. Use wandb.Run.log() for multiple points over time, and log custom 2D arrays with wandb.Table(). We recommend logging up to 10,000 data points per logged key.

with wandb.init() as run: 

  # Logging a custom table of data
  my_custom_data = [[x1, y1, z1], [x2, y2, z2]]
  run.log(
    {"custom_data_table": wandb.Table(data=my_custom_data, columns=["x", "y", "z"])}
  )

Try a quick example notebook to log the data tables, and in the next step we’ll set up custom charts. See what the resulting charts look like in the live report.

2. Create a query

Once you’ve logged data to visualize, go to your project page and click the + button to add a new panel, then select Custom Chart. You can follow along in the custom charts demo workspace.

Blank custom chart

Add a query

  1. Click summary and select historyTable to set up a new query pulling data from the run history.
  2. Type in the key where you logged the wandb.Table(). In the code snippet above, it was my_custom_table . In the example notebook, the keys are pr_curve and roc_curve.

Set Vega fields

Now that the query is loading in these columns, they’re available as options to select in the Vega fields dropdown menus:

Pulling in columns from the query results to set Vega fields
  • x-axis: runSets_historyTable_r (recall)
  • y-axis: runSets_historyTable_p (precision)
  • color: runSets_historyTable_c (class label)

3. Customize the chart

Now that looks pretty good, but I’d like to switch from a scatter plot to a line plot. Click Edit to change the Vega spec for this built in chart. Follow along in the custom charts demo workspace.

Custom chart selection

I updated the Vega spec to customize the visualization:

  • add titles for the plot, legend, x-axis, and y-axis (set “title” for each field)
  • change the value of “mark” from “point” to “line”
  • remove the unused “size” field
PR curve Vega spec

To save this as a preset that you can use elsewhere in this project, click Save as at the top of the page. Here’s what the result looks like, along with an ROC curve:

PR curve chart

Bonus: Composite Histograms

Histograms can visualize numerical distributions to help us understand larger datasets. Composite histograms show multiple distributions across the same bins, letting us compare two or more metrics across different models or across different classes within our model. For a semantic segmentation model detecting objects in driving scenes, we might compare the effectiveness of optimizing for accuracy versus intersection over union (IOU), or we might want to know how well different models detect cars (large, common regions in the data) versus traffic signs (much smaller, less common regions). In the demo Colab, you can compare the confidence scores for two of the ten classes of living things.

Composite histogram

To create your own version of the custom composite histogram panel:

  1. Create a new Custom Chart panel in your Workspace or Report (by adding a “Custom Chart” visualization). Hit the “Edit” button in the top right to modify the Vega spec starting from any built-in panel type.
  2. Replace that built-in Vega spec with my MVP code for a composite histogram in Vega. You can modify the main title, axis titles, input domain, and any other details directly in this Vega spec using Vega syntax (you could change the colors or even add a third histogram :)
  3. Modify the query in the right hand side to load the correct data from your wandb logs. Add the field summaryTable and set the corresponding tableKey to class_scores to fetch the wandb.Table logged by your run. This will let you populate the two histogram bin sets (red_bins and blue_bins) via the dropdown menus with the columns of the wandb.Table logged as class_scores. For my example, I chose the animal class prediction scores for the red bins and plant for the blue bins.
  4. You can keep making changes to the Vega spec and query until you’re happy with the plot you see in the preview rendering. Once you’re done, click Save as in the top and give your custom plot a name so you can reuse it. Then click Apply from panel library to finish your plot.

Here’s what my results look like from a very brief experiment: training on only 1000 examples for one epoch yields a model that’s very confident that most images are not plants and very uncertain about which images might be animals.

Chart configuration Chart result