Create and track plots from experiments

no
Summary: Create and track plots from machine learning experiments.

Original Documentation

Documentation Index#

Fetch the complete documentation index at: https://docs.wandb.ai/llms.txt Use this file to discover all available pages before exploring further.

Create and track plots from machine learning experiments.

Using the methods in wandb.plot, you can track charts with wandb.Run.log(), including charts that change over time during training. To learn more about our custom charting framework, check out the custom charts walkthrough.

Basic charts#

These simple charts make it easy to construct basic visualizations of metrics and results.

Log a custom line plot—a list of connected and ordered points on arbitrary axes.

    import wandb

    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"
                )
            }
        )
    ```

You can use this to log curves on any two dimensions. 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.


  <img src="https://mintcdn.com/wb-21fd5541/_OEDykSS2PIumrEw/images/track/line_plot.png?fit=max&auto=format&n=_OEDykSS2PIumrEw&q=85&s=9808ee611e7d6cea084d05903e83f5a6" alt="Custom line plot" data-og-width="1930" width="1930" data-og-height="1228" height="1228" data-path="images/track/line_plot.png" data-optimize="true" data-opv="3" srcset="https://mintcdn.com/wb-21fd5541/_OEDykSS2PIumrEw/images/track/line_plot.png?w=280&fit=max&auto=format&n=_OEDykSS2PIumrEw&q=85&s=8e37e4bccd3d084a38f87ef8feb1b0d7 280w, https://mintcdn.com/wb-21fd5541/_OEDykSS2PIumrEw/images/track/line_plot.png?w=560&fit=max&auto=format&n=_OEDykSS2PIumrEw&q=85&s=b2fe901f2b14ad0f3419397c2a48e39a 560w, https://mintcdn.com/wb-21fd5541/_OEDykSS2PIumrEw/images/track/line_plot.png?w=840&fit=max&auto=format&n=_OEDykSS2PIumrEw&q=85&s=3a8c30103d107aa75ba3bf3ca283e728 840w, https://mintcdn.com/wb-21fd5541/_OEDykSS2PIumrEw/images/track/line_plot.png?w=1100&fit=max&auto=format&n=_OEDykSS2PIumrEw&q=85&s=45658e0e20ed404a7a50d07bb598a63a 1100w, https://mintcdn.com/wb-21fd5541/_OEDykSS2PIumrEw/images/track/line_plot.png?w=1650&fit=max&auto=format&n=_OEDykSS2PIumrEw&q=85&s=a6566e7328167af60ecd07937096f1a4 1650w, https://mintcdn.com/wb-21fd5541/_OEDykSS2PIumrEw/images/track/line_plot.png?w=2500&fit=max&auto=format&n=_OEDykSS2PIumrEw&q=85&s=65d622a51e3dd311e8dd302cf635c816 2500w" />


[See in the app](https://wandb.ai/wandb/plots/reports/Custom-Line-Plots--VmlldzoyNjk5NTA)

[Run the code](https://tiny.cc/custom-charts)
  <span class="tab-end"></span>

  <span class="tab-start" data-tab-title="Scatter"></span>
Log a custom scatter plota list of points (x, y) on a pair of arbitrary axes x and y.

```python
    import wandb

    with wandb.init() as run:
        data = [[x, y] for (x, y) in zip(class_x_scores, class_y_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. 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.


  <img src="https://mintcdn.com/wb-21fd5541/_OEDykSS2PIumrEw/images/track/demo_scatter_plot.png?fit=max&auto=format&n=_OEDykSS2PIumrEw&q=85&s=536a7c7c0796e3de6a56b17535566156" alt="Custom scatter plot" data-og-width="2194" width="2194" data-og-height="940" height="940" data-path="images/track/demo_scatter_plot.png" data-optimize="true" data-opv="3" srcset="https://mintcdn.com/wb-21fd5541/_OEDykSS2PIumrEw/images/track/demo_scatter_plot.png?w=280&fit=max&auto=format&n=_OEDykSS2PIumrEw&q=85&s=50c6d89d90e2bb44648c86aad2437311 280w, https://mintcdn.com/wb-21fd5541/_OEDykSS2PIumrEw/images/track/demo_scatter_plot.png?w=560&fit=max&auto=format&n=_OEDykSS2PIumrEw&q=85&s=338ba774bf978dbc089b8da1b4d68600 560w, https://mintcdn.com/wb-21fd5541/_OEDykSS2PIumrEw/images/track/demo_scatter_plot.png?w=840&fit=max&auto=format&n=_OEDykSS2PIumrEw&q=85&s=cb9f2f5da86ddd930cadb29c0dc29bff 840w, https://mintcdn.com/wb-21fd5541/_OEDykSS2PIumrEw/images/track/demo_scatter_plot.png?w=1100&fit=max&auto=format&n=_OEDykSS2PIumrEw&q=85&s=86e9e502d7964d298590c2395d2ce333 1100w, https://mintcdn.com/wb-21fd5541/_OEDykSS2PIumrEw/images/track/demo_scatter_plot.png?w=1650&fit=max&auto=format&n=_OEDykSS2PIumrEw&q=85&s=4fc7913a254a2cb29f0ea9ad3d2c05cb 1650w, https://mintcdn.com/wb-21fd5541/_OEDykSS2PIumrEw/images/track/demo_scatter_plot.png?w=2500&fit=max&auto=format&n=_OEDykSS2PIumrEw&q=85&s=a82c3a53e7cb70e0afdf0d74a6701288 2500w" />


[See in the app](https://wandb.ai/wandb/plots/reports/Custom-Scatter-Plots--VmlldzoyNjk5NDQ)

[Run the code](https://tiny.cc/custom-charts)
  <span class="tab-end"></span>

  <span class="tab-start" data-tab-title="Bar"></span>
Log a custom bar charta list of labeled values as barsnatively in a few lines:

```python
    import wandb

    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. The number of labels and values in the lists must match exactly. Each data point must have both.


  <img src="https://mintcdn.com/wb-21fd5541/6bJLb4DIApn2yeFO/images/track/basic_charts_bar.png?fit=max&auto=format&n=6bJLb4DIApn2yeFO&q=85&s=ce4fc3ee16167f8f8c9fd87dc0043c70" alt="Custom bar chart" data-og-width="1286" width="1286" data-og-height="552" height="552" data-path="images/track/basic_charts_bar.png" data-optimize="true" data-opv="3" srcset="https://mintcdn.com/wb-21fd5541/6bJLb4DIApn2yeFO/images/track/basic_charts_bar.png?w=280&fit=max&auto=format&n=6bJLb4DIApn2yeFO&q=85&s=242898f94da5ecbaef0657e275a9ded2 280w, https://mintcdn.com/wb-21fd5541/6bJLb4DIApn2yeFO/images/track/basic_charts_bar.png?w=560&fit=max&auto=format&n=6bJLb4DIApn2yeFO&q=85&s=c9904e519080add8fad699fe63c36510 560w, https://mintcdn.com/wb-21fd5541/6bJLb4DIApn2yeFO/images/track/basic_charts_bar.png?w=840&fit=max&auto=format&n=6bJLb4DIApn2yeFO&q=85&s=9aee8ffd0c954e6e33b2fee7f14c6422 840w, https://mintcdn.com/wb-21fd5541/6bJLb4DIApn2yeFO/images/track/basic_charts_bar.png?w=1100&fit=max&auto=format&n=6bJLb4DIApn2yeFO&q=85&s=ddfbae6c1c9113a2ed2f2edf13f99bc6 1100w, https://mintcdn.com/wb-21fd5541/6bJLb4DIApn2yeFO/images/track/basic_charts_bar.png?w=1650&fit=max&auto=format&n=6bJLb4DIApn2yeFO&q=85&s=eb7fcd8bb66bd9726196b502d4205fb4 1650w, https://mintcdn.com/wb-21fd5541/6bJLb4DIApn2yeFO/images/track/basic_charts_bar.png?w=2500&fit=max&auto=format&n=6bJLb4DIApn2yeFO&q=85&s=6d38d1c976449e113429e898a2c36d56 2500w" />


[See in the app](https://wandb.ai/wandb/plots/reports/Custom-Bar-Charts--VmlldzoyNzExNzk)

[Run the code](https://tiny.cc/custom-charts)
  <span class="tab-end"></span>

  <span class="tab-start" data-tab-title="Histogram"></span>
Log a custom histogramsort a list of values into bins by count/frequency of occurrencenatively in a few lines. Let's say I have a list of prediction confidence scores (`scores`) and want to visualize their distribution:

```python
    import wandb

    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="Histogram")})
    ```

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.


  <img src="https://mintcdn.com/wb-21fd5541/_OEDykSS2PIumrEw/images/track/demo_custom_chart_histogram.png?fit=max&auto=format&n=_OEDykSS2PIumrEw&q=85&s=53afbd7a9439705cd7997e6a52c7cce0" alt="Custom histogram" data-og-width="1252" width="1252" data-og-height="558" height="558" data-path="images/track/demo_custom_chart_histogram.png" data-optimize="true" data-opv="3" srcset="https://mintcdn.com/wb-21fd5541/_OEDykSS2PIumrEw/images/track/demo_custom_chart_histogram.png?w=280&fit=max&auto=format&n=_OEDykSS2PIumrEw&q=85&s=fb608ba6b010c538d0741c2df246a977 280w, https://mintcdn.com/wb-21fd5541/_OEDykSS2PIumrEw/images/track/demo_custom_chart_histogram.png?w=560&fit=max&auto=format&n=_OEDykSS2PIumrEw&q=85&s=56ff24a6e266a3bd574d864589b4e6cd 560w, https://mintcdn.com/wb-21fd5541/_OEDykSS2PIumrEw/images/track/demo_custom_chart_histogram.png?w=840&fit=max&auto=format&n=_OEDykSS2PIumrEw&q=85&s=7947d1445f68fef5e5772c821bac4e3d 840w, https://mintcdn.com/wb-21fd5541/_OEDykSS2PIumrEw/images/track/demo_custom_chart_histogram.png?w=1100&fit=max&auto=format&n=_OEDykSS2PIumrEw&q=85&s=8ee91d3be03414424b8d48ddd7ef20ba 1100w, https://mintcdn.com/wb-21fd5541/_OEDykSS2PIumrEw/images/track/demo_custom_chart_histogram.png?w=1650&fit=max&auto=format&n=_OEDykSS2PIumrEw&q=85&s=e84b64d9b0b42d288bbfbf8b9acd8805 1650w, https://mintcdn.com/wb-21fd5541/_OEDykSS2PIumrEw/images/track/demo_custom_chart_histogram.png?w=2500&fit=max&auto=format&n=_OEDykSS2PIumrEw&q=85&s=e5003fd9c3b881b574f419bfa70ee61e 2500w" />


[See in the app](https://wandb.ai/wandb/plots/reports/Custom-Histograms--VmlldzoyNzE0NzM)

[Run the code](https://tiny.cc/custom-charts)
  <span class="tab-end"></span>

  <span class="tab-start" data-tab-title="Multi-line"></span>
Plot multiple lines, or multiple different lists of x-y coordinate pairs, on one shared set of x-y axes:

```python
    import wandb
    with wandb.init() as run:
        run.log(
            {
                "my_custom_id": wandb.plot.line_series(
                    xs=[0, 1, 2, 3, 4],
                    ys=[[10, 20, 30, 40, 50], [0.5, 11, 72, 3, 41]],
                keys=["metric Y", "metric Z"],
                title="Two Random Metrics",
                xname="x units",
            )
        }
    )
    ```

Note that the number of x and y points must match exactly. You can supply one list of x values to match multiple lists of y values, or a separate list of x values for each list of y values.


  <img src="https://mintcdn.com/wb-21fd5541/6bJLb4DIApn2yeFO/images/track/basic_charts_histogram.png?fit=max&auto=format&n=6bJLb4DIApn2yeFO&q=85&s=c554f1978caabbd7d05322ef59f399c8" alt="Multi-line plot" data-og-width="537" width="537" data-og-height="339" height="339" data-path="images/track/basic_charts_histogram.png" data-optimize="true" data-opv="3" srcset="https://mintcdn.com/wb-21fd5541/6bJLb4DIApn2yeFO/images/track/basic_charts_histogram.png?w=280&fit=max&auto=format&n=6bJLb4DIApn2yeFO&q=85&s=acae8459798b20cb3cbd917bd9964a65 280w, https://mintcdn.com/wb-21fd5541/6bJLb4DIApn2yeFO/images/track/basic_charts_histogram.png?w=560&fit=max&auto=format&n=6bJLb4DIApn2yeFO&q=85&s=06db3ae2f6d11bd5a0dd5e9ae14a0c89 560w, https://mintcdn.com/wb-21fd5541/6bJLb4DIApn2yeFO/images/track/basic_charts_histogram.png?w=840&fit=max&auto=format&n=6bJLb4DIApn2yeFO&q=85&s=ef89fb8cd0c2aa63dfa9c75ceea37a4f 840w, https://mintcdn.com/wb-21fd5541/6bJLb4DIApn2yeFO/images/track/basic_charts_histogram.png?w=1100&fit=max&auto=format&n=6bJLb4DIApn2yeFO&q=85&s=8be9b2857cc139a3bb37badf7c90fa21 1100w, https://mintcdn.com/wb-21fd5541/6bJLb4DIApn2yeFO/images/track/basic_charts_histogram.png?w=1650&fit=max&auto=format&n=6bJLb4DIApn2yeFO&q=85&s=45f5761de38308f0c2fd26b2d0b906c8 1650w, https://mintcdn.com/wb-21fd5541/6bJLb4DIApn2yeFO/images/track/basic_charts_histogram.png?w=2500&fit=max&auto=format&n=6bJLb4DIApn2yeFO&q=85&s=b7e966ec2e6915922aeff9fe3d0fd7a6 2500w" />


[See in the app](https://wandb.ai/wandb/plots/reports/Custom-Multi-Line-Plots--VmlldzozOTMwMjU)
  <span class="tab-end"></span>
<span class="tab-group-end"></span>

### Model evaluation charts

These preset charts have built-in `wandb.plot()` methods that make it quick and easy to log charts directly from your script and see the exact information you're looking for in the UI.

<span class="tab-group-start"></span>
  <span class="tab-start" data-tab-title="Precision-recall curves"></span>
Create a [Precision-Recall curve](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.precision_recall_curve.html#sklearn.metrics.precision_recall_curve) in one line:

```python
    import wandb
    with wandb.init() as run:
        # ground_truth is a list of true labels, predictions is a list of predicted scores
        # e.g. ground_truth = [0, 1, 1, 0], predictions = [0.1, 0.4, 0.35, 0.8]
        ground_truth = [0, 1, 1, 0]
        predictions = [0.1, 0.4, 0.35, 0.8]
        run.log({"pr": wandb.plot.pr_curve(ground_truth, predictions)})
    ```

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


  <img src="https://mintcdn.com/wb-21fd5541/_OEDykSS2PIumrEw/images/track/model_eval_charts_precision_recall.png?fit=max&auto=format&n=_OEDykSS2PIumrEw&q=85&s=c5accf7be884f7517b880425f127be82" alt="Precision-recall curve" data-og-width="657" width="657" data-og-height="431" height="431" data-path="images/track/model_eval_charts_precision_recall.png" data-optimize="true" data-opv="3" srcset="https://mintcdn.com/wb-21fd5541/_OEDykSS2PIumrEw/images/track/model_eval_charts_precision_recall.png?w=280&fit=max&auto=format&n=_OEDykSS2PIumrEw&q=85&s=d508f7ef06e4e033dd1f3a810bac100b 280w, https://mintcdn.com/wb-21fd5541/_OEDykSS2PIumrEw/images/track/model_eval_charts_precision_recall.png?w=560&fit=max&auto=format&n=_OEDykSS2PIumrEw&q=85&s=e9aed4549a0975e4fee4f1cf9e6cd5dd 560w, https://mintcdn.com/wb-21fd5541/_OEDykSS2PIumrEw/images/track/model_eval_charts_precision_recall.png?w=840&fit=max&auto=format&n=_OEDykSS2PIumrEw&q=85&s=acf61dfb53a3551dcbf5f11806f32fa1 840w, https://mintcdn.com/wb-21fd5541/_OEDykSS2PIumrEw/images/track/model_eval_charts_precision_recall.png?w=1100&fit=max&auto=format&n=_OEDykSS2PIumrEw&q=85&s=e103b3783e3bca4bba5b3eea65c30680 1100w, https://mintcdn.com/wb-21fd5541/_OEDykSS2PIumrEw/images/track/model_eval_charts_precision_recall.png?w=1650&fit=max&auto=format&n=_OEDykSS2PIumrEw&q=85&s=e74bdb53dcbb5262607a5ecd533f79c8 1650w, https://mintcdn.com/wb-21fd5541/_OEDykSS2PIumrEw/images/track/model_eval_charts_precision_recall.png?w=2500&fit=max&auto=format&n=_OEDykSS2PIumrEw&q=85&s=9ecd3498d2a4a3cc96f4799d6818a1ae 2500w" />


[See in the app](https://wandb.ai/wandb/plots/reports/Plot-Precision-Recall-Curves--VmlldzoyNjk1ODY)

[Run the code](https://colab.research.google.com/drive/1mS8ogA3LcZWOXchfJoMrboW3opY1A8BY?usp=sharing)
  <span class="tab-end"></span>

  <span class="tab-start" data-tab-title="ROC curves"></span>
Create an [ROC curve](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.roc_curve.html#sklearn.metrics.roc_curve) in one line:

```python
    import wandb

    with wandb.init() as run:
        # ground_truth is a list of true labels, predictions is a list of predicted scores
        # e.g. ground_truth = [0, 1, 1, 0], predictions = [0.1, 0.4, 0.35, 0.8]
        ground_truth = [0, 1, 1, 0]
        predictions = [0.1, 0.4, 0.35, 0.8]
        run.log({"roc": wandb.plot.roc_curve(ground_truth, predictions)})
    ```

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


  <img src="https://mintcdn.com/wb-21fd5541/_OEDykSS2PIumrEw/images/track/demo_custom_chart_roc_curve.png?fit=max&auto=format&n=_OEDykSS2PIumrEw&q=85&s=1e23e67b4238b990c7b68a3fe5fcd245" alt="ROC curve" data-og-width="1338" width="1338" data-og-height="788" height="788" data-path="images/track/demo_custom_chart_roc_curve.png" data-optimize="true" data-opv="3" srcset="https://mintcdn.com/wb-21fd5541/_OEDykSS2PIumrEw/images/track/demo_custom_chart_roc_curve.png?w=280&fit=max&auto=format&n=_OEDykSS2PIumrEw&q=85&s=299490b54a28c52f82c42fab10da9aca 280w, https://mintcdn.com/wb-21fd5541/_OEDykSS2PIumrEw/images/track/demo_custom_chart_roc_curve.png?w=560&fit=max&auto=format&n=_OEDykSS2PIumrEw&q=85&s=1ac576aefe202055fb76504c9a9d3e7a 560w, https://mintcdn.com/wb-21fd5541/_OEDykSS2PIumrEw/images/track/demo_custom_chart_roc_curve.png?w=840&fit=max&auto=format&n=_OEDykSS2PIumrEw&q=85&s=237dea670615874e28ddf135a36fa373 840w, https://mintcdn.com/wb-21fd5541/_OEDykSS2PIumrEw/images/track/demo_custom_chart_roc_curve.png?w=1100&fit=max&auto=format&n=_OEDykSS2PIumrEw&q=85&s=09ca2bc510168269ec6b3f7e60b9541a 1100w, https://mintcdn.com/wb-21fd5541/_OEDykSS2PIumrEw/images/track/demo_custom_chart_roc_curve.png?w=1650&fit=max&auto=format&n=_OEDykSS2PIumrEw&q=85&s=a34615dcbc8088b79fd2992f9dc5a5f1 1650w, https://mintcdn.com/wb-21fd5541/_OEDykSS2PIumrEw/images/track/demo_custom_chart_roc_curve.png?w=2500&fit=max&auto=format&n=_OEDykSS2PIumrEw&q=85&s=91467cb1fff0e25014169912abcd2c76 2500w" />


[See in the app](https://wandb.ai/wandb/plots/reports/Plot-ROC-Curves--VmlldzoyNjk3MDE)

[Run the code](https://colab.research.google.com/github/wandb/examples/blob/master/colabs/wandb-log/Plot_ROC_Curves_with_W%26B.ipynb)
  <span class="tab-end"></span>

  <span class="tab-start" data-tab-title="Confusion matrix"></span>
Create a multi-class [confusion matrix](https://scikit-learn.org/stable/auto_examples/model_selection/plot_confusion_matrix.html) in one line:

```python
    import wandb

    cm = wandb.plot.confusion_matrix(
        y_true=ground_truth, preds=predictions, class_names=class_names
    )

    with wandb.init() as run:
        run.log({"conf_mat": cm})
    ```

You can log this wherever your code has access to:

* a model's predicted labels on a set of examples (`preds`) or the normalized probability scores (`probs`). The probabilities must have the shape (number of examples, number of classes). You can supply either probabilities or predictions but not both.
* the corresponding ground truth labels for those examples (`y_true`)
* a full list of the labels/class names as strings of `class_names`. Examples: `class_names=["cat", "dog", "bird"]` if index 0 is `cat`, 1 is `dog`, 2 is `bird`.


  <img src="https://mintcdn.com/wb-21fd5541/88iR80mZ8tuFCZUU/images/experiments/confusion_matrix.png?fit=max&auto=format&n=88iR80mZ8tuFCZUU&q=85&s=eb980135fce1c4b0960f03cef572420a" alt="Confusion matrix" data-og-width="1070" width="1070" data-og-height="422" height="422" data-path="images/experiments/confusion_matrix.png" data-optimize="true" data-opv="3" srcset="https://mintcdn.com/wb-21fd5541/88iR80mZ8tuFCZUU/images/experiments/confusion_matrix.png?w=280&fit=max&auto=format&n=88iR80mZ8tuFCZUU&q=85&s=12b711fa3c1d314da73b7304793f8fe0 280w, https://mintcdn.com/wb-21fd5541/88iR80mZ8tuFCZUU/images/experiments/confusion_matrix.png?w=560&fit=max&auto=format&n=88iR80mZ8tuFCZUU&q=85&s=26de55889c321d365054fc48ab1d4d3e 560w, https://mintcdn.com/wb-21fd5541/88iR80mZ8tuFCZUU/images/experiments/confusion_matrix.png?w=840&fit=max&auto=format&n=88iR80mZ8tuFCZUU&q=85&s=bbb70f7e104b4e5bc057cf6c39263538 840w, https://mintcdn.com/wb-21fd5541/88iR80mZ8tuFCZUU/images/experiments/confusion_matrix.png?w=1100&fit=max&auto=format&n=88iR80mZ8tuFCZUU&q=85&s=50cfa3f719fec5cac95975f5baf7c737 1100w, https://mintcdn.com/wb-21fd5541/88iR80mZ8tuFCZUU/images/experiments/confusion_matrix.png?w=1650&fit=max&auto=format&n=88iR80mZ8tuFCZUU&q=85&s=e6dc00dbd9eb9dd24f7515a402569ac8 1650w, https://mintcdn.com/wb-21fd5541/88iR80mZ8tuFCZUU/images/experiments/confusion_matrix.png?w=2500&fit=max&auto=format&n=88iR80mZ8tuFCZUU&q=85&s=e2e0fe32c902c292b85bdfb321cf0745 2500w" />


[See in the app](https://wandb.ai/wandb/plots/reports/Confusion-Matrix--VmlldzozMDg1NTM)

[Run the code](https://colab.research.google.com/github/wandb/examples/blob/master/colabs/wandb-log/Log_a_Confusion_Matrix_with_W%26B.ipynb)
  <span class="tab-end"></span>
<span class="tab-group-end"></span>

### Interactive custom charts

For full customization, tweak a built-in [Custom Chart preset](/models/app/features/custom-charts/walkthrough/) or create a new preset, then save the chart. Use the chart ID to log data to that custom preset directly from your script.

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

# Map from the table's columns to the chart's fields
fields = {"x": "step", "value": "height"}

# Use the table to populate the new custom chart preset
# To use your own saved chart preset, change the vega_spec_name
# To edit the title, change the string_fields
my_custom_chart = wandb.plot_table(
    vega_spec_name="carey/new_chart",
    data_table=table,
    fields=fields,
    string_fields={"title": "Height Histogram"},
)

with wandb.init() as run:
    # Log the custom chart
    run.log({"my_custom_chart": my_custom_chart})

Run the code

Matplotlib and Plotly plots#

Instead of using W&B Custom Charts with wandb.plot(), you can log charts generated with matplotlib and Plotly.

import wandb
import matplotlib.pyplot as plt

with wandb.init() as run:
    # Create a simple matplotlib plot
    plt.figure()
    plt.plot([1, 2, 3, 4])
    plt.ylabel("some interesting numbers")
    
    # Log the plot to W&B
    run.log({"chart": plt})

Just pass a matplotlib plot or figure object to wandb.Run.log(). By default we’ll convert the plot into a Plotly plot. If you’d rather log the plot as an image, you can pass the plot into wandb.Image. We also accept Plotly charts directly.

If you’re getting an error “You attempted to log an empty plot” then you can store the figure separately from the plot with fig = plt.figure() and then log fig in your call to wandb.Run.log().

Log custom HTML to W&B Tables#

W&B supports logging interactive charts from Plotly and Bokeh as HTML and adding them to Tables.

Log Plotly figures to Tables as HTML#

You can log interactive Plotly charts to wandb Tables by converting them to HTML.

import wandb
import plotly.express as px

# Initialize a new run
with wandb.init(project="log-plotly-fig-tables", name="plotly_html") as run:

    # Create a table
    table = wandb.Table(columns=["plotly_figure"])

    # Create path for Plotly figure
    path_to_plotly_html = "./plotly_figure.html"

    # Example Plotly figure
    fig = px.scatter(x=[0, 1, 2, 3, 4], y=[0, 1, 4, 9, 16])

    # Write Plotly figure to HTML
    # Set auto_play to False prevents animated Plotly charts
    # from playing in the table automatically
    fig.write_html(path_to_plotly_html, auto_play=False)

    # Add Plotly figure as HTML file into Table
    table.add_data(wandb.Html(path_to_plotly_html))

    # Log Table
    run.log({"test_table": table})

Log Bokeh figures to Tables as HTML#

You can log interactive Bokeh charts to wandb Tables by converting them to HTML.

from scipy.signal import spectrogram
import holoviews as hv
import panel as pn
from scipy.io import wavfile
import numpy as np
from bokeh.resources import INLINE

hv.extension("bokeh", logo=False)
import wandb


def save_audio_with_bokeh_plot_to_html(audio_path, html_file_name):
    sr, wav_data = wavfile.read(audio_path)
    duration = len(wav_data) / sr
    f, t, sxx = spectrogram(wav_data, sr)
    spec_gram = hv.Image((t, f, np.log10(sxx)), ["Time (s)", "Frequency (hz)"]).opts(
        width=500, height=150, labelled=[]
    )
    audio = pn.pane.Audio(wav_data, sample_rate=sr, name="Audio", throttle=500)
    slider = pn.widgets.FloatSlider(end=duration, visible=False)
    line = hv.VLine(0).opts(color="white")
    slider.jslink(audio, value="time", bidirectional=True)
    slider.jslink(line, value="glyph.location")
    combined = pn.Row(audio, spec_gram * line, slider).save(html_file_name)


html_file_name = "audio_with_plot.html"
audio_path = "hello.wav"
save_audio_with_bokeh_plot_to_html(audio_path, html_file_name)

wandb_html = wandb.Html(html_file_name)

with wandb.init(project="audio_test") as run:
    my_table = wandb.Table(columns=["audio_with_plot"], data=[[wandb_html]])
    run.log({"audio_table": my_table})
Link last verified June 7, 2026. View original ↗
Source: Weights & Biases Docs
Link last verified: 2026-03-04