Challenge
- Slicer: Select Target để tự điều chỉnh mức target → Chart thay đổi dynamic theo.
- Chia thành 2 vùng màu: Green Zone & Red Zone → Thay đổi dynamic theo target.
- Vùng xanh từ target lên trên cùng – Vùng đỏ từ target xuống dưới đáy
- Có đường Line tự đổi màu theo Green Zone & Red Zone
- Chỉ hiển thị Label tại Red Zone & Data Labels với YoY% (So với năm trước)
- 6.8K ▲ +800 (+13%) ← Tăng so với năm trước → Xanh
- 3.6K ▼ -1.5K (-29%) ← Giảm so với năm trước → Đỏ
- Có Title Dynamic thay đổi theo chart
- Phân Tích Doanh Số (Target: 10,000) | Đạt: 5/12 → Tiêu đề tự động cập nhật khi thay đổi target.
Learninng by Doing – Học PBI Qua Challenge
Nhóm 1 – Base Measures
Total Sales = SUM(Fact_Sales[SalesAmount])
Total Sales LY =
VAR _Result =
CALCULATE(
[Total Sales],
SAMEPERIODLASTYEAR(Dim_Date[Date])
)
RETURN
_Result
Boundary Target = [Target Value]
Tại sao sử dụng Boundary Target
Nhóm 2 – Error Band (Vùng Màu)
Over UB1 =
VAR _MaxSales =
CALCULATE( -- Sẽ thay đổi filter context trước khi tính expression bên trong
-- VALUES(Dim_Date[MonthYear]): Lấy danh sách các tháng unique (Jan-2024, Feb-2024...)
-- MAXX(..., [Total Sales]): Duyệt từng tháng, tính [Total Sales] cho tháng đó, lấy giá trị MAX
MAXX(VALUES(Dim_Date[MonthYear]), [Total Sales]),
-- MAXX + VALUES: MAX(Column) chỉ lấy max của cột, MAXX cho phép tính [Total Sales] (measure) cho từng tháng
ALLSELECTED(Dim_Date) -- ALLSELECTED xóa filter Dim_Date -> Bây giờ thấy TẤT CẢ các tháng
-- ALL bỏ qua cả Slicer, ALLSELECTED giữ lại Slicer → đường thẳng sẽ cập nhật khi user filter
)
RETURN
_MaxSales * 1.2 -- Tạo khoảng trống 20% phía trên cột cao nhất
-- Đảm bảo vùng màu xanh luôn cao hơn data point cao nhất
Measure Over UB1 tạo một đường thẳng ngang ở mức cao hơn 20% so với doanh số cao nhất. Dùng làm Upper Bound (giới hạn trên) cho Error Band màu xanh lá (Green Zone).
Under LB1 =
VAR _MinSales =
CALCULATE(
MINX(VALUES(Dim_Date[MonthYear]), [Total Sales]),
ALLSELECTED(Dim_Date)
)
RETURN _MinSales
Measure Under LB1 tạo một đường thẳng ngang ở mức doanh số thấp nhất. Dùng làm Lower Bound (giới hạn dưới) cho Error Band màu đỏ (Red Zone).
Total Sales2 =
IF(
[Total Sales] <= [Boundary Target],
[Total Sales],
BLANK()
)
Measure Total Sales2 trả về doanh số CHỈ KHI tháng đó KHÔNG ĐẠT target. Dùng để hiển thị Data Labels chỉ tại những điểm nằm trong Red Zone.
Tạo Line Chart với 2 lines
- Line 1:
[Total Sales](đường chính) → Tắt Data Labels - Line 2:
[Total Sales2](đường phụ) → Bật Data Labels - Chỉnh màu lại Line 2 cho phù hợp
Nhóm 3 – Conditional Line (Đường Line Đổi Màu)
Sales Green Line =
IF(
[Total Sales] > [Boundary Target],
[Total Sales],
BLANK()
)
Sales Red Line =
IF(
[Total Sales] <= [Boundary Target],
[Total Sales],
BLANK()
)
-- Measure tạo đường line màu đỏ chỉ hiển thị tại những tháng không đạt target (Sales <= Target). Kết hợp với [Sales Green Line] để tạo hiệu ứng đường đổi màu.
YoY Detail =
VAR _Sales = [Total Sales] -- Tạo biến _Sales để lưu doanh số NĂM NAY
VAR _SalesLY = [Total Sales LY] -- Tạo biến _SalesLY để lưu doanh số NĂM TRƯỚC (Last Year)
VAR _Variance = _Sales - _SalesLY -- Tính chênh lệch tuyệt đối giữa năm nay và năm trước
VAR _VarPct = DIVIDE(_Variance, _SalesLY, 0) -- Tính phần trăm thay đổi
VAR _Arrow = IF(_Variance >= 0, "▲", "▼") -- Chọn mũi tên dựa trên xu hướng
VAR _AbsVar = ABS(_Variance) -- Lấy giá trị tuyệt đối của chênh lệch -> Dùng để so sánh độ lớn (xem thuộc nhóm K, M hay B)
VAR _FormattedVar =
-- Định dạng số theo đơn vị K/M/B cho gọn gàng
SWITCH(TRUE(),
_AbsVar >= 1000000000, FORMAT(_Variance/1000000000, "+0.#;-0.#") & "B", -- Tỷ (Billion)
_AbsVar >= 1000000, FORMAT(_Variance/1000000, "+0.#;-0.#") & "M", -- Triệu (Million)
_AbsVar >= 1000, FORMAT(_Variance/1000, "+0.#;-0.#") & "K", -- Nghìn (Thousand)
FORMAT(_Variance, "+0;-0") -- Số nguyên
)
RETURN
IF(NOT ISBLANK(_SalesLY), -- Có dữ liệu năm trước → Ghép chuỗi kết quả
_Arrow & " " & _FormattedVar & " (" & FORMAT(_VarPct, "+0%;-0%") & ")",
BLANK() -- Không có dữ liệu năm trước → Trả về BLANK() (ô trống)
)
Measure YoY Detail tạo một label so sánh doanh số năm nay vs năm ngoái với định dạng đẹp mắt, gồm:
- Mũi tên chỉ xu hướng (▲ tăng / ▼ giảm)
- Số chênh lệch được format gọn gàng (K/M/B)
- Phần trăm thay đổi
- Kết quả ví dụ:
▲ +1.5M (+12%)hoặc▼ -200K (-8%)
YoY Detail Color =
VAR _CurrentSales = [Total Sales] -- Lưu doanh số NĂM NAY vào biến _CurrentSales
VAR _LastYearSales = [Total Sales LY] -- Lưu doanh số NĂM TRƯỚC vào biến _LastYearSales
VAR _Variance = _CurrentSales - _LastYearSales -- Tính chênh lệch giữa 2 năm
VAR _Result =
SWITCH( -- Bắt đầu khối SWITCH TRUE() để đánh giá nhiều điều kiện
TRUE(), -- Kiểm tra từ trên xuống, gặp điều kiện đúng đầu tiên → trả về kết quả và DỪNG
ISBLANK(_LastYearSales), "#383838", -- Không có dữ liệu năm trước
_Variance > 0, "#0099bf",
_Variance < 0, "#9f3434",
"#383838"
)
RETURN
_Result
Measure YoY Detail Color trả về mã màu HEX để tô màu cho Data Labels dựa trên xu hướng so sánh YoY:
- Xanh dương (
#0099bf) → Tăng trưởng dương (năm nay > năm trước) - Đỏ (
#9f3434) → Tăng trưởng âm (năm nay < năm trước) - Xám (
#383838) → Không có dữ liệu hoặc bằng nhau
Vào Visual → Format → Data Labels
- Series → Total Sales2
- Chọn Color → fx (Conditional Formatting)
- Chọn Format by: Field Value → Chọn measure
[YoY Detail Color]
Nhóm 4 – Title Dynamic
Months Met Target =
VAR _CurrentTarget = Target[Target Value]
VAR _MonthsTable = VALUES(Dim_Date[MonthYear])
VAR _AchievedMonthsTable =
FILTER(
_MonthsTable,
[Total Sales] >= _CurrentTarget
)
VAR _Result = COUNTROWS(_AchievedMonthsTable)
RETURN
_Result
Dynamic Title =
VAR _TotalMonths = DISTINCTCOUNT(Dim_Date[MonthYear])
VAR _AchievedMonths = [Months Met Target]
VAR _TargetValueText = FORMAT(Target[Target Value], "#,##0")
VAR _Result =
"Phân Tích Doanh Số (Target: " & _TargetValueText & ")" &
" | Đạt: " & "(" & _AchievedMonths & "/" & _TotalMonths & ")"
RETURN
_Result
Chi tiết hơn sẽ được hướng dẫn step by step trong khóa học.
