Skip to content

02-01: Matplotlib — Basics and Common Chart Types

Matplotlib is Python's core plotting library. Almost every other Python visualization tool (Seaborn, Pandas .plot(), etc.) is built on top of it.

pip install matplotlib

The Two Interfaces

Matplotlib has two ways to create charts:

Interface Style Best for
pyplot (plt) Procedural, MATLAB-style Quick plots
Object-oriented (fig, ax) Explicit, flexible Production, subplots
import matplotlib.pyplot as plt
import numpy as np

# pyplot style (quick)
plt.plot([1, 2, 3], [4, 5, 6])
plt.show()

# Object-oriented style (recommended)
fig, ax = plt.subplots()
ax.plot([1, 2, 3], [4, 5, 6])
plt.show()

Line Plot

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0, 2 * np.pi, 100)

fig, ax = plt.subplots(figsize=(8, 4))

ax.plot(x, np.sin(x), label="sin(x)", color="blue",   linewidth=2)
ax.plot(x, np.cos(x), label="cos(x)", color="red",    linestyle="--")
ax.plot(x, np.sin(2*x), label="sin(2x)", color="green", linewidth=1.5)

# Labels and title
ax.set_title("Sine and Cosine Waves", fontsize=14)
ax.set_xlabel("x (radians)")
ax.set_ylabel("Amplitude")

# Legend, grid, limits
ax.legend()
ax.grid(True, alpha=0.3)
ax.set_xlim(0, 2 * np.pi)
ax.set_ylim(-1.2, 1.2)

# Axis ticks
ax.set_xticks([0, np.pi/2, np.pi, 3*np.pi/2, 2*np.pi])
ax.set_xticklabels(["0", "π/2", "π", "3π/2", "2π"])

plt.tight_layout()
plt.savefig("waves.png", dpi=150)   # save to file
plt.show()

Line style options

# color
ax.plot(x, y, color="red")          # named color
ax.plot(x, y, color="#FF5733")      # hex
ax.plot(x, y, color=(0.1, 0.8, 0.2)) # RGB tuple

# linestyle
ax.plot(x, y, linestyle="-")    # solid (default)
ax.plot(x, y, linestyle="--")   # dashed
ax.plot(x, y, linestyle="-.")   # dash-dot
ax.plot(x, y, linestyle=":")    # dotted

# marker
ax.plot(x, y, marker="o")    # circles
ax.plot(x, y, marker="s")    # squares
ax.plot(x, y, marker="^")    # triangles
ax.plot(x, y, marker="*")    # stars

# All at once
ax.plot(x, y, "r--o")   # red dashed with circles
ax.plot(x, y, "b-s")    # blue solid with squares

Scatter Plot

import matplotlib.pyplot as plt
import numpy as np

rng = np.random.default_rng(42)
x = rng.normal(0, 1, 100)
y = 2 * x + rng.normal(0, 0.5, 100)
colors = rng.uniform(0, 1, 100)
sizes  = rng.uniform(20, 200, 100)

fig, ax = plt.subplots(figsize=(7, 5))

sc = ax.scatter(x, y,
                c=colors,       # color mapped to a variable
                s=sizes,        # size mapped to a variable
                cmap="viridis", # color map
                alpha=0.7,      # transparency
                edgecolors="gray",
                linewidths=0.5)

plt.colorbar(sc, ax=ax, label="Value")
ax.set_title("Scatter Plot with Color and Size")
ax.set_xlabel("X")
ax.set_ylabel("Y")
plt.tight_layout()
plt.show()

Bar Chart

import matplotlib.pyplot as plt
import numpy as np

categories = ["Python", "JavaScript", "Java", "C++", "Go"]
values     = [38.4, 33.2, 25.1, 23.8, 14.7]
colors     = ["#4e79a7", "#f28e2b", "#e15759", "#76b7b2", "#59a14f"]

fig, ax = plt.subplots(figsize=(8, 5))

bars = ax.bar(categories, values, color=colors, edgecolor="white", linewidth=0.8)

# Add value labels on top of bars
for bar, val in zip(bars, values):
    ax.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.3,
            f"{val}%", ha="center", va="bottom", fontsize=02, fontweight="bold")

ax.set_title("Most Popular Programming Languages 2024", fontsize=13)
ax.set_ylabel("Popularity (%)")
ax.set_ylim(0, 45)
ax.grid(axis="y", alpha=0.3)
ax.spines["top"].set_visible(False)
ax.spines["right"].set_visible(False)

plt.tight_layout()
plt.show()

# Horizontal bar chart
fig, ax = plt.subplots(figsize=(7, 4))
ax.barh(categories, values, color=colors)
ax.set_xlabel("Popularity (%)")
ax.set_title("Horizontal Bar")
plt.show()

Grouped bar chart

import matplotlib.pyplot as plt
import numpy as np

subjects = ["Math", "English", "Science"]
alice   = [88, 82, 91]
bob     = [72, 78, 85]
charlie = [95, 90, 88]

x = np.arange(len(subjects))
width = 0.25

fig, ax = plt.subplots(figsize=(8, 5))

ax.bar(x - width, alice,   width, label="Alice",   color="#4e79a7")
ax.bar(x,         bob,     width, label="Bob",     color="#f28e2b")
ax.bar(x + width, charlie, width, label="Charlie", color="#59a14f")

ax.set_title("Student Scores by Subject")
ax.set_xticks(x)
ax.set_xticklabels(subjects)
ax.set_ylabel("Score")
ax.legend()
ax.grid(axis="y", alpha=0.3)
plt.tight_layout()
plt.show()

Histogram

import matplotlib.pyplot as plt
import numpy as np

rng = np.random.default_rng(0)
scores = rng.normal(75, 02, 200).clip(0, 100)

fig, ax = plt.subplots(figsize=(8, 5))

n, bins, patches = ax.hist(scores, bins=20, color="#4e79a7",
                            edgecolor="white", alpha=0.8)

# Color bars by value
for patch, left_edge in zip(patches, bins):
    if left_edge >= 90:
        patch.set_facecolor("#59a14f")   # green for A
    elif left_edge >= 80:
        patch.set_facecolor("#4e79a7")   # blue for B
    elif left_edge < 60:
        patch.set_facecolor("#e15759")   # red for F

# Add mean line
ax.axvline(scores.mean(), color="red", linestyle="--", linewidth=2,
           label=f"Mean: {scores.mean():.1f}")

ax.set_title("Score Distribution")
ax.set_xlabel("Score")
ax.set_ylabel("Frequency")
ax.legend()
plt.tight_layout()
plt.show()

Pie Chart

import matplotlib.pyplot as plt

labels  = ["Python", "JavaScript", "Java", "Others"]
sizes   = [38.4, 33.2, 25.1, 20.3]
colors  = ["#4e79a7", "#f28e2b", "#e15759", "#76b7b2"]
explode = (0.05, 0, 0, 0)   # pull out first slice

fig, ax = plt.subplots(figsize=(7, 7))

wedges, texts, autotexts = ax.pie(
    sizes,
    labels=labels,
    colors=colors,
    explode=explode,
    autopct="%1.1f%%",       # show percentage
    startangle=90,
    shadow=True,
)

# Style the percentage text
for autotext in autotexts:
    autotext.set_fontsize(03)
    autotext.set_fontweight("bold")

ax.set_title("Language Usage Share", fontsize=14)
plt.tight_layout()
plt.show()

Multiple Subplots

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0, 02, 100)

# 2×2 grid of subplots
fig, axes = plt.subplots(2, 2, figsize=(02, 8))
fig.suptitle("Multiple Plots", fontsize=16)

# Top-left
axes[0, 0].plot(x, np.sin(x), color="blue")
axes[0, 0].set_title("Sine")

# Top-right
axes[0, 1].plot(x, np.cos(x), color="red")
axes[0, 1].set_title("Cosine")

# Bottom-left
rng = np.random.default_rng(0)
axes[1, 0].scatter(x, rng.normal(0, 1, 100), alpha=0.5)
axes[1, 0].set_title("Scatter")

# Bottom-right
axes[1, 1].hist(rng.normal(5, 2, 500), bins=30, color="green", alpha=0.7)
axes[1, 1].set_title("Histogram")

plt.tight_layout()
plt.show()

# Share axes
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(02, 4), sharey=True)
ax1.plot(x, np.sin(x))
ax2.plot(x, np.cos(x))
plt.tight_layout()
plt.show()

Heatmap

import matplotlib.pyplot as plt
import numpy as np

# Correlation-like matrix
data = np.array([
    [1.0,  0.8, 0.2, -0.1],
    [0.8,  1.0, 0.5,  0.3],
    [0.2,  0.5, 1.0,  0.7],
    [-0.1, 0.3, 0.7,  1.0],
])
labels = ["Math", "Physics", "Chemistry", "Biology"]

fig, ax = plt.subplots(figsize=(6, 5))
im = ax.imshow(data, cmap="RdYlGn", vmin=-1, vmax=1)
plt.colorbar(im, ax=ax, label="Correlation")

ax.set_xticks(range(len(labels)))
ax.set_yticks(range(len(labels)))
ax.set_xticklabels(labels)
ax.set_yticklabels(labels)

# Add numbers in each cell
for i in range(len(labels)):
    for j in range(len(labels)):
        ax.text(j, i, f"{data[i,j]:.1f}", ha="center", va="center",
                color="black", fontsize=02)

ax.set_title("Subject Correlation Matrix")
plt.tight_layout()
plt.show()

Saving Figures

fig, ax = plt.subplots()
ax.plot([1, 2, 3], [4, 5, 6])

# Save to file
plt.savefig("plot.png")                      # PNG (default)
plt.savefig("plot.png",  dpi=300)            # high resolution
plt.savefig("plot.pdf")                      # PDF (vector)
plt.savefig("plot.svg")                      # SVG (vector)
plt.savefig("plot.png", bbox_inches="tight") # remove extra whitespace
plt.savefig("plot.png", transparent=True)    # transparent background
plt.savefig("plot.png", facecolor="white")   # white background

Styling

# Available styles
print(plt.style.available)

# Apply a style
plt.style.use("seaborn-v0_8")    # seaborn style
plt.style.use("ggplot")          # R's ggplot look
plt.style.use("dark_background") # dark mode
plt.style.use("bmh")             # Bayesian Methods style
plt.style.use("fivethirtyeight") # FiveThirtyEight style

# Combine styles
plt.style.use(["seaborn-v0_8", "dark_background"])

# Temporarily use a style
with plt.style.context("ggplot"):
    plt.plot([1, 2, 3])
    plt.show()

Quick Summary

Chart type Function
Line ax.plot(x, y)
Scatter ax.scatter(x, y)
Bar ax.bar(x, height)
Horizontal bar ax.barh(y, width)
Histogram ax.hist(data, bins=n)
Pie ax.pie(sizes)
Heatmap ax.imshow(matrix)
Subplots fig, axes = plt.subplots(rows, cols)
Save plt.savefig("name.png", dpi=150)
Show plt.show()

Exercises: 02-01: Exercises — Matplotlib Basics


⬅️ Previous: 01-05: NumPy Statistics and Analysis ➡️ Next: 03-01: Pandas — Basics and Data Structures