Skip to content

📝 Visualization: Khi 1 hình ảnh = 1 triệu dòng data

Mở đầu — "Chart đẹp quá, nhưng sai hoàn toàn."

Hạnh, 29 tuổi, Senior Data Analyst tại một tập đoàn bán lẻ đa kênh ở Hà Nội — loại doanh nghiệp có 120 cửa hàng offline, sàn e-commerce riêng, và app loyalty với 3.5 triệu thành viên. Hạnh phụ trách phân tích doanh thu và hành vi khách hàng cho team Strategy, báo cáo trực tiếp cho CFO và CMO.

Hạnh không thiếu kinh nghiệm. Cô viết Python sạch, Pandas thành thạo, EDA bài bản — từ univariate đến correlation matrix. Sếp tin tưởng, đồng nghiệp nể phục. Hạnh là người duy nhất trong team được mời trình bày trực tiếp trong buổi Quarterly Business Review (QBR) — nơi CEO, CFO, CMO và các VP ngồi cùng phòng.

Nhưng QBR quý 4/2025 suýt trở thành thảm họa.

Ban Chiến lược yêu cầu Hạnh phân tích hiệu quả kênh bán hàng — online vs offline, theo vùng miền, theo danh mục sản phẩm. Dataset: 2.8 triệu giao dịch trong 3 tháng. Hạnh EDA kỹ càng, tìm đủ insight, rồi ngồi 2 ngày làm slide trình bày.

Slide chính của Hạnh là một 3D pie chart rực rỡ 7 màu cầu vồng, thể hiện tỷ trọng doanh thu theo danh mục sản phẩm. Phía dưới là biểu đồ dual-axis — cột cho doanh thu, đường cho số lượng đơn — với hai trục Y có scale khác nhau hoàn toàn. Và cuối cùng, một bảng so sánh vùng miền dùng... biểu đồ tròn chồng lên nhau.

Hạnh nghĩ slide rất "pro" — nhiều màu, nhiều chart type, trông phức tạp và ấn tượng.

CFO — ông Đức, người nổi tiếng thẳng tính — nhìn slide 10 giây rồi hỏi: "Hạnh ơi, biểu đồ tròn này — miếng 'Thực phẩm' và 'Đồ gia dụng' trông gần bằng nhau. Cái nào lớn hơn?"

Hạnh nhìn lại: miếng Thực phẩm là 23%, Đồ gia dụng là 21%. Chênh 2 percentage points, nhưng trong 3D pie chart, góc nhìn nghiêng khiến hai miếng trông gần như bằng nhau — thậm chí miếng phía trước trông to hơn miếng phía sau dù giá trị thấp hơn.

CMO hỏi tiếp: "Còn biểu đồ dual-axis — doanh thu tăng 15% nhưng số đơn tăng 40%? Sao đường và cột trông đang đi cùng hướng vậy? Vậy giá trị trung bình đơn hàng đang giảm mạnh chứ? Chart không thể hiện được điều đó."

Hạnh chết lặng. Insight đúng, nhưng chart sai. Cô đã để visualization "phản bội" chính analysis của mình.

CEO nói vỏn vẹn một câu: "Hạnh à, anh không hiểu được câu chuyện từ mấy biểu đồ này. Lần sau cần rõ hơn nhé."

Buổi tối hôm đó, Hạnh gọi cho Dũng — anh bạn làm Data Visualization Specialist tại một công ty tư vấn quốc tế: "Dũng ơi, mình có insight đúng mà chart sai, sếp không hiểu gì cả. Mình thua vì visualization."

Dũng trả lời: "Chart giống như bản đồ. Data là địa hình thật, chart là bản đồ mày vẽ để người khác đi theo. Bản đồ sai thì dù địa hình đúng, người đọc vẫn đi lạc. Mày vẽ bản đồ 3D xoay nghiêng, ai mà đọc được?"

Phần 1: Chart = Bản đồ — Sai bản đồ thì đi lạc

Dũng video call tối hôm đó, bắt đầu bằng câu hỏi: "Mày biết tại sao bản đồ Google Maps luôn nhìn từ trên xuống không?"

Hạnh: "Vì... dễ đọc?"

Dũng: "Đúng. Orthographic projection — nhìn thẳng từ trên, không méo, không lệch. Chart cũng vậy. Biểu đồ tốt phải để người đọc so sánh chính xác giá trị. 3D pie chart vi phạm nguyên tắc này — góc nghiêng khiến perception bị méo. The Economist cấm dùng 3D chart. Financial Times cũng cấm. Vì sao? Vì nó đẹp nhưng nói dối."

Dũng share màn hình, mở dataset mẫu tương tự của Hạnh:

python
import matplotlib.pyplot as plt
import numpy as np

categories = ['Thực phẩm', 'Đồ gia dụng', 'Thời trang', 'Điện tử', 'Mỹ phẩm', 'Khác']
values = [23, 21, 18, 17, 12, 9]

# ❌ SAI: 3D Pie Chart — perception bị méo
fig, axes = plt.subplots(1, 2, figsize=(16, 6))

axes[0].pie(values, labels=categories, autopct='%1.0f%%',
            shadow=True, startangle=90,
            colors=['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7', '#DDA0DD'])
axes[0].set_title('❌ Pie Chart — Khó so sánh chính xác', fontsize=12, fontweight='bold')

# ✅ ĐÚNG: Horizontal Bar Chart — so sánh trực quan
y_pos = np.arange(len(categories))
sorted_idx = np.argsort(values)[::-1]
sorted_cats = [categories[i] for i in sorted_idx]
sorted_vals = [values[i] for i in sorted_idx]

bars = axes[1].barh(y_pos, sorted_vals, color='#2C3E50', alpha=0.85, edgecolor='white')
axes[1].set_yticks(y_pos)
axes[1].set_yticklabels(sorted_cats)
axes[1].set_xlabel('Tỷ trọng doanh thu (%)')
axes[1].set_title('✅ Bar Chart — So sánh rõ ràng', fontsize=12, fontweight='bold')

# Thêm data labels
for bar, val in zip(bars, sorted_vals):
    axes[1].text(bar.get_width() + 0.3, bar.get_y() + bar.get_height()/2,
                 f'{val}%', va='center', fontweight='bold')

plt.tight_layout()
plt.show()

"Thấy chưa?" Dũng nói. "Cùng một data, bar chart cho mày so sánh ngay lập tức: Thực phẩm 23% > Đồ gia dụng 21%. Pie chart mày phải đoán, nhất là khi hai giá trị gần nhau. Não người giỏi so sánh chiều dài (bar), nhưng kém so sánh diện tích và góc (pie)."

Chart = Bản đồ dẫn đường cho insight

Hãy nghĩ mỗi chart là một bản đồ:

  • Bar chart → bản đồ đường thẳng — so sánh giá trị rõ ràng, ai cũng đọc được
  • Pie chart → bản đồ xoay 3D — đẹp mắt nhưng dễ nhầm hướng
  • Line chart → bản đồ timeline — thấy xu hướng theo thời gian
  • Scatter plot → bản đồ địa hình — thấy mối quan hệ, cụm, outlier

Sai bản đồ → đi lạc. Sai chart → hiểu sai data → quyết định sai.

Hạnh bắt đầu ngấm. Cô nhớ lại slide QBR: CFO hỏi "miếng nào lớn hơn?" chính vì pie chart làm méo perception. Nếu cô dùng bar chart đơn giản, chênh lệch 2 percentage points sẽ hiện rõ ràng.

Phần 2: "Chart Fails" — Những lỗi kinh điển mà DA nào cũng từng mắc

Dũng kể: "Mày không phải người đầu tiên. Có 3 chart fails nổi tiếng mà gần như mọi DA đều mắc ít nhất 1 lần."

Fail #1 — The 3D Pie Chart Trap:

"Fox News từng dùng 3D pie chart cho kết quả poll — 3 lựa chọn cộng lại = 193%. Lý do? 3D effect + overlapping labels. The Economist sau đó viết hẳn bài phê phán việc dùng pie chart, đặc biệt 3D pie. Nguyên tắc IBCS (International Business Communication Standards) nói thẳng: 'Avoid pie charts. Use bar charts instead.'"

Fail #2 — The Dual-Axis Deception:

"Dual-axis chart — hai trục Y với scale khác nhau — là cách dễ nhất để vô tình tạo narrative sai. Mày có thể khiến bất kỳ hai đường nào trông như có correlation bằng cách chỉnh scale."

python
import matplotlib.pyplot as plt
import numpy as np

months = ['T1', 'T2', 'T3', 'T4', 'T5', 'T6', 'T7', 'T8', 'T9', 'T10', 'T11', 'T12']
revenue = [4.2, 4.5, 4.8, 5.1, 5.3, 5.0, 4.8, 5.2, 5.5, 5.8, 6.2, 6.5]  # tỷ VNĐ
orders = [12000, 13500, 15800, 18200, 20100, 19500, 18800, 21000, 24500, 28000, 33000, 38000]

fig, axes = plt.subplots(1, 2, figsize=(18, 6))

# ❌ SAI: Dual-axis — misleading correlation
ax1 = axes[0]
ax2 = ax1.twinx()
ax1.bar(months, revenue, alpha=0.7, color='#3498db', label='Doanh thu (tỷ)')
ax2.plot(months, orders, color='#e74c3c', linewidth=2, marker='o', label='Số đơn')
ax1.set_ylabel('Doanh thu (tỷ VNĐ)', color='#3498db')
ax2.set_ylabel('Số đơn hàng', color='#e74c3c')
axes[0].set_title('❌ Dual-Axis — Trông "đồng hành" nhưng AOV đang giảm!', fontweight='bold')
ax1.legend(loc='upper left')
ax2.legend(loc='upper right')

# ✅ ĐÚNG: Tách riêng + thêm metric dẫn xuất
aov = [r * 1e9 / o for r, o in zip(revenue, orders)]  # Average Order Value
axes[1].plot(months, aov, color='#2C3E50', linewidth=2.5, marker='s')
axes[1].fill_between(months, aov, alpha=0.1, color='#2C3E50')
axes[1].set_ylabel('Giá trị đơn trung bình (VNĐ)')
axes[1].set_title('✅ AOV giảm 51% trong năm — insight thật!', fontweight='bold')
axes[1].axhline(y=np.mean(aov), color='red', linestyle='--', alpha=0.5, label=f'Mean AOV: {np.mean(aov):,.0f}đ')
axes[1].legend()

plt.tight_layout()
plt.show()

"Thấy chưa?" Dũng chỉ vào chart. "Dual-axis khiến mày nghĩ doanh thu và số đơn cùng tăng — tốt quá! Nhưng thực tế AOV (giá trị đơn trung bình) giảm từ 350K xuống 171K — giảm 51%. Khách mua nhiều hơn nhưng mua rẻ hơn. Đó là insight thật, nhưng dual-axis chart che giấu nó."

Fail #3 — The Rainbow Color Explosion:

"Nhiều DA nghĩ nhiều màu = nhiều thông tin. Sai. Nhiều màu = nhiều cognitive load. The Economist dùng tối đa 3-4 màu cho mỗi chart. IBCS khuyến nghị dùng 1 màu chính + 1 màu highlight."

3 "Chart Fails" phổ biến nhất

Chart FailTại sao saiFix
3D Pie ChartGóc nghiêng méo perception, khó so sánhDùng horizontal bar chart
Dual-AxisHai scale khác nhau tạo false correlationTách riêng hoặc tính metric dẫn xuất (AOV, growth rate)
Rainbow ColorsQuá nhiều màu → cognitive overload, không focusMax 3-4 màu, 1 highlight color cho insight chính

Edward Tufte — cha đẻ data visualization — nói: "Above all else, show the data." Mọi thứ không giúp người đọc hiểu data (3D effect, gradient, shadow, excessive color) = chartjunk — rác thải trên biểu đồ.

Phần 3: 15 loại chart và khi nào dùng cái nào

Hạnh hỏi: "Vậy có bao nhiêu loại chart mình cần biết? Và làm sao biết khi nào dùng cái nào?"

Dũng: "15 loại là đủ cho 95% tình huống. Nhưng quan trọng hơn số lượng là biết chọn đúng. Mỗi chart trả lời một loại câu hỏi khác nhau."

python
import matplotlib.pyplot as plt

# Chart Selection Guide — bảng tra cứu cho DA
chart_guide = {
    'So sánh giá trị': {
        'charts': ['Bar Chart', 'Grouped Bar', 'Lollipop Chart'],
        'example': 'Doanh thu theo vùng miền, performance theo nhân viên'
    },
    'Xu hướng theo thời gian': {
        'charts': ['Line Chart', 'Area Chart', 'Slope Chart'],
        'example': 'Doanh thu theo tháng, user growth, stock price'
    },
    'Tỷ lệ / Phần-tổng': {
        'charts': ['Stacked Bar', 'Treemap', 'Waffle Chart'],
        'example': 'Market share, budget allocation, survey results'
    },
    'Phân phối': {
        'charts': ['Histogram', 'Boxplot', 'Violin Plot'],
        'example': 'Phân phối lương, thời gian session, điểm số'
    },
    'Quan hệ / Tương quan': {
        'charts': ['Scatter Plot', 'Bubble Chart', 'Heatmap'],
        'example': 'Giá vs diện tích, chi tiêu marketing vs doanh thu'
    }
}

fig, ax = plt.subplots(figsize=(14, 7))
ax.axis('off')

# Header
headers = ['Câu hỏi', 'Chart phù hợp', 'Ví dụ']
col_widths = [0.22, 0.35, 0.43]

table_data = []
for question, info in chart_guide.items():
    table_data.append([question, ', '.join(info['charts']), info['example']])

table = ax.table(cellText=table_data, colLabels=headers,
                 cellLoc='left', loc='center',
                 colWidths=col_widths)

table.auto_set_font_size(False)
table.set_fontsize(10)
table.scale(1, 2.2)

# Style header
for j in range(3):
    table[0, j].set_facecolor('#2C3E50')
    table[0, j].set_text_props(color='white', fontweight='bold')

plt.title('📊 Chart Selection Guide — Chọn đúng chart cho đúng câu hỏi',
          fontsize=14, fontweight='bold', pad=20)
plt.tight_layout()
plt.show()

"Công thức đơn giản," Dũng tóm tắt. "Trước khi chọn chart, tự hỏi: 'Mình muốn người đọc SO SÁNH, thấy XU HƯỚNG, hiểu TỶ LỆ, nhìn PHÂN PHỐI, hay tìm MỐI QUAN HỆ?' Câu trả lời quyết định chart type."

Phần 4: Visualization Best Practices — IBCS & "Less is More"

Dũng hướng dẫn Hạnh redo lại chart cho QBR. Nguyên tắc cốt lõi: mỗi chart phải kể được đúng 1 câu chuyện.

"The Economist có style guide riêng cho data viz," Dũng giải thích. "Họ theo 5 nguyên tắc: (1) clear title nêu rõ insight, (2) minimal color — max 3, (3) direct labeling thay vì legend, (4) no gridlines thừa, (5) source citation. IBCS cũng tương tự — chuẩn hóa biểu đồ trong business communication."

Hạnh redo slide chính:

python
import matplotlib.pyplot as plt
import numpy as np

# Data: Doanh thu theo kênh và vùng miền (tỷ VNĐ)
regions = ['TP.HCM', 'Hà Nội', 'Đà Nẵng', 'Cần Thơ', 'Hải Phòng']
online = [45.2, 38.7, 12.3, 8.5, 6.1]
offline = [62.1, 55.3, 18.9, 15.2, 11.8]

fig, ax = plt.subplots(figsize=(12, 6))

x = np.arange(len(regions))
width = 0.35

# Màu theo IBCS: actual (đậm) vs budget/comparison (nhạt)
bars1 = ax.bar(x - width/2, offline, width, label='Offline', color='#2C3E50', edgecolor='white')
bars2 = ax.bar(x + width/2, online, width, label='Online', color='#3498DB', edgecolor='white')

# Direct labeling — không cần legend phức tạp
for bar in bars1:
    ax.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.8,
            f'{bar.get_height():.1f}', ha='center', va='bottom', fontsize=9, fontweight='bold')
for bar in bars2:
    ax.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.8,
            f'{bar.get_height():.1f}', ha='center', va='bottom', fontsize=9, fontweight='bold',
            color='#3498DB')

# Title kể câu chuyện — không generic
ax.set_title('Offline vẫn chiếm ưu thế ở mọi vùng, nhưng Online đang thu hẹp khoảng cách tại TP.HCM',
             fontsize=12, fontweight='bold', pad=15)

ax.set_xticks(x)
ax.set_xticklabels(regions, fontsize=11)
ax.set_ylabel('Doanh thu (tỷ VNĐ)', fontsize=11)
ax.legend(frameon=False, fontsize=11)

# Remove chartjunk — Less is More
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.tick_params(left=False)
ax.yaxis.grid(True, alpha=0.3, linestyle='--')
ax.set_axisbelow(True)

# Source
ax.text(0.99, -0.12, 'Nguồn: Hệ thống POS + E-commerce platform, Q4/2025',
        transform=ax.transAxes, fontsize=8, ha='right', style='italic', color='gray')

plt.tight_layout()
plt.show()

Dũng nhận xét: "Thấy không? Title bây giờ KỂ CÂU CHUYỆN — 'Offline vẫn chiếm ưu thế nhưng Online đang thu hẹp khoảng cách tại TP.HCM.' CEO nhìn vào title là hiểu insight ngay. Không cần đọc số. Đó là chuẩn The Economist."

5 nguyên tắc Visualization Best Practices (theo IBCS & The Economist)

  1. Title = Insight, không phải mô tả → "Doanh thu theo vùng miền" ❌ vs "Offline chiếm ưu thế nhưng Online thu hẹp khoảng cách ở TP.HCM" ✅
  2. Tối đa 3-4 màu → 1 màu chính + 1 màu so sánh + 1 màu highlight cho insight chính
  3. Direct labeling > Legend → Gắn label trực tiếp lên data point, người đọc không phải nhìn qua nhìn lại
  4. Remove chartjunk → Bỏ gridlines thừa, 3D effect, shadow, border. Mọi pixel phải phục vụ data.
  5. Source citation → Luôn ghi nguồn dữ liệu — tạo credibility, nhất là khi present cho C-level

Phần 5: Từ "Slide đẹp" đến "Slide kể chuyện"

Hạnh dành cuối tuần redo toàn bộ QBR deck. Cô áp dụng mọi nguyên tắc Dũng dạy: bar chart thay pie chart, tách dual-axis thành 2 chart riêng, giảm màu xuống còn 3, title mỗi chart là insight.

Thứ Hai tuần sau, Hạnh present lại cho CFO ông Đức — lần này chỉ 2 người trong phòng họp nhỏ.

Slide đầu tiên: bar chart ngang so sánh doanh thu theo danh mục — sorted descending, data labels rõ ràng, title: "Thực phẩm dẫn đầu nhưng Điện tử tăng trưởng nhanh nhất (+32% QoQ)."

Slide thứ hai: hai line chart cạnh nhau — doanh thu và số đơn — với annotation chỉ rõ: "AOV giảm 51% — khách mua nhiều hơn nhưng giá trị đơn giảm do flash sale quá nhiều."

Slide thứ ba: heatmap đơn giản — vùng miền × kênh bán — highlight TP.HCM online đang bắt kịp offline.

Ông Đức nhìn xong 3 slide, gật đầu: "Bây giờ anh hiểu rồi. AOV giảm là vấn đề quan trọng nhất — mình cần review lại chiến lược flash sale. Hạnh trình bày cái này ở QBR tuần sau nhé."

Hạnh cười. Cùng data, cùng insight — nhưng chart khác, câu chuyện khác hoàn toàn.

"Visualization không phải trang trí cho data," Hạnh viết lên sticky note dán cạnh màn hình. "Visualization là bản đồ — vẽ đúng thì người đọc đến đúng đích. Vẽ sai thì insight hay mấy cũng vô nghĩa."

Kết luận

Hạnh không phải DA tệ. Cô là Senior DA giỏi — EDA kỹ, insight đúng, Python thành thạo. Nhưng cô suýt thất bại ở bước cuối cùng: truyền tải insight đến người ra quyết định.

Chart không phải hình minh họa. Chart là công cụ truyền thông. Một bar chart đơn giản với đúng title có thể thay đổi quyết định triệu đô. Một 3D pie chart rực rỡ có thể khiến CEO hiểu sai hoàn toàn.

Edward Tufte nói: "The purpose of visualization is insight, not pictures." Mục đích của visualization là insight — không phải hình đẹp.

Nếu bạn đang chuẩn bị presentation — hãy tự hỏi: "Chart của mình đang kể câu chuyện gì? Người đọc nhìn vào 5 giây có hiểu insight không? Có element nào trên chart không phục vụ data?"

Vì chart đẹp mà sai — còn tệ hơn không có chart.

Điểm chính cần nhớ

  • Chart = Bản đồ dẫn đường — sai bản đồ thì đi lạc. Chart tốt giúp người đọc đến đúng insight trong 5 giây. Chart sai khiến người đọc hiểu sai data, dẫn đến quyết định sai.
  • 3 "Chart Fails" phổ biến nhất: 3D pie chart (méo perception), dual-axis (false correlation), rainbow colors (cognitive overload). Tránh cả ba.
  • Chọn chart theo câu hỏi: So sánh → bar, xu hướng → line, phân phối → histogram/boxplot, quan hệ → scatter, tỷ lệ → stacked bar. Không đoán — tra bảng rồi chọn.
  • Title = Insight — đừng viết "Doanh thu theo tháng." Viết "Doanh thu tăng 15% nhưng AOV giảm 51% do flash sale." Title tốt khiến người đọc hiểu chart mà không cần đọc số.
  • Less is More — bỏ 3D, bỏ shadow, bỏ gridlines thừa, giảm màu. Mỗi pixel trên chart phải phục vụ data. Mọi thứ khác là chartjunk.
  • IBCS & The Economist standards — dùng tối đa 3-4 màu, direct labeling thay legend, ghi nguồn data, chart kể 1 câu chuyện duy nhất.
  • Visualization là bước cuối nhưng quan trọng nhất — insight hay mà chart sai thì sếp không hiểu, stakeholder không action. 10 phút chọn đúng chart = tiết kiệm 1 buổi present thất bại.