*! version 1.3.1 15jul2026

Title

dashboardbuilder -- Build a self-contained, interactive HTML
dashboard from Stata (tabs, charts, KPI tiles, selector dropdown, CSV/PDF
download buttons, themed styling)

Syntax

Start a dashboard:

dashboardbuilder init , title(string)
[subtitle(string) selector(name) sellabel(string)
refvalue(string) tx2036 theme(simple|tx2036)]

Declare a tab (optional; panels without tabs share one page):

dashboardbuilder tab , name(name) [label(string)]

Capture the data currently in memory as one panel (repeat per panel):

dashboardbuilder panel paneltype , type_options
[tab(name) title(string) note(string) interp(string)
ytitle(string)]

where paneltype is
kpi | line | bar | hbar | compare | table | html

Write the HTML file and print the build receipt:

dashboardbuilder build using filename.html
[, replace nocsv nopng notooltip pdf
truepdf corner callout(string) sourcenote(string) noopen]

Utilities:

dashboardbuilder describe (show what has been registered so far)

dashboardbuilder clear (abandon the current build)

dashboardbuilder openlast (open the last-built dashboard in the browser)

dashboardbuilder openfolder (open the folder that contains it)

Description

dashboardbuilder is a putdocx-style builder: you call it
several times, then finish. Each panel call snapshots the data
currently in memory, so the natural workflow is to load or derive one analytic
subset, capture it as a panel, derive the next subset, capture it, and so on.
build then writes one self-contained HTML file: all data embedded as
inline JSON, all charts drawn by readable vanilla JavaScript/SVG, no internet,
no CDN, no external files. The file opens by double-click, works from a shared
drive or email attachment, and prints cleanly.

The output is deliberately a starter wireframe. Every chart is plain,
commented JS you can open and tweak; the file marks intended tweak points with
EDIT-ME comments, and the Stata build receipt lists what was built
plus what likely still needs a human pass (missing titles, missing sources,
crowded charts, oversize panels, and similar).

Layout, top to bottom: themed header (title + subtitle); a controls card with
the optional selector dropdown and the tab bar; one card per panel (title,
optional interpretation callout, optional CSV button, chart, legend, note); an
optional callout box; and a source/footer line. An optional
save-as-PDF button uses the browser's print-to-PDF with a bundled print
stylesheet.

Panel types

kpi big-number tiles. values(varlist) names the numeric
variables; each becomes a tile using its variable label. Collapse your data to
one row (per selector unit) first: the first visible row supplies the values.

line line chart. x() is the horizontal variable (numeric,
for example year); y(varlist) draws one line per variable. String
x is treated as ordered categories.

bar vertical bars. x() is the category; y() the
numeric height. Value labels on x are honored.

hbar horizontal bars; better when category names are long or
numerous (rankings).

compare bullet bars: one row per x() category, a bar for
y(), and a | reference marker from ref(varname) or, when a
selector reference is set, from the reference unit's own rows (see below). All
rows share one scale, so bar lengths are comparable.

table plain table of vars(varlist) (default: all
variables). Renders the first 500 rows; the CSV download has all rows.

html embed an external HTML file named in file(string) (for
example a sparkta2 map or any saved interactive chart). The file's
contents are inlined into an <iframe>, so the dashboard stays one
self-contained file. Takes no data from memory; use height(#) to set the
frame height in pixels (default 520). Static (it does not filter with the
selector).

The selector (the "choose a county" pattern)

selector(name) on init names a variable (for example
selector(county)). Any panel whose captured data contains a variable
with that name becomes filterable: the dashboard gets a dropdown, and
those panels re-render showing only the rows of the chosen unit. Panels
without the column stay static.

With tabs, the dropdown is shown only on tabs that have at least one filterable
panel, and auto-hidden on tabs where nothing filters (so a "choose a unit"
control is never offered where it would do nothing). A tab that is entirely
static therefore reads as a selection-independent overview.

refvalue(string) names one value of the selector to treat as the
reference unit, for example refvalue("Texas (statewide)") or
refvalue("United States"). Effects: the value is pinned to the top of the
dropdown; line panels overlay the reference unit's series as dashed
lines; compare panels place the | marker at the reference unit's
value when no ref() variable was given. Build the reference row yourself
(for example collapse + append) before capturing panels; it is
ordinary data.

Options

init

title(string) dashboard title (required). Shown in the header
and the browser tab.

subtitle(string) smaller text next to the title.

selector(name) variable name that activates the dropdown-filter
machinery; see the selector.

sellabel(string) dropdown label; default "Choose a selector".

refvalue(string) selector value treated as the reference unit.

tx2036 Texas 2036 branding (navy #1B2D55, orange
#D44500); shorthand for theme(tx2036).

theme(simple|tx2036) color theme; default simple, a neutral
slate/blue.

tab

name(name) short internal name (no spaces).

label(string) button text; defaults to the name.

panel (all types)

tab(name) which tab the panel lives on; default is the most
recently declared tab (an implicit "main" tab is created if none exists).

title(string) card heading. Strongly recommended; untitled
panels are flagged in the receipt.

note(string) small muted text under the chart (source or caveat).

interp(string) one-line takeaway shown in an accent-colored
callout under the title.

ytitle(string) value-axis caption shown in the legend area
(line/bar/hbar/compare).

panel html (extra options)

file(string) path to the HTML file to embed (required for
html panels). Relative paths resolve against Stata's current working
directory; the file's contents are inlined into an <iframe srcdoc> at build
time, so the dashboard stays self-contained. Build the file first (for example a
sparkta2 map exported with offline), then pass its path here.

height(#) iframe height in pixels (default 520). Maps usually want
more, for example height(760).

build

using filename.html output path; ".html" is appended if
missing. Relative paths resolve against Stata's current working directory.

replace overwrite an existing file.

Per-panel buttons and tooltips are ON by default; all three are fully
self-contained (no internet). Turn them off with:

nocsv drop the per-panel CSV download button (CSV downloads the
panel's rows, filtered to the current selection).

nopng drop the per-panel PNG download button. PNG appears on the
chart panels (line/bar/hbar/compare), which are drawn as SVG and rasterized in
the browser with no library. The exported image carries the panel's title,
interpretation, legend, and note, not just the plot, so the chart is
self-describing. kpi and table are HTML, where a no-library canvas export cannot
be guaranteed across browsers, so they show CSV only.

notooltip disable the styled hover tooltips (self-contained; they
need no external library).

PDF download buttons (opt-in):

pdf add a Save as PDF button that uses the browser's own
print-to-PDF (controls are hidden by the print stylesheet). Fully offline.

truepdf add a one-click Download PDF button.
This pulls a JavaScript library (html2pdf.js) from a CDN, so this one
button needs internet and will not work on an air-gapped machine; the rest
of the dashboard still works offline. The button degrades gracefully (it alerts
and points the user to Save as PDF) when the library cannot load.

corner float the global PDF button(s) (Save as PDF /
Download PDF) as a fixed button in the bottom-right corner of the page,
instead of in the top controls card. Handy when the top of the dashboard is
busy (for example above a tall embedded map).

Notes and opening:

callout(string) highlighted note box near the bottom (use for
"projections are scenarios, not predictions"-style guardrails).

sourcenote(string) source citation line in the footer.

noopen do not auto-open the finished file. By default the
dashboard opens in your OS default browser as soon as the build finishes (via
the operating system's own opener: open on macOS, start on Windows,
xdg-open on Linux). Pass noopen to suppress that, for example in
batch runs or loops that build many files at once.

The build receipt also prints two clickable browse links -
the finished file and its containing folder - whose link text is the
full path, so a click opens it and you can also copy the path to navigate there
yourself. Reopen the last-built dashboard any time with
dashboardbuilder openlast, or open its folder with
dashboardbuilder openfolder.

Python requirements (read once, then forget)

dashboardbuilder uses Stata's built-in Python integration (Stata 16+) for
JSON serialization and HTML templating. It uses only the Python standard
library (json, os): there is nothing to pip install, ever.
The only requirement is that Stata can see a Python 3 interpreter.

Every init checks this and stops with instructions if not. To set
up or repair the link yourself:

1. python query -- shows what Stata is currently using.

2. python search -- lists Python installs Stata can find.

3. Point Stata at one (path varies by machine):

. python set exec /usr/local/bin/python3, permanently (Mac/Linux)

. python set exec C:\Python312\python.exe, permanently (Windows)

If a call ever fails with "the Python helper functions are missing", someone
ran python clear mid-session; run discard and start again from
dashboardbuilder init.

Examples

1. Two-minute minimal dashboard (auto data, default theme):

. sysuse auto, clear

. collapse (mean) price mpg weight, by(foreign)

. dashboardbuilder init , title("Auto quick look")

. dashboardbuilder panel bar , x(foreign) y(price) title("Mean price by origin")

. dashboardbuilder panel table , title("The numbers")

. dashboardbuilder build using "auto_quick.html", replace

(the dashboard opens automatically; add noopen to suppress)

2. Selector + reference unit (each state vs. a hand-built US row),
Texas 2036 theme, tabs, downloads:

. sysuse census, clear

. * build the reference row: a synthetic "United States" aggregate

. preserve

. collapse (sum) pop death marriage divorce (mean) medage [aw=pop]

. gen state = "United States"

. tempfile us

. save `us'

. restore

. append using `us'

. dashboardbuilder init , title("State explorer") tx2036 selector(state) refvalue("United States")

. dashboardbuilder tab , name(today) label("Where states stand")

. dashboardbuilder panel kpi , values(pop medage) title("Headline numbers")

. dashboardbuilder build using "states.html", replace pdf sourcenote("Source: 1980 census extract.")

3. Feeding analytic subsets: reload/reshape between panel calls;
each panel embeds its own snapshot:

. sysuse uslifeexp, clear

. dashboardbuilder init , title("US life expectancy, 1900-1999")

. dashboardbuilder panel line , x(year) y(le_male le_female) title("The gap")

. keep if year >= 1950

. dashboardbuilder panel line , x(year) y(le_wm le_bm) title("White vs Black men, postwar")

. dashboardbuilder build using "lifeexp.html", replace

4. Embed a map (or any HTML): build a self-contained HTML with another
tool, then inline it as an html panel:

. * a sparkta2 choropleth, exported OFFLINE so it is self-contained

. sparkta2 readiness, id(fips) geo(texas) type(choropleth) offline noopen export("map.html")

. use county_data, clear

. dashboardbuilder init , title("County explorer") tx2036

. dashboardbuilder panel html , file("map.html") height(760) title("Readiness by county")

. dashboardbuilder panel kpi , values(readiness) title("Statewide average")

. dashboardbuilder build using "county.html", replace

A fuller worked script ships with the package:
example_dashboardbuilder.do. It builds four dashboards that exercise every
panel type and most options, and each maps onto a common use case:

auto_quick two-minute minimal look at a collapsed table (example 1
above); a bar chart plus a data table, default theme.

state_explorer the "choose a unit vs. a reference" pattern (example
2 above): a state selector, a synthetic United States reference row, tabs, KPI
tiles, compare bullet bars, a static ranking, PDF buttons, callout and source.

lifeexp a time series told across tabs, feeding a restricted subset
between panel calls (example 3 above).

nhanes_bp an optional health-survey example (needs internet once for
webuse); collapsing microdata to group means before charting.

A second script, example_dashboardbuilder_map.do, is the extended
example behind 4 above: it builds a sparkta2 Texas county choropleth and
embeds it in a dashboard via panel html (needs sparkta2 installed).

Stored results

dashboardbuilder build stores in r():

r(file) absolute path of the HTML file

r(ntabs) number of tabs

r(npanels) number of panels

r(bytes) file size in bytes

Remarks

What the receipt's TODO list watches for: untitled panels; Stata-date
x variables (convert to year or a labeled string first); panels embedding more
than 2,000 rows (collapse first); tables over 500 rows; KPI cards with more
than 6 tiles; bar charts with more than 25 categories; a selector with static
panels; missing sourcenote(); no interp() anywhere.

Data stay local: everything is embedded in the file you write; nothing is
uploaded anywhere. Anyone you send the file to can read the data out of it, so
share it as you would share the underlying data.

Author

Eric Booth, Texas 2036 Data & Research.

Contact: eric.booth@texas2036.org
or eric.a.booth@gmail.com.

Inspired by the hand-built "Texas County Explorer" prototype; this tool
generalizes that layout into a reusable wireframe generator.