matplotlib
Python
polygons
phase-diagram
data-visualization

How to plot polygons from categorical grid points in matplotlib? phase-diagram generation

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

If your phase diagram is sampled on a regular grid and each grid point belongs to a category, the first step is to convert those categories into integer codes. After that, you can either visualize the regions directly with pcolormesh or trace polygon-like boundaries for each category and add them as matplotlib patches.

Start with a Regular Grid and Category Labels

Suppose you sampled a phase diagram over temperature and composition, and each grid point was labeled alpha, beta, or liquid. Matplotlib needs numbers, not strings, so encode the categories first.

python
1import numpy as np
2
3x = np.linspace(0, 4, 9)
4y = np.linspace(0, 4, 9)
5X, Y = np.meshgrid(x, y)
6
7labels = np.where(
8    X + Y < 2.5,
9    "alpha",
10    np.where(Y > 2.5, "beta", "liquid")
11)
12
13phase_to_int = {"alpha": 0, "beta": 1, "liquid": 2}
14Z = np.vectorize(phase_to_int.get)(labels)

Now Z is a grid of integers that can drive both coloring and boundary extraction.

Visualize the Regions First

Before turning anything into polygons, it helps to verify the categorical field visually:

python
1import matplotlib.pyplot as plt
2from matplotlib.colors import ListedColormap
3
4cmap = ListedColormap(["#66c2a5", "#8da0cb", "#fc8d62"])
5
6fig, ax = plt.subplots()
7mesh = ax.pcolormesh(X, Y, Z, cmap=cmap, shading="nearest")
8
9ax.set_xlabel("x")
10ax.set_ylabel("y")
11ax.set_title("Categorical phase grid")
12plt.show()

For many applications, this alone is already good enough. pcolormesh shows the regions correctly as colored cells.

Trace Polygon Boundaries for Each Category

If you specifically need polygon-like outlines, contour each category mask at level 0.5 and convert the contour segments into Polygon patches.

python
1import matplotlib.pyplot as plt
2from matplotlib.colors import ListedColormap
3from matplotlib.patches import Polygon
4
5fig, ax = plt.subplots()
6ax.pcolormesh(X, Y, Z, cmap=cmap, shading="nearest", alpha=0.35)
7
8styles = [
9    ("alpha", 0, "#1b9e77"),
10    ("beta", 1, "#7570b3"),
11    ("liquid", 2, "#d95f02"),
12]
13
14for name, value, edgecolor in styles:
15    mask = (Z == value).astype(float)
16    contour = ax.contour(X, Y, mask, levels=[0.5], colors=edgecolor, linewidths=1.5)
17
18    for segment in contour.allsegs[0]:
19        if len(segment) >= 3:
20            patch = Polygon(
21                segment,
22                closed=True,
23                facecolor="none",
24                edgecolor=edgecolor,
25                linewidth=2
26            )
27            ax.add_patch(patch)
28
29ax.set_xlabel("x")
30ax.set_ylabel("y")
31ax.set_title("Phase regions with polygon boundaries")
32plt.show()

This works because each boolean mask creates a contour around the connected region where that category is present. The contour segments provide the vertices for your polygon patches.

Why This Works for Phase Diagrams

A phase diagram built from categorical grid points is really a classification map. The polygon boundary you want is the boundary of each connected class region. On a regular grid, contouring the category mask is a straightforward way to approximate that boundary.

That makes the workflow:

  1. classify each grid point
  2. convert class names to numeric codes
  3. visualize the full field
  4. contour each class mask to extract boundaries

It is simple, fast, and stays inside matplotlib.

When the Grid Is Coarse or Noisy

If the grid is sparse, the polygon boundaries will look blocky or jagged. That is not a matplotlib bug. It reflects the resolution of the original sampled data.

You can improve the result by:

  • sampling a finer grid
  • smoothing or interpolating before classification
  • post-processing small isolated regions before plotting

Those choices depend on whether the goal is scientific fidelity or a cleaner presentation figure.

Common Pitfalls

The biggest pitfall is trying to contour string labels directly. Convert categories to integer codes first.

Another issue is expecting a coarse grid to produce smooth physical boundaries. The extracted polygons can only be as accurate as the categorical field you generated.

It is also easy to forget that disconnected islands of the same phase create multiple contour segments. That is normal and should be handled as multiple polygons, not treated as a bug.

Summary

  • Encode categorical phase labels as integers before plotting.
  • Use pcolormesh first to verify the phase grid visually.
  • Extract polygon-like boundaries by contouring a boolean mask for each category.
  • Convert contour segments into Polygon patches when you need explicit matplotlib polygon objects.
  • If the boundaries look jagged, the underlying grid resolution is usually the real cause.

Course illustration
Course illustration

All Rights Reserved.