SVM
R programming
classification graph
data visualization
machine learning

How do I plot a classification graph of a SVM in R

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

To plot an SVM classification graph in R, use the plot() method from the e1071 package on an svm object. This displays the decision boundary and support vectors for two-feature classification. For more customizable plots, use ggplot2 with a grid of predicted values to visualize the decision regions. Both approaches require the data to have exactly two features (or you must select two features to plot).

Basic SVM Plot with e1071

r
1library(e1071)
2
3# Use the iris dataset (select 2 features and 2 classes for simplicity)
4data <- iris[iris$Species != "setosa", ]
5data$Species <- droplevels(data$Species)
6
7# Train SVM with 2 features
8model <- svm(Species ~ Sepal.Length + Sepal.Width, data = data, kernel = "radial")
9
10# Plot the decision boundary
11plot(model, data, Sepal.Length ~ Sepal.Width)

The plot() method shows:

  • Colored regions for each class's decision area
  • Data points marked by class
  • Support vectors highlighted with crosses

Customizing the e1071 Plot

r
1plot(model, data, Sepal.Length ~ Sepal.Width,
2     svSymbol = "x",        # Symbol for support vectors
3     dataSymbol = "o",      # Symbol for data points
4     symbolPalette = c("red", "blue"),
5     color.palette = terrain.colors,
6     main = "SVM Classification")

ggplot2 Visualization (More Control)

r
1library(e1071)
2library(ggplot2)
3
4# Prepare data
5data <- iris[iris$Species != "setosa", ]
6data$Species <- droplevels(data$Species)
7
8# Train SVM
9model <- svm(Species ~ Sepal.Length + Sepal.Width, data = data, kernel = "radial")
10
11# Create a grid of points covering the feature space
12x_range <- seq(min(data$Sepal.Length) - 0.5, max(data$Sepal.Length) + 0.5, length.out = 200)
13y_range <- seq(min(data$Sepal.Width) - 0.5, max(data$Sepal.Width) + 0.5, length.out = 200)
14grid <- expand.grid(Sepal.Length = x_range, Sepal.Width = y_range)
15
16# Predict class for each grid point
17grid$Predicted <- predict(model, grid)
18
19# Plot
20ggplot() +
21  geom_tile(data = grid, aes(x = Sepal.Length, y = Sepal.Width, fill = Predicted),
22            alpha = 0.3) +
23  geom_point(data = data, aes(x = Sepal.Length, y = Sepal.Width,
24             color = Species, shape = Species), size = 3) +
25  scale_fill_manual(values = c("versicolor" = "lightblue", "virginica" = "lightyellow")) +
26  scale_color_manual(values = c("versicolor" = "blue", "virginica" = "red")) +
27  labs(title = "SVM Decision Boundary", x = "Sepal Length", y = "Sepal Width") +
28  theme_minimal()

Highlighting Support Vectors

r
1# Get support vector indices
2sv_indices <- model$index
3
4# Add support vector flag to data
5data$is_sv <- seq_len(nrow(data)) %in% sv_indices
6
7ggplot() +
8  geom_tile(data = grid, aes(x = Sepal.Length, y = Sepal.Width, fill = Predicted),
9            alpha = 0.3) +
10  geom_point(data = data[!data$is_sv, ],
11             aes(x = Sepal.Length, y = Sepal.Width, color = Species), size = 2) +
12  geom_point(data = data[data$is_sv, ],
13             aes(x = Sepal.Length, y = Sepal.Width, color = Species),
14             size = 4, shape = 4, stroke = 2) +  # Crosses for SVs
15  labs(title = "SVM with Support Vectors Highlighted") +
16  theme_minimal()

Different Kernel Comparison

r
1kernels <- c("linear", "radial", "polynomial", "sigmoid")
2plots <- list()
3
4for (k in kernels) {
5  model <- svm(Species ~ Sepal.Length + Sepal.Width, data = data, kernel = k)
6  grid$Predicted <- predict(model, grid)
7
8  p <- ggplot() +
9    geom_tile(data = grid, aes(x = Sepal.Length, y = Sepal.Width, fill = Predicted),
10              alpha = 0.3) +
11    geom_point(data = data, aes(x = Sepal.Length, y = Sepal.Width, color = Species),
12               size = 2) +
13    labs(title = paste("Kernel:", k)) +
14    theme_minimal() +
15    theme(legend.position = "none")
16
17  plots[[k]] <- p
18}
19
20# Display all four plots
21library(gridExtra)
22grid.arrange(grobs = plots, ncol = 2)

Multi-Class SVM Plot

r
1# All 3 iris classes with 2 features
2model <- svm(Species ~ Sepal.Length + Sepal.Width, data = iris, kernel = "radial")
3
4grid <- expand.grid(
5  Sepal.Length = seq(min(iris$Sepal.Length) - 0.5, max(iris$Sepal.Length) + 0.5, length.out = 200),
6  Sepal.Width = seq(min(iris$Sepal.Width) - 0.5, max(iris$Sepal.Width) + 0.5, length.out = 200)
7)
8grid$Predicted <- predict(model, grid)
9
10ggplot() +
11  geom_tile(data = grid, aes(x = Sepal.Length, y = Sepal.Width, fill = Predicted),
12            alpha = 0.3) +
13  geom_point(data = iris, aes(x = Sepal.Length, y = Sepal.Width, color = Species),
14             size = 2) +
15  scale_fill_manual(values = c("setosa" = "lightgreen", "versicolor" = "lightblue",
16                                "virginica" = "lightyellow")) +
17  labs(title = "Multi-Class SVM Decision Regions") +
18  theme_minimal()

Plotting with Decision Values (Margins)

r
1model <- svm(Species ~ Sepal.Length + Sepal.Width, data = data,
2             kernel = "radial", decision.values = TRUE)
3
4# Get decision values for the grid
5pred <- predict(model, grid, decision.values = TRUE)
6grid$decision_value <- as.numeric(attr(pred, "decision.values"))
7
8ggplot() +
9  geom_tile(data = grid, aes(x = Sepal.Length, y = Sepal.Width, fill = decision_value)) +
10  scale_fill_gradient2(low = "blue", mid = "white", high = "red", midpoint = 0) +
11  geom_contour(data = grid, aes(x = Sepal.Length, y = Sepal.Width, z = decision_value),
12               breaks = c(-1, 0, 1), color = "black") +
13  geom_point(data = data, aes(x = Sepal.Length, y = Sepal.Width, shape = Species),
14             size = 3) +
15  labs(title = "SVM Decision Boundary with Margins") +
16  theme_minimal()

The contour lines at z = -1, z = 0, and z = 1 show the decision boundary and the margin boundaries.

Common Pitfalls

  • More than 2 features: SVM decision boundaries in 2D can only be plotted for 2 features. If your model uses more features, select the 2 most important ones for visualization or use dimensionality reduction (PCA) to project to 2D before plotting.
  • Grid resolution too low: Using too few grid points (e.g., length.out = 50) makes the decision boundary look pixelated. Use at least 100-200 points per axis for smooth boundaries, but balance against computation time.
  • Factor levels not dropped: After subsetting data (e.g., removing "setosa"), unused factor levels remain. Use droplevels() to remove them, otherwise the SVM trains with phantom classes.
  • Kernel mismatch with data: A linear kernel cannot capture non-linear boundaries. If the classes overlap in complex ways, try kernel = "radial". If the plot shows poor separation, tune the cost and gamma parameters.
  • Forgetting to scale features: SVM is sensitive to feature scales. If one feature ranges 0-1 and another ranges 0-1000, the SVM is dominated by the larger feature. Use scale = TRUE (the default in e1071::svm) to standardize features before training.

Summary

  • Use plot(model, data, Feature1 ~ Feature2) from e1071 for quick SVM visualization
  • Use ggplot2 with a prediction grid for customizable decision boundary plots
  • Highlight support vectors by extracting model$index and plotting them differently
  • Compare kernels by training multiple models and arranging plots with gridExtra
  • Only 2 features can be visualized directly — use PCA for higher-dimensional data

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the 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.