Python Viz 1 — Bức tranh công cụ trực quan hoá dữ liệu

13 thg 7, 2026 4 lượt xem
#visualization
#dataviz
#python
#matplotlib
#plotly

Vì sao trực quan hoá bằng code, chứ không phải kéo-thả

Trong một phòng phân tích ngân hàng, phần lớn biểu đồ vẫn ra đời trong Excel: copy dữ liệu từ query, chọn dải ô, bấm Insert Chart, chỉnh màu bằng chuột, rồi dán vào PowerPoint. Cách này nhanh cho một lần, nhưng nó có một khuyết tật chí mạng: không tái lập được. Tháng sau số liệu đổi, bạn phải làm lại từ đầu — copy lại, chỉnh lại, dễ sai lệch định dạng. Không ai kiểm tra được biểu đồ này lấy dữ liệu từ đâu, lọc điều kiện gì, cắt kỳ nào. Khi sếp hỏi "biểu đồ nợ xấu quý trước vẽ thế nào?", câu trả lời thường là "để em làm lại".

Trực quan hoá bằng code (Python) lật ngược bài toán. Biểu đồ trở thành một hàm của dữ liệu: cùng một script, cùng nguồn dữ liệu, luôn ra cùng một hình. Ưu điểm cụ thể:

  • Tái lập (reproducible): script + dữ liệu = biểu đồ. Lưu vào Git, ai chạy cũng ra kết quả giống nhau, có lịch sử thay đổi.
  • Tự động hoá: gắn vào pipeline hay lịch chạy (cron/Airflow), báo cáo tự sinh mỗi sáng, không cần người ngồi copy-paste.
  • Tích hợp trực tiếp với dữ liệu: vẽ thẳng từ DataFrame pandas/Polars ngay sau bước xử lý, không qua bước xuất Excel trung gian dễ lỗi.
  • Quy mô lớn: vẽ trăm biểu đồ cho trăm chi nhánh bằng một vòng lặp; Excel thì bó tay.
  • Notebook: kể chuyện dữ liệu xen code, chữ và hình trong cùng một tài liệu (Jupyter), rất hợp cho phân tích khám phá.

Công cụ BI kéo-thả (Power BI, Tableau, Metabase) vẫn tuyệt vời cho dashboard tự phục vụ cho người không code. Nhưng cho phân tích ad-hoc, báo cáo tuỳ biến sâu, và bất cứ thứ gì cần nhúng vào quy trình dữ liệu, code thắng. Việc chọn loại biểu đồ nào cho thông điệp nào là chủ đề riêng — xem chọn biểu đồ đúng. Bài này lo phần công cụ: có những gì trong tay và khi nào rút cái nào ra.


Bản đồ công cụ: mỗi thư viện đứng ở đâu

Hệ sinh thái viz Python không phải một mớ công cụ thay thế lẫn nhau, mà là các lớp và các vai trò khác nhau. Đây là bản đồ định hướng cho cả series.

Matplotlib — nền tảng, kiểm soát tuyệt đối

Matplotlib ra đời 2003, là lớp nền mà gần như mọi thư viện khác dựng lên trên. Nó cho bạn kiểm soát tuyệt đối từng pixel: vị trí trục, cỡ chữ, khoảng cách, chú thích, nhiều trục con (subplot) phức tạp. Đổi lại, code dài dòng — vẽ một biểu đồ "đẹp để xuất bản" có thể tốn hàng chục dòng chỉnh sửa. Matplotlib xuất ra hình tĩnh (PNG, SVG, PDF), lý tưởng cho báo cáo in, tài liệu, slide. Khi bạn cần một hình chính xác đến từng chi tiết cho hồ sơ trình hội đồng, matplotlib là lựa chọn. Chi tiết ở bài matplotlib.

Seaborn — thống kê nhanh, và pandas/Polars .plot()

Seaborn là lớp mỏng dựng trên matplotlib, chuyên cho biểu đồ thống kê. Một dòng sns.boxplot(...) cho ra hộp phân phối đã tô màu đẹp, mặc định hợp lý. Nó hiểu DataFrame trực tiếp, tự nhóm theo cột hạng mục, tự vẽ khoảng tin cậy. Đây là công cụ khám phá dữ liệu nhanh (EDA): histogram, phân phối, tương quan, heatmap. Bên cạnh đó, chính pandas và Polars có sẵn .plot() (gọi ngầm matplotlib) để vẽ nháp một dòng ngay trên DataFrame. Xem seaborn & vẽ từ pandas.

Plotly — tương tác, chạy trên web

Plotly sinh ra biểu đồ tương tác: di chuột xem giá trị (hover tooltip), phóng to, kéo chọn vùng, bật/tắt chuỗi bằng cách bấm chú thích. Kết quả là HTML + JavaScript, nhúng thẳng vào web hay notebook. Khi người xem cần tự khám phá dữ liệu — "cho tôi rê chuột xem giao dịch ngày 15 là bao nhiêu" — plotly là câu trả lời. Xem plotly tương tác.

Altair / Vega-Lite — declarative "grammar of graphics"

Altair là giao diện Python cho Vega-Lite, theo triết lý declarative (khai báo): bạn mô tả dữ liệu ánh xạ vào cái gì (cột X là ngày, trục Y là số tiền, màu theo loại giao dịch) chứ không ra lệnh vẽ từng bước. Đây là hiện thân trong sáng nhất của "grammar of graphics" — rất mạnh khi biểu đồ có nhiều chiều dữ liệu và bạn muốn thử nhanh các cách mã hoá. Xem altair & grammar of graphics.

Bản đồ (geospatial) — folium, geopandas, plotly

Dữ liệu ngân hàng đầy yếu tố không gian: chi nhánh, ATM, mật độ khách theo tỉnh, giao dịch theo vùng. Vẽ lên bản đồ cần công cụ chuyên: folium (bản đồ tương tác nền Leaflet), geopandas (DataFrame có cột hình học), và plotly cũng vẽ được bản đồ choropleth. Xem geospatial trong Python viztrực quan hoá GIS.

Streamlit — biến script thành data app

Streamlit biến một script Python thành web app/dashboard chỉ với vài dòng: thêm ô lọc, ô chọn ngày, nút bấm, rồi biểu đồ tự cập nhật theo lựa chọn người dùng. Không cần biết HTML/JS. Đây là cầu nối giữa "phân tích một lần trong notebook" và "công cụ cho đồng nghiệp tự dùng". Xem dashboard với Streamlit.

Bản đồ tổng, xếp theo hai trục tĩnh↔tương tácnhanh↔kiểm soát:


"Grammar of graphics" — nền tư duy để chọn biểu đồ đúng

Trước khi bàn dùng thư viện nào, cần hiểu biểu đồ được cấu tạo thế nào. "Grammar of graphics" (ngữ pháp đồ hoạ, Leland Wilkinson 1999) là ý tưởng nền: mọi biểu đồ đều tháo rời được thành các thành phần độc lập, ghép lại theo quy tắc. Hiểu nó, bạn thôi học thuộc "biểu đồ cột vẽ sao, biểu đồ đường vẽ sao" và bắt đầu thiết kế biểu đồ từ dữ liệu.

Bốn thành phần cốt lõi:

  1. Dữ liệu (data): bảng có các cột — mỗi cột là một biến (ngày, số tiền, loại giao dịch, chi nhánh).
  2. Mã hoá thị giác (visual encoding / aesthetics): ánh xạ biến → thuộc tính thị giác. Biến này thành vị trí (trục X/Y), biến kia thành màu, biến khác thành kích thước điểm. Đây là quyết định quan trọng nhất.
  3. Hình học (geometry / marks): dữ liệu được vẽ bằng hình gì — điểm (point), đường (line), thanh (bar), vùng (area).
  4. Toạ độ (coordinate): hệ trục — Descartes (thông thường), hay cực (biểu đồ tròn), hay bản đồ địa lý.

Sức mạnh nằm ở chỗ: cùng một dữ liệu, đổi mã hoá hoặc hình học là ra biểu đồ khác. Cùng bảng "số tiền theo ngày theo loại giao dịch":

Mã hoáHình họcKết quả
X=ngày, Y=tiền, màu=loạiđườngbiểu đồ đường nhiều chuỗi (xu hướng)
X=loại, Y=tiềnthanhbiểu đồ cột so sánh loại
X=ngày, Y=loại, màu=tiềnô vuôngheatmap mật độ

Bảng "sự thật ngầm" này giải thích vì sao chọn biểu đồ đúng lại quan trọng: chọn mã hoá sai (ví dụ dùng màu cho biến số liên tục thay vì vị trí) khiến người xem đọc sai. Mắt người đọc vị trí chính xác nhất, rồi tới độ dài, kém nhất là diện tíchmàu sắc — nên biến quan trọng nhất nên gán cho vị trí/độ dài. Altair và plotly express theo sát triết lý này; matplotlib để bạn tự dựng từng thành phần.


Chọn công cụ theo nhu cầu

Không có "công cụ tốt nhất", chỉ có đúng công cụ cho tình huống. Khung quyết định thực dụng:

Nhu cầuCông cụ nên dùngVì sao
Khám phá nhanh (EDA)seaborn, df.plot()một dòng ra hình, mặc định hợp lý
Xuất bản tĩnh (báo cáo, slide in)matplotlibkiểm soát từng chi tiết, xuất PDF/SVG nét
Người xem tự khám phá / webplotly, altairhover, zoom, nhúng HTML
Nhiều chiều, muốn thử nhanh cách mã hoáaltairdeclarative, đổi encoding rất gọn
Bản đồ chi nhánh / vùngfolium, geopandas, plotlyvẽ lên nền địa lý
App cho đồng nghiệp tự lọcstreamlitbiến script thành dashboard

Trục quyết định lớn nhất là tĩnh vs tương tác:

  • Tĩnh khi kết quả đi vào tài liệu chết — PDF trình hội đồng, slide in, ảnh dán email. Người xem không tương tác được, nên hình phải nói trọn thông điệp ngay. Matplotlib/seaborn là đây.
  • Tương tác khi kết quả sống trên màn hình và người xem cần đào sâu — dashboard theo dõi, báo cáo web, notebook trình bày. Plotly/altair/streamlit là đây.

Một lỗi phổ biến: làm biểu đồ tương tác lộng lẫy rồi... xuất ra PNG dán vào Word — mất hết tương tác, lại nặng nề hơn matplotlib. Hãy chọn theo đích đến cuối cùng của hình.


Nguyên tắc viz tốt — công cụ chỉ là phương tiện

Thư viện xịn không cứu được biểu đồ dở. Vài nguyên tắc bất biến (sâu hơn ở thiết kế dashboard):

  • Rõ thông điệp: mỗi biểu đồ trả lời một câu hỏi. Tiêu đề nên là câu kết luận ("Nợ xấu tăng ở 3 chi nhánh phía Nam"), không phải nhãn khô khan ("Biểu đồ nợ xấu").
  • Ít nhiễu (data-ink ratio): bỏ đường lưới thừa, viền hộp, hiệu ứng 3D, bóng đổ. Mực in nên dành cho dữ liệu, không cho trang trí.
  • Màu có mục đích: màu để phân biệt nhóm hoặc nhấn cái quan trọng, không phải cho vui. Cảnh giác với người mù màu (tránh đỏ-xanh lá cạnh nhau).
  • Trung thực: trục Y bắt đầu từ 0 cho biểu đồ cột (cắt trục thổi phồng khác biệt); không bóp méo tỉ lệ; ghi rõ đơn vị và nguồn. Với báo cáo ngân hàng, trung thực số liệu là yêu cầu tuân thủ, không phải tuỳ chọn thẩm mỹ.

Kết nối dữ liệu: vẽ thẳng từ pandas / Polars

Mọi công cụ trên đều "hiểu" DataFrame. Quy trình chuẩn: query dữ liệu → xử lý bằng pandas hoặc Polars (so sánh Polars) → truyền thẳng DataFrame vào thư viện vẽ. Không có bước xuất Excel trung gian. Ví dụ nguồn dữ liệu — một câu tổng hợp số dư theo loại tiền, đúng schema sandbox:

-- ▶ Chạy được
SELECT currency, COUNT(*) AS so_tk, SUM(balance) AS tong_du
FROM accounts
GROUP BY currency
ORDER BY tong_du DESC;

Kết quả câu này nạp vào một DataFrame là vẽ được ngay. Với Polars, dùng eager scan rồi .to_pandas() nếu thư viện vẽ cần pandas; đa số plotly/altair nhận cả hai.


Cùng một biểu đồ: matplotlib vs plotly

Để thấy khác biệt tĩnh vs tương tác trên cùng dữ liệu, đây là ví dụ minh hoạ (code Python) vẽ số dư trung bình theo loại tiền. Giả sử đã có DataFrame df với hai cột currencytong_du.

Matplotlib — tĩnh, kiểm soát từng chi tiết:

import matplotlib.pyplot as plt

fig, ax = plt.subplots(figsize=(7, 4))
ax.bar(df["currency"], df["tong_du"], color="#2563eb")
ax.set_title("Tổng số dư theo loại tiền")
ax.set_ylabel("Số dư (VND quy đổi)")
ax.spines[["top", "right"]].set_visible(False)  # bỏ nhiễu
fig.tight_layout()
fig.savefig("so_du.png", dpi=150)   # xuất ảnh tĩnh cho báo cáo

Kết quả là file PNG — dán vào slide, in ra là xong. Muốn đổi gì phải chỉnh code và chạy lại.

Plotly — tương tác, cho web/notebook:

import plotly.express as px

fig = px.bar(df, x="currency", y="tong_du",
             title="Tổng số dư theo loại tiền",
             labels={"tong_du": "Số dư (VND quy đổi)"})
fig.show()                    # hover xem giá trị, zoom, kéo chọn
fig.write_html("so_du.html")  # nhúng vào trang web

Cùng dữ liệu, cùng loại biểu đồ cột, nhưng plotly cho ra HTML tương tác: rê chuột lên từng cột hiện đúng con số, phóng to vùng quan tâm. Chú ý điểm chung: cả hai đều theo grammar of graphics — X là currency (vị trí), Y là tong_du (độ dài), hình học là thanh. Chỉ khác đích đến: một cái cho giấy, một cái cho màn hình.


Use case thực tế

Bối cảnh (số liệu ước lượng, minh hoạ): Phòng Phân tích Kinh doanh NCB phải nộp báo cáo hiệu quả huy động vốn theo chi nhánh hằng tháng cho ban lãnh đạo, gồm khoảng 20 biểu đồ cho ~40 chi nhánh. Quy trình cũ hoàn toàn bằng Excel: một chuyên viên mất khoảng 2 ngày công mỗi tháng để pull dữ liệu, vẽ tay, chỉnh màu, dán vào slide. Mỗi lần số liệu điều chỉnh cuối tháng là làm lại một phần, và đã có lần biểu đồ dán nhầm kỳ.

Chuyển sang vẽ bằng Python:

  1. Nguồn tái lập: một script query kho dữ liệu (số dư huy động theo chi nhánh, theo kỳ) trả về DataFrame Polars, thay cho copy tay.
  2. Chọn công cụ theo tình huống:
    • Bản báo cáo PDF trình hội đồng dùng matplotlib — cần hình tĩnh, nét, bố cục cố định, in ra chuẩn.
    • Trong lúc phân tích khám phá (chi nhánh nào bất thường?), chuyên viên dùng seaborn vẽ nhanh phân phối và heatmap tương quan.
    • Bản dashboard cho các giám đốc chi nhánh tự xem, tự lọc theo vùng, dựng bằng streamlit + biểu đồ plotly để hover xem số cụ thể.
  3. Tự động hoá: một vòng lặp sinh 40 biểu đồ chi nhánh trong vài giây; lịch chạy đầu tháng tự cập nhật khi dữ liệu chốt.

Kết quả ước lượng: thời gian dựng báo cáo giảm từ ~2 ngày công xuống còn ~2 giờ (chủ yếu là đọc và diễn giải, không còn vẽ tay); loại bỏ lỗi dán nhầm kỳ; và bất kỳ ai cũng chạy lại được đúng biểu đồ cũ từ Git khi cần đối chiếu. Việc chọn đúng loại biểu đồ cho từng chỉ số (xem chọn biểu đồ) và gắn với bộ chỉ số KPI chuẩn của phòng giúp báo cáo nhất quán qua các tháng.


Ghi nhớ

  • Vẽ bằng code thắng Excel kéo-thả ở ba điểm sống còn với ngân hàng: tái lập, tự động hoá, tích hợp thẳng vào pipeline dữ liệu. BI kéo-thả vẫn hợp cho dashboard tự phục vụ người không code.
  • Bản đồ công cụ: matplotlib (nền, kiểm soát tuyệt đối, tĩnh) → seaborn (thống kê nhanh trên matplotlib) → plotly (tương tác web) → altair (declarative, grammar of graphics) → folium/geopandas (bản đồ) → streamlit (data app).
  • Grammar of graphics là nền tư duy: dữ liệu → mã hoá thị giác (vị trí/màu/kích thước) → hình học → toạ độ. Mắt đọc vị tríđộ dài chính xác hơn màudiện tích — gán biến quan trọng nhất cho vị trí.
  • Chọn theo nhu cầu: khám phá nhanh → seaborn; xuất bản tĩnh → matplotlib; tương tác/web → plotly/altair; app → streamlit. Trục quyết định lớn nhất là tĩnh vs tương tác, chọn theo đích đến cuối cùng của hình.
  • Nguyên tắc viz tốt độc lập với công cụ: rõ thông điệp, ít nhiễu, màu có mục đích, trung thực số liệu (trục Y từ 0, không bóp méo tỉ lệ).
  • Kết nối dữ liệu: vẽ thẳng từ pandas/Polars, bỏ bước xuất Excel trung gian dễ lỗi.
  • Cùng một biểu đồ, matplotlib cho ảnh tĩnh (báo cáo in), plotly cho HTML tương tác (web/notebook) — khác nhau ở đích đến, chung nhau ở grammar of graphics.

Nguồn tham khảo

Bài viết liên quan

Vì sao Python là ngôn ngữ số một của data engineer: vai trò trong pipeline (ingest/transform/orchestrate), hệ sinh thái thư viện (pandas/polars/pyarrow/sqlalchemy), quản lý môi trường (venv/uv/poetry), và khi nào dùng Python vs SQL/Spark.

13 thg 7, 2026 6

Học cách tổ chức code Python: định nghĩa hàm với tham số vị trí/từ khoá/mặc định, *args/**kwargs, lambda và hàm bậc cao, closure, decorator, generator với yield. Đóng gói code thành module và package, cô lập thư viện bằng môi trường ảo venv, quản lý phụ thuộc với pip và requirements.txt để dự án tái lập được trên mọi máy.

13 thg 7, 2026 5

Biến script thành pipeline đáng tin cậy: cấu trúc project & packaging (uv/poetry), type hints & pydantic, kiểm thử với pytest, logging & cấu hình, đóng gói Docker, và tích hợp CI cho code dữ liệu.

13 thg 7, 2026 5

Hướng dẫn OOP trong Python từ class/instance, kế thừa và super(), đa hình & duck typing, encapsulation tới dunder methods, @property, classmethod/staticmethod, dataclass và type hints (mypy). Kèm nguyên tắc clean code: đặt tên rõ nghĩa, hàm nhỏ, DRY, SOLID cùng chuẩn PEP8 với công cụ ruff/black.

13 thg 7, 2026 5

Cảm nhận của bạn

Bình luận

Bạn cần để viết bình luận.

Chưa có bình luận. Hãy là người đầu tiên chia sẻ!