How to plot a confusion matrix with scikit-learn

A confusion matrix turns held-out classification predictions into a class-by-class count table. In scikit-learn, plotting the matrix makes label mix-ups visible so a classifier review does not depend on accuracy alone.

The ConfusionMatrixDisplay helper can draw the matrix from a fitted estimator or from already computed predictions. Using from_predictions() fits evaluation scripts where y_test and y_pred already exist, and it avoids asking the estimator to predict again.

Keep the label order consistent between the printed matrix, display_labels, and any classification report. Rows represent true labels and columns represent predicted labels, so diagonal cells are correct classifications and off-diagonal cells show the mistakes to review.

Steps to plot a scikit-learn confusion matrix:

  1. Create confusion_matrix_plot_demo.py with held-out labels, predictions, and a noninteractive Matplotlib backend.
    confusion_matrix_plot_demo.py
    from pathlib import Path
     
    import matplotlib
     
    matplotlib.use("Agg")
     
    import matplotlib.pyplot as plt
    import sklearn
    from sklearn.datasets import load_wine
    from sklearn.metrics import ConfusionMatrixDisplay, confusion_matrix
    from sklearn.model_selection import train_test_split
    from sklearn.tree import DecisionTreeClassifier
     
     
    wine = load_wine()
    X_train, X_test, y_train, y_test = train_test_split(
        wine.data,
        wine.target,
        test_size=0.30,
        stratify=wine.target,
        random_state=7,
    )
     
    model = DecisionTreeClassifier(max_depth=3, random_state=7)
    model.fit(X_train, y_train)
     
    y_pred = model.predict(X_test)
    matrix = confusion_matrix(y_test, y_pred)
    output_path = Path("confusion-matrix-display.png")
     
    fig, ax = plt.subplots(figsize=(6, 5))
    ConfusionMatrixDisplay.from_predictions(
        y_test,
        y_pred,
        display_labels=wine.target_names,
        values_format="d",
        cmap="Blues",
        colorbar=False,
        ax=ax,
    )
    ax.set_title("Wine classifier confusion matrix")
    fig.tight_layout()
    fig.savefig(output_path, dpi=160, bbox_inches="tight")
     
    print(f"scikit-learn {sklearn.__version__}")
    print("labels: " + ", ".join(wine.target_names))
    print("confusion matrix:")
    print(matrix)
    print(f"saved plot: {output_path}")

    matplotlib.use(“Agg”) saves the plot from a shell, container, or job runner that does not have an interactive display.

  2. Run the plotting script.
    $ python3 confusion_matrix_plot_demo.py
    scikit-learn 1.9.0
    labels: class_0, class_1, class_2
    confusion matrix:
    [[15  3  0]
     [ 0 20  1]
     [ 0  0 15]]
    saved plot: confusion-matrix-display.png
  3. Check the off-diagonal counts before accepting the plot.

    The class_0 row shows 3 samples predicted as class_1, and the class_1 row shows 1 sample predicted as class_2. The diagonal cells show 15, 20, and 15 correct predictions.

  4. Open the saved PNG and confirm that the labels and counts match the printed matrix.

    Fix display_labels or pass an explicit labels order before sharing the plot if the class names do not match the matrix order.