Comparison Plots¶
Comparison plots display coefficients, fit metrics, and information criteria side by side across multiple models. PanelBox provides 4 chart types for systematic model comparison.
Quick Start¶
from panelbox.visualization import create_comparison_charts
charts = create_comparison_charts(
[pooled_results, fe_results, re_results],
names=["Pooled OLS", "Fixed Effects", "Random Effects"],
theme="professional",
)
# Access individual charts
charts["coefficients"].to_html()
charts["fit_comparison"].save_image("fit.png")
By default, create_comparison_charts() generates coefficients, fit_comparison, and ic_comparison. Select specific charts:
charts = create_comparison_charts(
results_list,
names=model_names,
charts=["coefficients", "forest_plot", "fit_comparison", "ic_comparison"],
)
Note
The forest_plot is designed for a single model's coefficients. When passing multiple models, it is skipped with a warning.
Coefficient Comparison¶
Registry name: comparison_coefficients
Grouped bar chart comparing coefficient estimates across models with standard error bars. A horizontal reference line at zero helps identify sign changes.
from panelbox.visualization import ChartFactory
chart = ChartFactory.create(
"comparison_coefficients",
data={
"models": ["Pooled OLS", "Fixed Effects", "Random Effects"],
"coefficients": {
"hours": [0.15, 0.12, 0.14],
"education": [0.08, None, 0.07], # FE drops time-invariant
"experience": [0.03, 0.02, 0.025],
},
"std_errors": { # Optional
"hours": [0.02, 0.03, 0.025],
"education": [0.01, None, 0.012],
"experience": [0.005, 0.006, 0.005],
},
"ci_level": 0.95,
},
theme="professional",
)
Interpretation:
- Similar coefficients across models: robust finding
- Sign changes: specification sensitivity, investigate further
- FE estimate differs from RE: Hausman test likely rejects, endogeneity present
- Wider error bars: less precise estimate, possibly fewer observations
Forest Plot¶
Registry name: comparison_forest_plot
Publication-ready forest plot showing coefficient point estimates with horizontal confidence intervals. Colors indicate statistical significance.
chart = ChartFactory.create(
"comparison_forest_plot",
data={
"variables": ["hours", "education", "experience", "tenure"],
"estimates": [0.12, 0.08, 0.025, 0.015],
"ci_lower": [0.06, 0.05, 0.010, -0.002],
"ci_upper": [0.18, 0.11, 0.040, 0.032],
"pvalues": [0.001, 0.003, 0.02, 0.08], # Optional
"sort_by_size": True, # Optional
},
theme="academic",
)
Color coding by significance:
- Dark green: p < 0.001 (highly significant)
- Green: p < 0.01
- Orange: p < 0.05
- Gray: p >= 0.05 (not significant)
A vertical reference line at zero identifies which coefficients are statistically different from zero (CIs not crossing zero).
Interpretation:
- CI not crossing zero: statistically significant at the chosen level
- Narrow CI: precise estimate
- Wide CI: imprecise, consider more data or different specification
- Ordering by magnitude highlights the most important predictors
Model Fit Comparison¶
Registry name: comparison_model_fit
Grouped bar chart comparing goodness-of-fit statistics across models.
chart = ChartFactory.create(
"comparison_model_fit",
data={
"models": ["Pooled OLS", "Fixed Effects", "Random Effects"],
"metrics": {
"R-squared": [0.25, 0.72, 0.65],
"Adj. R-squared": [0.24, 0.68, 0.64],
"F-statistic": [45.2, 120.5, 98.3],
},
"normalize": False, # Optional: normalize metrics for comparison
},
theme="professional",
)
Interpretation:
- Higher R-squared in FE: entity effects capture substantial variation
- Large gap between R-squared and adjusted R-squared: possible overfitting
- Higher F-statistic: stronger overall model significance
- When comparing FE and RE, also consider the Hausman test (not just fit metrics)
Information Criteria Chart¶
Registry name: comparison_ic
Grouped bar chart of AIC and BIC values across models. The model with the lowest IC value receives a gold border highlight. Shows delta values (\(\Delta\)) from the best model.
chart = ChartFactory.create(
"comparison_ic",
data={
"models": ["Pooled OLS", "Fixed Effects", "Random Effects"],
"aic": [1250.3, 980.5, 1015.2],
"bic": [1265.8, 1050.1, 1035.7],
"hqic": [1255.0, 1005.2, 1020.3], # Optional: Hannan-Quinn IC
"show_delta": True, # Show delta from best model
},
theme="academic",
)
Interpretation:
- Lower AIC/BIC: better model (penalizes complexity)
- \(\Delta\)AIC < 2: models are essentially equivalent
- \(\Delta\)AIC 2--7: considerably less support for the higher-AIC model
- \(\Delta\)AIC > 10: virtually no support for the higher-AIC model
- AIC and BIC disagree: BIC penalizes complexity more, prefer BIC for large \(N\)
Data Transformers¶
The ComparisonDataTransformer extracts comparison data from model results objects:
from panelbox.visualization.transformers.comparison import ComparisonDataTransformer
transformer = ComparisonDataTransformer()
# Full transformation
data = transformer.transform(
[pooled_results, fe_results, re_results],
names=["Pooled", "FE", "RE"],
)
# Returns dict with: 'models', 'coefficients', 'std_errors',
# 'pvalues', 'fit_metrics', 'ic_values'
Complete Example¶
Compare three estimators for a wage equation:
import panelbox as pb
from panelbox.visualization import create_comparison_charts, export_charts
# Estimate three models
pooled = pb.PooledOLS(data=data, formula="lwage ~ hours + exper + tenure").fit()
fe = pb.FixedEffects(data=data, formula="lwage ~ hours + exper + tenure + EntityEffects").fit()
re = pb.RandomEffects(data=data, formula="lwage ~ hours + exper + tenure").fit()
# Create all comparison charts
charts = create_comparison_charts(
[pooled, fe, re],
names=["Pooled OLS", "Fixed Effects", "Random Effects"],
theme="professional",
)
# Forest plot for the preferred model
from panelbox.visualization import ChartFactory
forest = ChartFactory.create(
"comparison_forest_plot",
data={
"variables": list(fe.params.index),
"estimates": list(fe.params.values),
"ci_lower": list(fe.conf_int().iloc[:, 0]),
"ci_upper": list(fe.conf_int().iloc[:, 1]),
"pvalues": list(fe.pvalues),
},
theme="academic",
)
# Export all
export_charts(charts, output_dir="./comparison", format="svg", prefix="model_")
forest.save_image("comparison/forest_plot.svg")
Comparison with Other Software¶
| Chart | PanelBox | Stata | R |
|---|---|---|---|
| Coefficient comparison | comparison_coefficients |
estimates table |
modelsummary::modelplot() |
| Forest plot | comparison_forest_plot |
coefplot |
coefplot, forestplot |
| Model fit | comparison_model_fit |
estimates stats |
modelsummary() |
| Information criteria | comparison_ic |
estimates stats |
AIC(), BIC() |
See Also¶
- Diagnostics Plots -- Residual diagnostics for individual models
- Test Plots -- Validation test comparison heatmap
- Panel Plots -- Entity and time effects from individual models
- Themes & Customization -- Style your comparison charts