Giới thiệu về định dạng bảng trong Pandas
Trong quy trình xử lý và phân tích dữ liệu, việc trực quan hóa thông tin đóng vai trò then chốt giúp người dùng nắm bắt nhanh chóng các xu hướng tiềm ẩn. Bên cạnh biểu đồ, bảng dữ liệu được định dạng đẹp mắt cũng là công cụ hữu hiệu. Tuy nhiên, thư viện Pandas mặc định chỉ hiển thị dữ liệu thô. Để khắc phục điều này, chúng ta có thể sử dụng cơ chế Styler của Pandas kết hợp với các hàm tùy chỉnh để áp dụng màu sắc cho từng hàng dựa trên điều kiện cụ thể.
Nguyên lý hoạt động của việc tùy chỉnh giao diện
Mặc dù Pandas không hỗ trợ thay đổi màu sắc trực tiếp trên đối tượng DataFrame gốc cho mục đích lưu trữ, nhưng thuộc tính .style cung cấp một bộ công cụ mạnh mẽ để tạo ra bản xem trước HTML hoặc Jupyter Notebook tương tác. Chúng ta có thể truyền một hàm Python vào phương thức apply, hàm này sẽ nhận dữ liệu đầu vào và trả về chuỗi CSS tương ứng để áp dụng cho ô hoặc hàng.
Các phương pháp chính
- Sử dụng
apply(axis=1): Phù hợp để thao tác trên toàn bộ dòng dựa trên giá trị của nhiều cột. - Sử dụng
applymap(hoặcmaptrong phiên bản mới): Tác động đến từng ô riêng lẻ nếu cần chi tiết hơn. - Kết hợp với thư viện vẽ: Sử dụng
matplotlibđể xuất ra ảnh tĩnh khi môi trường không hỗ trợ HTML.
Triển khai thực tế với mã nguồn Python
Dưới đây là các ví dụ minh họa cách thiết lập màu nền cho các hàng trong bảng dữ liệu theo các kịch bản khác nhau.
Ví dụ 1: Đánh dấu theo ngưỡng giá trị cố định
Bảng dưới đây chứa doanh thu bán hàng. Chúng ta sẽ làm nổi bật các sản phẩm có doanh số vượt mức 150 đơn vị.
import pandas as pd
# Khởi tạo dữ liệu mẫu
ten_san_pham = ['Alpha', 'Beta', 'Gamma', 'Delta']
doanh_so = [120, 180, 90, 200]
bap_an = pd.DataFrame({'Ten': ten_san_pham, 'DoanhSo': doanh_so})
def thiet_lap_mau_trong_ve_doi_cua_so(hang):
"""Hàm kiểm tra điều kiện và trả về định dạng CSS"""
gia_tri = hang['DoanhSo']
neu_tra_mau = 'background-color: #ffcccc' # Màu đỏ nhạt
mac_dinh = ''
danh_sach_css = [mac_dinh] * len(hang)
if gia_tri > 150:
danh_sach_css = [neu_tra_mau] * len(hang)
return danh_sach_css
ket_qua_nen = bap_an.style.apply(thiet_lap_mau_trong_ve_doi_cua_so, axis=1)
# ket_qua_nen // Hiển thị trong Jupyter Notebook
Ví dụ 2: Phân loại theo thứ tự thống kê
Thay vì so sánh với con số cố định, ta có thể tô màu dựa trên giá trị lớn nhất và nhỏ nhất của tập dữ liệu hiện hành.
max_gia = bap_an['DoanhSo'].max()
min_gia = bap_an['DoanhSo'].min()
def canh_bao_cuoi_cung_va_dau_danh(hang):
"""Đánh dấu cực đại và cực tiểu"""
mau_xanh = 'background-color: #ccffcc'
mau_do = 'background-color: #ffcccc'
trang = ''
if hang['DoanhSo'] == max_gia:
result = [mau_xanh] * len(hang)
elif hang['DoanhSo'] == min_gia:
result = [mau_do] * len(hang)
else:
result = [trang] * len(hang)
return result
styled_table = bap_an.style.apply(can_bao_cuoi_cung_va_dau_danh, axis=1)
print(styled_table)
Ví dụ 3: Mã màu gradient động
Sử dụng colormap từ Matplotlib để gán màu độ sâu khác nhau tương ứng với mức độ cao thấp của dữ liệu liên tục.
import matplotlib.pyplot as plt
from matplotlib.cm import get_cmap
import numpy as np
chuoi_mau = get_cmap('plasma')
def tao_mau_theo_tiem_tuc(hang):
"""Tính toán tỷ lệ phần trăm và chuyển sang mã màu RGBA"""
ds_min = bap_an['DoanhSo'].min()
ds_max = bap_an['DoanhSo'].max()
range_val = ds_max - ds_min
normalized_val = (hang['DoanhSo'] - ds_min) / range_val
# Lấy màu RGB từ colormap
rgb_color = chuoi_mau(normalized_val)[:3]
rgba_str = f"rgba({rgb_color[0]*255}, {rgb_color[1]*255}, {rgb_color[2]*255}, 1)"
return [f'background-color: {rgba_str}'] * len(hang)
gradient_style = bap_an.style.apply(tao_mau_theo_tiem_tuc, axis=1)
Ví dụ 4: Thay đổi màu chữ dựa trên nội dung văn bản
Hướng dẫn cách thay đổi color của chữ thay vì nền, áp dụng khi tên sản phẩm chứa ký tự đặc biệt.
def bien_thanh_van_menh(mot_dong):
"""Kiểm tra chuỗi tên sản phẩm"""
mau_chu_xanh_duong = 'color: blue; font-weight: bold'
mau_chu_den = ''
if 'Alpha' in mot_dong['Ten']:
return [mau_chu_xanh_duong] * len(mot_dong)
return [mau_chu_den] * len(mot_dong)
text_styled = bap_an.style.apply(bien_thanh_van_menh, axis=1)
Ví dụ 5: Vẽ bảng tĩnh bằng Matplotlib
Nếu bạn cần xuất file ảnh mà không phụ thuộc vào trình duyệt web, việc xây dựng bảng trực tiếp trên trục tọa độ đồ họa là giải pháp tối ưu.
fig, ax = plt.subplots(figsize=(5, 3))
ax.axis('tight')
ax.axis('off')
# Tạo đối tượng Table
tbl = ax.table(cellText=bap_an.values, colLabels=bap_an.columns, loc='center')
for i in range(len(bap_an)):
for j in range(len(bap_an.columns)):
if bap_an.iloc[i, 1] > 150:
tbl[(i+1, j)].set_facecolor('#ffff00')
plt.show()
Ví dụ 6: Kết hợp nhiều tiêu chí phức tạp
Áp dụng logic AND/OR để lọc điều kiện trước khi gắn nhãn màu sắc.
def phan_loai_phuc_hop(row_data):
"""Kết hợp điều kiện doanh số và tên sản phẩm"""
default_bg = ''
# Điều kiện: Doanh số lớn nhưng tên chứa 'Beta'
if row_data['DoanhSo'] >= 150 and 'Beta' in row_data['Ten']:
default_bg = 'background-color: lightgreen'
# Điều kiện: Doanh số thấp bất kể tên
elif row_data['DoanhSo'] < 100:
default_bg = 'background-color: lightcoral'
return [default_bg] * len(row_data)
multi_condition_view = bap_an.style.apply(phan_loai_phuc_hop, axis=1)
Ví dụ 7: Sử dụng hàm chuẩn hóa Z-score
Dùng biến thiên thống kê để phát hiện ngoại lai (outliers).
mean_val = bap_an['DoanhSo'].mean()
std_val = bap_an['DoanhSo'].std()
def highlight_outliers(x):
z_score = abs((x['DoanhSo'] - mean_val) / std_val)
if z_score > 1.5:
return ['background-color: yellow'] * len(x)
return [''] * len(x)
stats_highlight = bap_an.style.apply(highlight_outliers, axis=1)
Ví dụ 8: Áp dụng Gradient Gradient sẵn có của Pandas
Pandas tích hợp sẵn hàm background_gradient giúp tiết kiệm代码 lượng viết tùy chỉnh nếu chỉ cần so sánh trong một cột.
# Chỉ tô màu cột doanh số dựa trên sự chênh lệch trong cột đó
simple_gradient = bap_an.style.background_gradient(cmap='Blues', subset=['DoanhSo'], axis=0)
Ví dụ 9: Thay đổi kiểu dáng bảng dựa trên ngày tháng
Giả sử dữ liệu có thêm cột thời gian, chúng ta có thể đánh dấu cuối tuần hoặc ngày lễ.
du_lieu_time = pd.DataFrame({
'Ngay': pd.date_range('2023-01-01', periods=5),
'Luu_Luong': [10, 20, 30, 40, 50]
})
def dinh_dang_thoi_gian(dt_row):
weekday = dt_row['Ngay'].weekday()
if weekday >= 5: # Cuối tuần là 5, 6
return ['background-color: #eee'] * len(dt_row)
return [''] * len(dt_row)
time_styled = du_lieu_time.style.apply(dinh_dang_thoi_gian, axis=1)
Ví dụ 10: Tùy chỉnh CSS nâng cao
Không chỉ màu nền, bạn có thể thay đổi viền, độ dày hay đường viền quanh ô.
def advanced_style(dong_data):
# Đổi cả border và background
css_rules = ['border: 1px solid black; padding: 10px; background-color: #f0f0f0']
return css_rules * len(dong_data)
complex_border = du_lieu_time.style.apply(advanced_style, axis=1)