*! xtqrplot v1.3.0 02apr2026

Title

xtqrplot -- Entity-specific marginal effects from panel quantile regression

Syntax

xtqrplot depvar indepvars [if] [in],
panelvar(varname)
timevar(varname)
[options]

Required
panelvar(varname) panel (cross-section) identifier

timevar(varname) time identifier

Model
method(string) xtqreg (default) or qregpd

reps(#) bootstrap replications for qregpd; default 200

seed(#) random seed for qregpd reproducibility

nwindows(#) number of quantile windows 1-49; default 9

Effect
effect(string) coef (default), semi, elast, or bp

Plot
plottype(string) cross (default), time, or twoway

noplot suppress graphs; produce only tables

nonormal suppress pre-estimation normality tests and histograms

Output
saving(string) base filename for .gph and .dta output files

replace overwrite existing files

Description

xtqrplot estimates panel quantile regression across a grid of interior
quantile windows and produces entity-specific marginal effect plots and tables.
The command answers the economically relevant question: what is the
coefficient for a given country (or year)? -- not an average across the
distribution, but the coefficient at the quantile where that entity's
dependent variable actually sits.

xtqrplot is compatible with both balanced and unbalanced panel
data. Unbalanced panels are handled automatically through the underlying
estimators (xtqreg and qregpd); the entity-level effects and
plots are computed from whatever observations are available for each unit.

The command proceeds in five stages:

(1) Normality diagnostics. Skewness-Kurtosis (sktest),
Shapiro-Wilk (swilk), and Shapiro-Francia (sfrancia) tests
for each variable, plus histograms with kernel density overlays.
Suppress with nonormal.

(2) Quantile regression. The panel model is estimated at each quantile
window using xtqreg or qregpd. Coefficients and standard errors
are stored internally.

(3) Median summary. Results at the quantile nearest q50 are displayed
as a coefficient table with SE, z-statistic, p-value, and a replication
command to reproduce those results manually.

(4) Entity assignment. Each entity's mean (or actual, for twoway) value
of the dependent variable is ranked in the overall distribution and assigned
to the nearest quantile window. The corresponding coefficient is scaled into
the chosen effect type with 95% confidence intervals.

(5) Visualisation. Bar charts with CI error bars and secondary-axis
percentile markers (cross/time) or diverging-colour circle heat maps with
coefficient value labels (twoway) are produced, one per independent variable.

Options

Model

method(string) selects the estimator.

xtqreg (default) implements Machado & Santos Silva (2019) moments-based
quantile regression for large balanced and unbalanced panels. Requires:
ssc install xtqreg.

qregpd implements Powell (2016) with bootstrap inference, consistent
under non-additive fixed effects. Requires: ssc install qregpd.
Use reps() to control bootstrap replications and seed() for
reproducibility.

reps(#) bootstrap replications for method(qregpd). Default 200.

seed(#) sets the random seed before each qregpd estimation,
ensuring identical results across runs. Not applicable to xtqreg.

nwindows(#) number of interior quantile windows. Step = 100/(nwindows+1);
grid runs from step to nwindows*step. Default 9 gives 10,20,...,90.

nwindows Quantile grid
1 50 (median only)
3 25, 50, 75
4 20, 40, 60, 80
9 10, 20, ..., 90 (default)
19 5, 10, ..., 95

Effect

effect(string) specifies what is plotted for each entity.

coef -- raw coefficient beta at the entity's assigned window

semi -- semi-elasticity: beta x mean(X) for that entity

elast -- elasticity: beta x mean(X) / mean(Y) (requires Y > 0)

bp -- basis points: beta x 10,000 (for financial rate variables)

Plot

plottype(string) controls the visualisation dimension.

cross (default) -- horizontal bar chart, entities on y-axis, 95% CI
error bars, green circle on secondary x-axis showing exact percentile of
each entity's mean dependent variable.

time -- same layout, time periods on y-axis.

twoway -- heat map (rows=entities, cols=years) with a diverging
colour palette (blue=negative, red=positive, intensity=magnitude), coefficient
value labels, and a printed matrix table. One plot and table per independent
variable. If heatplot is installed (ssc install heatplot), a
high-quality continuous colour legend is produced. Otherwise a 10-bin scatter
fallback is used automatically.

Note on twoway plot size: The twoway heat map is best suited for
panels with a limited number of units and time periods (e.g. up to 15 countries
and 20 years). For larger panels, labels and cells become unreadable; in those
cases the printed matrix table is the more informative output.

noplot suppresses all graphs.

nonormal suppresses pre-estimation normality tests and histograms.

Output

saving(string) base filename (no extension). Saves:
basename_cross.dta, basename_cross.gph, etc.

replace overwrites existing files.

Effect types

Let beta(tau_i) be the estimated coefficient at entity i's assigned quantile.
X-bar_i and Y-bar_i are entity i's mean regressor and dependent variable.

Effect Formula Interpretation

coef beta(tau_i) Change in conditional quantile of Y per unit X
semi beta(tau_i) x X-bar_i Effect scaled by entity's X level
elast beta(tau_i) x X-bar_i / Y-bar_i Percentage change relative to Y level
bp beta(tau_i) x 10,000 Effect in basis points

All effects include 95% confidence intervals (beta +/- 1.96 x SE) shown as
error bars (cross/time plots).

Quality checks performed internally

xtqrplot performs the following quality checks automatically before
and during estimation:

(1) Option validation -- All option values are validated before
any estimation begins. Invalid values exit immediately with rc=198 and a
descriptive error message.

(2) Package availability -- The selected estimator (xtqreg or
qregpd) is confirmed to be installed before estimation starts.

(3) Panel structure -- xtset is called internally to
verify that panelvar and timevar form a valid panel structure.

(4) Sample size warning -- A warning is printed if fewer than
30 observations are in the estimation sample.

(5) Normality diagnostics -- sktest, swilk, and sfrancia are
run for every variable in the model, with histograms, before any regression
is estimated. Use nonormal to suppress.

(6) Per-quantile convergence -- Each quantile window is
estimated with capture. If any window fails, estimation stops
immediately with a detailed error message listing likely causes and
remedies.

(7) Missing effect check -- After computing entity-level
effects, the count of missing values per variable is reported so the
user can identify assignment failures.

(8) CI consistency -- Confidence interval bounds are computed
as beta +/- 1.96 x SE; missing SE values produce missing CI bounds rather
than incorrect values.

(9) File overwrite protection -- Saving without replace
when the output file already exists exits with rc=602 and a clear message,
preventing silent data overwrites.

(10) Plot failure isolation -- In twoway mode, each independent
variable's plot is wrapped in capture. A plot failure for one variable
does not prevent the others from being produced or the matrix table from
being printed.

A formal pre-submission test suite (xtqrplot_test_suite.do) covering
37 tests across 11 test blocks is available from the package repository.
Run it after installation to verify all checks pass in your Stata environment.

Output produced

xtqrplot prints three blocks to the Stata results window:

(1) Normality diagnostics -- sktest, swilk, sfrancia for every variable,
plus histograms with kernel density overlays.

(2) Median-level table -- coefficient, SE, z, p-value at the quantile
nearest q50, plus the exact command to replicate those results manually.

(3) Entity results table -- entity name, mean(Y), exact percentile,
assigned quantile window, and computed effect for each independent variable.
For twoway plots, a full country x year matrix of coefficients is also printed.

The saved dataset (if saving() is used) contains:
_my (mean Y), _mx# (mean X#), _pctrank (percentile 0-100),
_q_win (assigned window), _eff# (effect), _eff#_lo/_hi (95% CI bounds).

Examples

Setup -- simulate panel with skewed x2

. clear
. set seed 2024
. set obs 100
. gen country_id = ceil(_n/10)
. gen year = mod(_n-1,10) + 2010
. gen x1 = rnormal(2,1)
. gen u1 = runiform()
. gen u2 = runiform()
. gen x2 = -ln(u1) - ln(u2) - 2
. drop u1 u2
. gen y = 1 + 0.4*x1 + 0.3*x2 + rnormal()*(1+0.5*abs(x2))
. label define clab 1 "Argentina" 2 "Brazil" 3 "Chile" ///
4 "Colombia" 5 "Ecuador" 6 "Mexico" 7 "Panama" ///
8 "Peru" 9 "Uruguay" 10 "Venezuela"
. label values country_id clab
. xtset country_id year

Default cross-section plot

. xtqrplot y x1 x2, panelvar(country_id) timevar(year)

Twoway heat map (observe x2 variation)

. xtqrplot y x1 x2, panelvar(country_id) timevar(year) ///
plottype(twoway) nonormal

Basis points, semi-elasticity, save output

. xtqrplot y x1 x2, panelvar(country_id) timevar(year) ///
effect(bp) saving(results/out) replace nonormal

qregpd with seed for reproducibility

. xtqrplot y x1, panelvar(country_id) timevar(year) ///
method(qregpd) reps(300) seed(42) nwindows(4)

Suppress graph, extract data only

. xtqrplot y x1 x2, panelvar(country_id) timevar(year) ///
noplot nonormal saving(mydata) replace
. use mydata_cross, clear
. list country_id _pctrank _q_win _eff1 _eff2

References

Koenker, R. and Bassett, G. (1978).
Regression quantiles.
Econometrica, 46(1), 33-50.

Machado, J.A.F. and Santos Silva, J.M.C. (2019).
Quantiles via moments.
Journal of Econometrics, 213(1), 145-173.
https://doi.org/10.1016/j.jeconom.2019.04.009

Powell, D. (2016).
Quantile regression with nonadditive fixed effects.
RAND Working Paper WR-1088.
https://www.rand.org/pubs/working_papers/WR1088.html

Royston, P. (1991).
Shapiro-Francia test for normality.
Stata Technical Bulletin, 2, 16-17.

Model performance disclaimer

xtqrplot is a visualisation and post-estimation tool. Model performance
and the validity of results depend entirely on the underlying panel quantile
regression and the data provided. The following caveats apply:

Results are only meaningful when the panel quantile regression converges
successfully at each quantile window. Always inspect the quantile-by-quantile
output and verify that coefficients move sensibly across quantiles.

The quantile window assignment is a nearest-neighbour approximation. Entities
near the boundary between two windows may be assigned to either; small samples
amplify this sensitivity.

The twoway heat map interpolates spatially across an unbalanced panel, which
can produce misleading colour patterns for panels with many missing cells.

This package is under active development. If you observe any irregularity
-- unexpected output, errors not listed in the error catalogue, or results that
appear economically implausible -- please report them to the author with a
minimal reproducible example. Your feedback directly improves the package.

Contact: nouman.arshed@gmail.com

Author

Dr Noman Arshed

Senior Lecturer

Department of Business Analytics

Sunway Business School, Sunway University

Email: nouman.arshed@gmail.com

Bug reports and suggestions are welcome. Please include a reproducible
example using the simulated dataset in the Examples section above.

Also see

xtset, qreg, sktest, swilk, sfrancia,
xtqreg (if installed), qregpd (if installed),
heatplot (if installed, enhances twoway plots)

To install optional enhanced plotting packages:

ssc install heatplot

ssc install palettes

ssc install colrspace