Một biểu đồ tốt truyền đạt thông tin nhanh hơn nhiều so với bảng số liệu. Matplotlib là thư viện vẽ biểu đồ nền tảng của Python — hơi rườm rà lúc đầu, nhưng cho bạn quyền kiểm soát tới từng chi tiết.
Hai cách dùng Matplotlib
Matplotlib có hai giao diện, và việc trộn lẫn chúng là nguồn gốc của nhiều nhầm lẫn.
import matplotlib.pyplot as plt
# Cách 1: pyplot — nhanh, hợp cho biểu đồ đơn giản
plt.plot([1, 2, 3], [4, 5, 6])
plt.show()
# Cách 2: hướng đối tượng — nên dùng cho mọi thứ nghiêm túc
fig, ax = plt.subplots()
ax.plot([1, 2, 3], [4, 5, 6])
plt.show()
Hãy tập dùng cách thứ hai ngay từ đầu. Khi biểu đồ có nhiều phần hoặc bạn muốn tùy chỉnh sâu, cách hướng đối tượng rõ ràng hơn hẳn.
Hiển thị tiếng Việt
Font mặc định của Matplotlib không có dấu tiếng Việt, nhãn sẽ hiện thành ô vuông. Chỉ định font hỗ trợ Unicode:
plt.rcParams["font.family"] = "DejaVu Sans"
# Trên Windows có thể dùng: "Segoe UI", "Tahoma"
# Trên macOS: "Arial Unicode MS"
DejaVu Sans có sẵn cùng Matplotlib nên đây là lựa chọn an toàn nhất khi code cần chạy trên nhiều máy khác nhau.
Các loại biểu đồ thường dùng
Biểu đồ đường — thể hiện xu hướng theo thời gian
import numpy as np
thang = ["T1", "T2", "T3", "T4", "T5", "T6"]
doanh_thu = [120, 135, 128, 156, 172, 168]
fig, ax = plt.subplots(figsize=(10, 5))
ax.plot(thang, doanh_thu, marker="o", linewidth=2, color="#2563eb")
ax.set_title("Doanh thu 6 tháng đầu năm", fontsize=14, fontweight="bold")
ax.set_xlabel("Tháng")
ax.set_ylabel("Doanh thu (triệu đồng)")
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig("doanh_thu.png", dpi=150)
Biểu đồ cột — so sánh giữa các nhóm
phong_ban = ["Kỹ thuật", "Kinh doanh", "Marketing", "Nhân sự"]
so_nguoi = [45, 32, 18, 12]
fig, ax = plt.subplots(figsize=(9, 5))
thanh = ax.bar(phong_ban, so_nguoi, color="#0ea5e9")
ax.bar_label(thanh, padding=3) # hiện số ngay trên cột
ax.set_ylabel("Số nhân viên")
ax.set_title("Quy mô các phòng ban")
ax.spines[["top", "right"]].set_visible(False)
plt.tight_layout()
Hai dòng cuối là những chi tiết nhỏ tạo khác biệt lớn: bar_label giúp người xem đọc số chính xác mà không phải dóng theo trục, còn việc ẩn đường viền trên và phải làm biểu đồ trông sạch hơn.
Biểu đồ phân tán — tìm mối tương quan
rng = np.random.default_rng(42)
kinh_nghiem = rng.uniform(0, 15, 100)
luong = 8 + kinh_nghiem * 1.2 + rng.normal(0, 2, 100)
fig, ax = plt.subplots(figsize=(8, 6))
ax.scatter(kinh_nghiem, luong, alpha=0.6, s=50, color="#8b5cf6")
# Thêm đường xu hướng
he_so = np.polyfit(kinh_nghiem, luong, 1)
x = np.linspace(0, 15, 100)
ax.plot(x, np.polyval(he_so, x), "r--", linewidth=2, label="Xu hướng")
ax.set_xlabel("Số năm kinh nghiệm")
ax.set_ylabel("Lương (triệu đồng)")
ax.legend()
Biểu đồ tần suất — xem phân bố dữ liệu
du_lieu = rng.normal(170, 8, 1000)
fig, ax = plt.subplots(figsize=(9, 5))
ax.hist(du_lieu, bins=30, color="#10b981", edgecolor="white")
ax.axvline(du_lieu.mean(), color="red", linestyle="--",
label=f"Trung bình: {du_lieu.mean():.1f}")
ax.set_xlabel("Chiều cao (cm)")
ax.set_ylabel("Số người")
ax.legend()
Nhiều biểu đồ trong một hình
fig, axes = plt.subplots(2, 2, figsize=(12, 8))
axes[0, 0].plot(thang, doanh_thu)
axes[0, 0].set_title("Doanh thu")
axes[0, 1].bar(phong_ban, so_nguoi)
axes[0, 1].set_title("Nhân sự")
axes[1, 0].scatter(kinh_nghiem, luong, alpha=0.5)
axes[1, 0].set_title("Kinh nghiệm và lương")
axes[1, 1].hist(du_lieu, bins=20)
axes[1, 1].set_title("Phân bố chiều cao")
fig.suptitle("Báo cáo tổng hợp", fontsize=16, fontweight="bold")
plt.tight_layout()
Luôn gọi tight_layout() trước khi lưu. Không có nó, nhãn trục thường bị cắt mất ở rìa hình.
Lưu hình đúng cách
plt.savefig("bieu_do.png", dpi=150, bbox_inches="tight")
plt.savefig("bieu_do.svg") # vector, phóng to không vỡ
plt.savefig("bieu_do.pdf") # cho tài liệu in ấn
Với biểu đồ đưa vào báo cáo hoặc trang web, hãy dùng SVG. Định dạng vector giữ nét ở mọi kích thước và thường nhẹ hơn PNG độ phân giải cao.
Vài nguyên tắc trình bày
- Trục tung của biểu đồ cột phải bắt đầu từ 0. Cắt trục làm phóng đại chênh lệch và dễ gây hiểu sai.
- Đừng dùng biểu đồ tròn khi có quá 5 phần. Mắt người so sánh chiều dài tốt hơn so sánh góc — biểu đồ cột thường rõ ràng hơn.
- Ghi rõ đơn vị trên nhãn trục. “Doanh thu” không nói lên điều gì; “Doanh thu (triệu đồng)” thì có.
- Cân nhắc người mù màu. Tránh phân biệt các nhóm chỉ bằng đỏ và xanh lá; thêm ký hiệu hoặc kiểu nét khác nhau.
Khi nào dùng thư viện khác
Matplotlib mạnh nhưng dài dòng. Với các biểu đồ thống kê thông dụng, Seaborn viết ngắn hơn nhiều và mặc định đẹp hơn:
import seaborn as sns
sns.boxplot(data=df, x="phong_ban", y="luong")
Nếu bạn cần biểu đồ tương tác cho trang web hoặc dashboard, hãy xem Plotly. Còn Matplotlib vẫn là lựa chọn tốt nhất khi cần kiểm soát tuyệt đối từng chi tiết, hoặc xuất hình cho báo cáo và tài liệu in.