# Tableau / Power BI Build Specification

This document specifies how to rebuild the interactive dashboard
(`index.html`) natively in Tableau Public or Power BI Desktop, for use in
an interview or technical test where the specific tool matters. It reproduces
the same content, filters, and cross-filtering behaviour, using the same
underlying data, embedded inline in `index.html`'s
`<script id="data-blob" type="application/json">` tag rather than shipped as
a separate file.

Source data: open `index.html` in a text editor or browser dev tools, copy
the contents of that `data-blob` script tag, and export its `records` array
to a flat CSV (`dashboard_records.csv`) with one row per country-survey
observation. Fields: `iso3, country, region, year, income_class,
income_label, stunting_pct, wasting_pct, underweight_pct, overweight_pct,
wash_access_composite, gdp_per_capita_usd, female_literacy_pct,
u5_population_000s, stunting_high_burden, wasting_high_burden`. A second,
static reference table (`shap_drivers.csv`: `feature_label, mean_abs_shap`)
holds the fixed model driver ranking from `notebook/model_results.json`.

## 1. Data connections

1. Connect to `dashboard_records.csv` as the primary data source.
2. Connect to `shap_drivers.csv` as a second, unrelated data source (it feeds
   the Model Driver Ranking sheet only and should not be joined or blended
   with the records table, since it is a fixed model artifact, not a filtered
   view of the panel).

## 2. Calculated fields

Create these on the `dashboard_records` source:

| Field | Formula (Tableau syntax; Power BI DAX equivalent noted) | Purpose |
|---|---|---|
| `Survey Period` | `STR([Year] - ((INT([Year])-1983) % 5))` concatenated to `+ "-" + STR(period_start+4)` (or a lookup table for the eight 5-year bins 1983-1987 ... 2015-2019) | Groups sparse survey years into readable bins for the trend chart. Power BI: a calculated column bucketing `Year` into `FLOOR((Year-1983)/5)*5+1983`. |
| `Stunting Burden Flag` | `IF [stunting_pct] >= 20 THEN "High/very high" ELSE "Low/medium" END` | Drives the KPI status chip and the class-distribution view. |
| `Wasting Burden Flag` | `IF [wasting_pct] >= 15 THEN "High/very high" ELSE "Low/medium" END` | Same, for wasting. |
| `WASH Status Flag` | `IF [wash_access_composite] >= 65 THEN "Adequate access" ELSE "Below 65% access" END` | Drives the WASH KPI chip. |
| `Income Classification (Ordinal)` | Already present as `income_class` (0-3); expose `income_label` as the display field and sort by the numeric field. | Wealth-quintile analogue for filtering/sorting. |

## 3. Sheets to build

**Sheet 1: KPI cards ("Burden Summary").** Five text/BAN (Big Ass Number)
tiles: AVG(stunting_pct), AVG(wasting_pct), AVG(underweight_pct),
AVG(wash_access_composite), and COUNTD(iso3) alongside COUNT(records). Format
each as a single number with a subtitle. Add a colored indicator (Tableau:
a small shape or colored text using the burden-flag fields with a
two-value color legend restricted to the desaturated amber `#B45309` /
green `#15803D` pair from the dashboard's palette, never the default
red/green traffic-light palette). Power BI: use Card visuals with
conditional formatting rules bound to the same flag fields.

**Sheet 2: Prevalence trend.** A dual-line chart: `Survey Period` on the
columns shelf, `AVG(stunting_pct)` and `AVG(wasting_pct)` on rows as two
measures (dual-axis combined into one shared 0-100% axis, not two separate
scales). Add two reference lines at y=20 and y=15 (Tableau: Analytics pane
> Reference Line, one per measure, dashed, labeled "WHO high-burden
threshold"). Color the two measures navy (`#1A3A5C`) and blue (`#2563EB`) to
match the dashboard.

**Sheet 3: Model driver ranking.** A horizontal bar chart from
`shap_drivers.csv`: `feature_label` on rows (sorted descending by
`mean_abs_shap`), `mean_abs_shap` on columns. Single color fill (`#2563EB`),
no color legend needed since it is one series. Add a caption noting this
sheet is not affected by the dashboard's filters, since it reflects a fixed
trained model.

**Sheet 4: Data quality assessment.** A text table (five rows: Validity,
Integrity, Precision, Reliability, Timeliness, each with its note), built
from a small manually-entered data source (`dqa_notes.csv`: `dimension,
note`) since this content does not vary with the data and is not aggregated
from `dashboard_records`.

## 4. Dashboard layout

Use a **top-KPI-row-plus-detail** layout, matching `index.html`:

```
+--------------------------------------------------------------+
|  Filters: Region | Income Classification | Survey Period      |
+--------------------------------------------------------------+
|  KPI 1  |  KPI 2  |  KPI 3  |  KPI 4  |  KPI 5 (counts)        |
+--------------------------------+-------------------------------+
|  Prevalence trend (Sheet 2)    |  Model driver ranking          |
|                                 |  (Sheet 3, fixed)              |
+--------------------------------+-------------------------------+
|  Data quality assessment (Sheet 4)                             |
+--------------------------------------------------------------+
```

Suggested canvas size: 1280x1600 (fixed layout), or a floating layout with the
filter row pinned to the top so it stays visible while scrolling.

## 5. Filters and cross-filtering

Add three filters to the dashboard (not to individual sheets), applied to
**all worksheets built from `dashboard_records`** (Sheet 1 and Sheet 2, not
Sheet 3 or Sheet 4, which are intentionally fixed):

1. `region` (single-select dropdown, default "All")
2. `income_label` (single-select dropdown, default "All")
3. `Survey Period` (single-select dropdown, default "All")

In Tableau, add each filter to the dashboard via the filter card's "Apply to
Worksheets > Selected Worksheets" option, checking only Sheet 1 and Sheet 2.
In Power BI, use a slicer visual per field and, in the slicer's edit
interactions pane, set Sheet 3 and Sheet 4's visuals to "None" so they stay
fixed while Sheet 1 and Sheet 2 respond. Add a "Reset filters" button
(Tableau: a dashboard button running a "Clear filter" action per filter;
Power BI: a bookmark that resets slicer state).

## 6. Palette reference

Reuse the exact hex values from `index.html`'s CSS `:root` block so a
native rebuild reads as the same product:

```
Navy:        #1A3A5C   (headers, primary line series)
Blue:        #2563EB   (secondary line series, single-hue bars)
Blue tint:   #EFF6FF   (callout backgrounds)
Background:  #FFFFFF
Card fill:   #F4F8FC
Border:      #CBD8E6
Text:        #1E2D3D
Muted text:  #566B7E
Amber (status): #B45309
Green (status): #15803D
```

Avoid Tableau's and Power BI's default categorical palettes on these sheets;
manually map each measure/series to the hex values above.
