🎯 Mục tiêu bài học
Sau bài học này, bạn sẽ:
✅ Tạo biểu đồ cơ bản với Matplotlib (line, bar, scatter, histogram)
✅ Vẽ biểu đồ thống kê đẹp với Seaborn (distribution, categorical, relational)
✅ Tạo biểu đồ tương tác với Plotly (zoom, hover, animation)
✅ Biết chọn loại biểu đồ phù hợp cho từng loại dữ liệu
✅ Customize và export biểu đồ chuyên nghiệp
Thời gian: 4 giờ | Độ khó: Beginner → Intermediate | Yêu cầu: Pandas (Bài 6-7)
📖 Bảng Thuật Ngữ Quan Trọng
| Thuật ngữ | Tiếng Việt | Mô tả |
|---|---|---|
| Figure | Khung vẽ | Container chứa toàn bộ biểu đồ |
| Axes | Trục/subplot | Một biểu đồ riêng lẻ trong figure |
| Distribution plot | Biểu đồ phân phối | Histogram, KDE, Box — xem phân bố dữ liệu |
| Categorical plot | Biểu đồ phân loại | Bar, Count — so sánh giữa các nhóm |
| Relational plot | Biểu đồ quan hệ | Scatter, Line — tương quan giữa biến |
| Heatmap | Bản đồ nhiệt | Ma trận màu — thể hiện giá trị bằng màu sắc |
| Interactive plot | Biểu đồ tương tác | Zoom, hover, click — dùng Plotly |
| Faceting | Chia nhỏ | Chia 1 biểu đồ thành nhiều panel theo category |
| Color palette | Bảng màu | Bộ màu được chọn sẵn cho biểu đồ |
| Annotation | Chú thích | Text/mũi tên đánh dấu trên biểu đồ |
Checkpoint
Phân biệt Figure vs Axes trong Matplotlib? Khi nào cần tạo nhiều Axes?
📊 Matplotlib — Nền Tảng
Trực quan hóa dữ liệu (Data Visualization) là gì? Là biến con số khô khan thành hình ảnh trực quan — giúp bạn nhìn thấy pattern, trend, và outlier mà không thể thấy bằng bảng số.
Tại sao quan trọng? Một biểu đồ tốt giá trị hơn 1000 dòng số liệu. Trong Data Science, visualization giúp bạn:
- Khám phá dữ liệu (EDA) — tìm pattern, outlier
- Truyền tải insight cho stakeholders
- Kiểm tra giả thuyết trực quan trước khi test thống kê
Setup
1import matplotlib.pyplot as plt2import numpy as np3import pandas as pd45# Style đẹp hơn mặc định6plt.style.use('seaborn-v0_8-whitegrid')Figure và Axes
1# Cách 1: Quick plot2plt.figure(figsize=(10, 6))3plt.plot([1, 2, 3, 4], [10, 20, 25, 30])4plt.title("Quick Plot")5plt.show()67# Cách 2: Object-oriented (KHUYẾN KHÍCH)8fig, ax = plt.subplots(figsize=(10, 6))9ax.plot([1, 2, 3, 4], [10, 20, 25, 30])10ax.set_title("OOP Style")11ax.set_xlabel("X")12ax.set_ylabel("Y")13plt.show()1415# Cách 3: Multiple subplots16fig, axes = plt.subplots(2, 2, figsize=(12, 10))17axes[0, 0].plot([1,2,3], [1,4,9])18axes[0, 1].bar(['A','B','C'], [3,7,5])19axes[1, 0].scatter(np.random.rand(50), np.random.rand(50))20axes[1, 1].hist(np.random.randn(1000), bins=30)21plt.tight_layout()22plt.show()Các loại biểu đồ cơ bản
1fig, axes = plt.subplots(2, 3, figsize=(15, 10))23# Line Plot4x = np.linspace(0, 10, 100)5axes[0,0].plot(x, np.sin(x), label='sin(x)')6axes[0,0].plot(x, np.cos(x), label='cos(x)', linestyle='--')7axes[0,0].legend()8axes[0,0].set_title("Line Plot")910# Bar Chart11axes[0,1].bar(['Q1','Q2','Q3','Q4'], [100, 150, 120, 180], color='steelblue')12axes[0,1].set_title("Bar Chart")1314# Scatter Plot15axes[0,2].scatter(np.random.rand(50), np.random.rand(50), 16 c=np.random.rand(50), s=np.random.rand(50)*500, alpha=0.6)17axes[0,2].set_title("Scatter Plot")1819# Histogram20axes[1,0].hist(np.random.randn(1000), bins=30, edgecolor='black')21axes[1,0].set_title("Histogram")2223# Pie Chart24axes[1,1].pie([30, 25, 20, 15, 10], labels=['A','B','C','D','E'], autopct='%1.1f%%')25axes[1,1].set_title("Pie Chart")2627# Box Plot28data = [np.random.normal(0, std, 100) for std in range(1, 4)]29axes[1,2].boxplot(data, labels=['σ=1', 'σ=2', 'σ=3'])30axes[1,2].set_title("Box Plot")3132plt.suptitle("Matplotlib Basics", fontsize=16, fontweight='bold')33plt.tight_layout()34plt.show()Luôn dùng OOP style (fig, ax = plt.subplots()) thay vì plt.plot(). Dễ customize và ít bug hơn khi vẽ nhiều biểu đồ.
Checkpoint
Tạo figure 2×2: Line, Bar, Scatter, Histogram. Thêm title, xlabel, ylabel cho mỗi subplot.
🎨 Seaborn — Statistical Visualization
Setup
1import seaborn as sns23sns.set_theme(style="whitegrid")45# Load sample dataset6tips = sns.load_dataset("tips")7print(tips.head())Distribution Plots — Biểu đồ xem phân bố dữ liệu
Dùng khi nào? Khi cần trả lời: "Dữ liệu phân bố ra sao? Có lệch không? Có outlier không?"
| Biểu đồ | Cho biết gì? | Dùng khi |
|---|---|---|
| Histogram | Phân bố tần suất | Xem data tập trung ở đâu |
| KDE | Phân bố mượt (đường cong) | So sánh phân bố 2+ nhóm |
| Box Plot | Median, Q1/Q3, outlier | Phát hiện outlier, so sánh nhóm |
| Violin | Box + KDE kết hợp | Thấy cả phân bố lẫn thống kê |
1fig, axes = plt.subplots(2, 2, figsize=(12, 10))23# Histogram + KDE4sns.histplot(data=tips, x="total_bill", kde=True, ax=axes[0,0])5axes[0,0].set_title("Histogram + KDE")67# KDE Plot grouped8sns.kdeplot(data=tips, x="total_bill", hue="time", fill=True, ax=axes[0,1])9axes[0,1].set_title("KDE by Time")1011# Box Plot12sns.boxplot(data=tips, x="day", y="total_bill", hue="time", ax=axes[1,0])13axes[1,0].set_title("Box Plot")1415# Violin Plot16sns.violinplot(data=tips, x="day", y="total_bill", hue="sex", 17 split=True, ax=axes[1,1])18axes[1,1].set_title("Violin Plot")1920plt.tight_layout()21plt.show()Categorical Plots — So sánh nhóm
1fig, axes = plt.subplots(1, 3, figsize=(15, 5))23# Bar Plot (mean + CI)4sns.barplot(data=tips, x="day", y="total_bill", hue="sex", 5 errorbar="sd", ax=axes[0])6axes[0].set_title("Bar Plot (Mean ± SD)")78# Count Plot9sns.countplot(data=tips, x="day", hue="time", palette="Set2", ax=axes[1])10axes[1].set_title("Count Plot")1112# Swarm Plot13sns.swarmplot(data=tips, x="day", y="total_bill", hue="sex", ax=axes[2])14axes[2].set_title("Swarm Plot")1516plt.tight_layout()17plt.show()Relational Plots — Tương quan
1# Scatter với nhiều dimensions2plt.figure(figsize=(10, 6))3sns.scatterplot(data=tips, x="total_bill", y="tip",4 hue="time", size="size", style="sex",5 palette="viridis", sizes=(20, 200))6plt.title("Total Bill vs Tip (Multi-dimensional)")7plt.show()89# Regression plot10sns.lmplot(data=tips, x="total_bill", y="tip", 11 hue="smoker", col="time", height=5)12plt.show()Heatmap — Ma trận tương quan
1plt.figure(figsize=(8, 6))2numeric_cols = tips.select_dtypes(include=[np.number])3corr = numeric_cols.corr()45sns.heatmap(corr, annot=True, cmap="coolwarm", center=0,6 fmt=".2f", linewidths=0.5, square=True)7plt.title("Correlation Heatmap")8plt.show()Pair Plot — Toàn cảnh
1# Tất cả cặp biến2sns.pairplot(tips, hue="time", diag_kind="kde", corner=True)3plt.show()Chọn biểu đồ theo mục đích:
| Mục đích | Biểu đồ |
|---|---|
| Phân phối 1 biến | histplot, kdeplot, boxplot |
| So sánh nhóm | barplot, countplot, violinplot |
| Tương quan 2 biến | scatterplot, regplot |
| Correlation matrix | heatmap |
| Khám phá toàn bộ | pairplot |
Checkpoint
Vẽ 4 biểu đồ Seaborn trên dataset tips: histogram, boxplot, scatter, heatmap. Tất cả trong 1 figure 2×2.
✨ Plotly — Interactive Visualization
Plotly vs Matplotlib/Seaborn: Matplotlib/Seaborn tạo ảnh tĩnh (PNG). Plotly tạo biểu đồ tương tác — zoom, hover xem giá trị, click chọn nhóm. Rất phù hợp cho dashboard và trình bày.
Plotly Express — Quick Interactive Plots
1import plotly.express as px23# Sample data4df = px.data.gapminder()5tips = px.data.tips()Scatter Plot (Interactive)
1fig = px.scatter(df.query("year == 2007"),2 x="gdpPercap", y="lifeExp",3 color="continent", size="pop",4 hover_name="country",5 log_x=True,6 title="GDP vs Life Expectancy (2007)")7fig.show()Bar Chart
1# Grouped bar2fig = px.bar(tips, x="day", y="total_bill", color="sex",3 barmode="group",4 title="Total Bill by Day and Sex")5fig.show()Histogram với Marginal
1fig = px.histogram(tips, x="total_bill", nbins=30,2 color="time",3 marginal="box", # hoặc "rug", "violin"4 title="Distribution of Total Bill")5fig.show()Box & Violin
1fig = px.box(tips, x="day", y="total_bill", color="smoker",2 notched=True,3 title="Total Bill Distribution")4fig.show()Choropleth Map
1fig = px.choropleth(df.query("year == 2007"),2 locations="iso_alpha",3 color="lifeExp",4 hover_name="country",5 color_continuous_scale="Viridis",6 title="Life Expectancy (2007)")7fig.show()Animation!
1fig = px.scatter(df, x="gdpPercap", y="lifeExp",2 animation_frame="year",3 animation_group="country",4 size="pop", color="continent",5 hover_name="country",6 log_x=True, size_max=55,7 range_x=[100, 100000],8 range_y=[25, 90],9 title="Gapminder Animation")10fig.show()Khi nào dùng Matplotlib/Seaborn vs Plotly?
| Tình huống | Chọn |
|---|---|
| Report/Paper (static) | Matplotlib/Seaborn |
| Notebook khám phá | Plotly |
| Dashboard/Web app | Plotly + Dash |
| Presentation | Plotly (wow factor) |
| Publication quality | Matplotlib (fine control) |
Checkpoint
Tạo 1 scatter plot interactive với Plotly: color theo category, size theo value, hover hiện tên. Thử zoom và hover!
🛠️ Graph Objects — Advanced Plotly
Custom Figure
1import plotly.graph_objects as go2from plotly.subplots import make_subplots34fig = go.Figure()56fig.add_trace(go.Scatter(7 x=[1, 2, 3, 4], y=[10, 11, 12, 13],8 mode='lines+markers', name='Line 1'9))10fig.add_trace(go.Scatter(11 x=[1, 2, 3, 4], y=[12, 9, 15, 12],12 mode='lines+markers', name='Line 2'13))1415fig.update_layout(16 title="Custom Plot",17 xaxis_title="X", yaxis_title="Y"18)19fig.show()Dual Y-Axis
1fig = go.Figure()23fig.add_trace(go.Scatter(4 x=[1,2,3,4], y=[100,200,300,400],5 name="Revenue ($)", yaxis="y1"6))7fig.add_trace(go.Bar(8 x=[1,2,3,4], y=[10,20,15,25],9 name="Orders", yaxis="y2", opacity=0.510))1112fig.update_layout(13 yaxis=dict(title="Revenue ($)", side="left"),14 yaxis2=dict(title="Orders", side="right", overlaying="y"),15 title="Dual Y-Axis"16)17fig.show()Subplots
1fig = make_subplots(rows=2, cols=2,2 subplot_titles=("Scatter", "Bar", "Line", "Histogram"))34fig.add_trace(go.Scatter(x=[1,2,3], y=[4,5,6], mode='markers'), row=1, col=1)5fig.add_trace(go.Bar(x=['A','B','C'], y=[3,7,5]), row=1, col=2)6fig.add_trace(go.Scatter(x=[1,2,3], y=[1,2,3], mode='lines'), row=2, col=1)7fig.add_trace(go.Histogram(x=np.random.randn(500)), row=2, col=2)89fig.update_layout(height=600, title_text="Subplots")10fig.show()Export
1# Interactive HTML2fig.write_html("chart.html")34# Static image5fig.write_image("chart.png", scale=2) # Cần kaleido6fig.write_image("chart.pdf")🎯 Styling và Best Practices
Chọn đúng biểu đồ
| Câu hỏi | Biểu đồ phù hợp |
|---|---|
| Dữ liệu thay đổi theo thời gian? | Line chart |
| So sánh giữa các nhóm? | Bar chart |
| Mối quan hệ 2 biến? | Scatter plot |
| Phân bố dữ liệu? | Histogram / Box plot |
| Tỷ lệ phần? | Pie chart (dùng ít, thích bar hơn) |
| Tương quan nhiều biến? | Heatmap |
Seaborn Themes
1# Themes: darkgrid, whitegrid, dark, white, ticks2sns.set_theme(style="whitegrid", palette="Set2",3 font_scale=1.2)Color Palettes
1# Categorical: Set1, Set2, Dark2, Paired, husl2# Sequential: Blues, Reds, Viridis, coolwarm3# Custom4custom = ["#FF6B6B", "#4ECDC4", "#45B7D1", "#96CEB4"]5sns.set_palette(custom)Plotly Templates
1# plotly, plotly_white, plotly_dark, ggplot2, seaborn, simple_white2fig = px.scatter(tips, x="total_bill", y="tip", 3 template="plotly_white")Best Practices:
- Luôn có title và label trục rõ ràng
- Chọn đúng loại biểu đồ cho loại dữ liệu
- Không quá 5-7 màu trong 1 biểu đồ
- Bắt đầu Y-axis từ 0 cho bar chart (tránh gây hiểu lầm)
- Dùng colorblind-friendly palette khi chia sẻ rộng
Checkpoint
Bạn đã biết khi nào dùng Histogram vs Box vs Violin chưa? Khi nào dùng Bar vs Line?
📝 Tổng Kết
So sánh 3 thư viện
| Tiêu chí | Matplotlib | Seaborn | Plotly |
|---|---|---|---|
| Ease of use | Medium | Easy | Easy |
| Static | ✅ | ✅ | ✅ |
| Interactive | ❌ | ❌ | ✅ |
| Themes | Manual | Built-in | Built-in |
| Statistical | Manual | ✅ Auto CI | Limited |
| 3D | Basic | ❌ | ✅ Excellent |
| Map | With Basemap | ❌ | ✅ Built-in |
| Animation | Complex | ❌ | ✅ Easy |
| Dashboard | ❌ | ❌ | ✅ Dash |
Quick Reference
1# Matplotlib2fig, ax = plt.subplots()3ax.plot(x, y)4plt.show()56# Seaborn7sns.histplot(data=df, x="col", hue="cat", kde=True)8sns.scatterplot(data=df, x="x", y="y", hue="cat")9sns.heatmap(corr, annot=True)10sns.pairplot(df)1112# Plotly13fig = px.scatter(df, x="x", y="y", color="cat", size="val")14fig = px.bar(df, x="cat", y="val", color="group")15fig.show()Bài tiếp theo: Thực hành Visualization với dataset thực tế — tạo báo cáo trực quan! 📊
Câu hỏi tự kiểm tra
- Khi nào nên dùng biểu đồ Line chart thay vì Bar chart? Cho ví dụ cụ thể.
- So sánh Matplotlib, Seaborn và Plotly — mỗi thư viện phù hợp trong trường hợp nào?
- Heatmap dùng để trực quan hóa điều gì? Tại sao nó hữu ích trong phân tích tương quan?
- Kể ra 3 best practices quan trọng khi tạo biểu đồ trực quan hóa dữ liệu.
🎉 Tuyệt vời! Bạn đã hoàn thành bài học Visualization!
Tiếp theo: Thực hành Visualization với dataset thực tế để tạo báo cáo trực quan chuyên nghiệp!
