scikit-learn
confusion matrix
data visualization
machine learning
Python

sklearn plot confusion matrix with labels

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

Introduction

In current scikit-learn, the clean way to plot a confusion matrix with class labels is to use ConfusionMatrixDisplay, not the older plot_confusion_matrix helper. You can create the plot either from predictions you already have or directly from an estimator. The label names are supplied through display_labels.

The Current API

The modern display class supports two common entry points:

  • 'ConfusionMatrixDisplay.from_predictions'
  • 'ConfusionMatrixDisplay.from_estimator'

If you already computed y_pred, use from_predictions. If you have a fitted classifier and test data, from_estimator is convenient.

Example with Labels

python
1import matplotlib.pyplot as plt
2from sklearn.datasets import load_iris
3from sklearn.ensemble import RandomForestClassifier
4from sklearn.metrics import ConfusionMatrixDisplay
5from sklearn.model_selection import train_test_split
6
7X, y = load_iris(return_X_y=True)
8class_names = ["setosa", "versicolor", "virginica"]
9
10X_train, X_test, y_train, y_test = train_test_split(
11    X, y, test_size=0.2, random_state=42
12)
13
14model = RandomForestClassifier(random_state=42)
15model.fit(X_train, y_train)
16
17disp = ConfusionMatrixDisplay.from_estimator(
18    model,
19    X_test,
20    y_test,
21    display_labels=class_names,
22    cmap="Blues",
23)
24
25plt.show()

That produces a labeled confusion matrix with readable class names instead of numeric indices.

If You Already Have Predictions

Use from_predictions when prediction generation is separate from plotting.

python
1from sklearn.metrics import ConfusionMatrixDisplay
2
3y_pred = model.predict(X_test)
4
5ConfusionMatrixDisplay.from_predictions(
6    y_test,
7    y_pred,
8    display_labels=class_names,
9    cmap="Blues",
10)
11
12plt.show()

This is especially useful when you want to compare several models using the same stored predictions.

It also makes evaluation code easier to separate from training code. The plotting function no longer needs to know how the model was fit; it only needs the true labels, predicted labels, and optional display names.

Normalized Confusion Matrices

Raw counts are useful, but normalized values often make class imbalance easier to interpret.

python
1ConfusionMatrixDisplay.from_predictions(
2    y_test,
3    y_pred,
4    display_labels=class_names,
5    normalize="true",
6    cmap="Blues",
7)
8
9plt.show()

Common normalization choices are:

  • '"true": normalize by actual class'
  • '"pred": normalize by predicted class'
  • '"all": normalize by the total sample count'

Be explicit about which version you are showing. A raw confusion matrix answers “how many examples landed in each cell,” while a normalized one answers “what proportion of a class ended up in each cell.” Those are both useful, but they are not interchangeable.

Why plot_confusion_matrix Is Not the Best Answer Anymore

A lot of older examples use plot_confusion_matrix, but scikit-learn moved toward ConfusionMatrixDisplay as the current display interface. If you copy old snippets blindly, you may run into deprecation warnings or missing helpers depending on your installed version.

So if your goal is current scikit-learn code, use ConfusionMatrixDisplay directly.

Choosing Good Labels

The display_labels argument should match the class order used by the confusion matrix. When your target labels are integers but you want readable names, provide a list in the same class order.

If you are unsure, inspect model.classes_ after fitting.

For binary classification, do not stop at the heatmap alone. Read it alongside precision, recall, and class support so you know whether the visually larger cells are just reflecting class imbalance rather than genuinely strong performance.

Common Pitfalls

A common mistake is passing label names in the wrong order. That makes the plot look polished but semantically wrong.

Another mistake is using outdated examples that call deprecated plotting helpers instead of ConfusionMatrixDisplay.

A third issue is reading only the diagonal counts and ignoring class imbalance. A normalized confusion matrix often reveals model weakness more clearly than raw totals.

Summary

  • Use ConfusionMatrixDisplay.from_estimator or from_predictions in current scikit-learn
  • Pass readable class names through display_labels
  • Use normalized plots when raw counts are hard to compare
  • Check class order before labeling the axes
  • Prefer the current display API over older deprecated confusion-matrix helpers

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

All Rights Reserved.