knitr::opts_chunk$set(collapse = TRUE, comment = "#>") ragg_png = function(..., res = 192) { ragg::agg_png(..., res = res, units = "in") } knitr::opts_chunk$set(dev = "ragg_png", fig.ext = "png")
library(synthdid) library(ggplot2) set.seed(12345)
We estimate the effect of California Proposition 99 on cigarette consumption
We have only one treated unit (California), so the only implemented method to estimate the standard error is the 'placebo' method described in Section 5 of Arkhangelsky et al. Because this is not trustworthy, it is not used by default: vcov instead returns NA. Here it is probably too large.
But to show how confidence intervals are constructed and displayed, we'll use it anyway. To do this, we pass method='placebo' to vcov and pass se.method='placebo' to our plotting functions so they do the same. If we didn't, the plots wouldn't show have standard errors.
data('california_prop99') setup = panel.matrices(california_prop99) tau.hat = synthdid_estimate(setup$Y, setup$N0, setup$T0) tau.hat print(summary(tau.hat)) se = sqrt(vcov(tau.hat, method='placebo')) sprintf('point estimate: %1.2f', tau.hat) sprintf('95%% CI (%1.2f, %1.2f)', tau.hat - 1.96 * se, tau.hat + 1.96 * se)
We show the trajectories of California and the synthetic control we compare it to, with a vertical line indicating onset of treatment. The relative size of the weights $\lambda_t$ for pre-treatment periods are shown on the bottom. Overlaid is a diagram of the estimate.
The blue segment shows the change from the weighted pre-treatment average to the post-treatment average California. The red one does the same for a synthetic control.
Our premise is that, absent treatment, California would change like the synthetic control: from California's pre-treatment average, we draw a dashed segment parallel to the control's red one. Where it ends is our estimate of what we'd have observed in California had, contrary to fact, it not been treated.
Comparing this counterfactual estimate to what we observed in the real world, we get a treatment effect. We show it with a black arrow. We show a 95% confidence interval with two gray arrows: one for the upper confidence bound and one for the lower.
plot(tau.hat, se.method='placebo')
We could draw the plot above, and get a questionable treatment effect estimate, by comparison to any individual control state. Our actual estimate is a weighted average of these: the weights are the synthetic control weights $\omega_i$. This plot shows each individual comparison with a dot, with weight $\omega_i$ determining the dot size. The black horizontal line shows the actual effect; the gray ones show the endpoints of a 95% confidence interval.
synthdid_units_plot(tau.hat, se.method='placebo')
When the synthetic control and treated trajectories are far from one another, it can be hard to see how parallel they are. Pass overlay=1 to plot to overlay them.
plot(tau.hat, overlay=1, se.method='placebo')
Pass values between zero and one to shift the control's trajectory toward California.
plot(tau.hat, overlay=.8, se.method='placebo')
We compare to synthetic control and diff-in-diff.
tau.sc = sc_estimate(setup$Y, setup$N0, setup$T0) tau.did = did_estimate(setup$Y, setup$N0, setup$T0) estimates = list(tau.did, tau.sc, tau.hat) names(estimates) = c('Diff-in-Diff', 'Synthetic Control', 'Synthetic Diff-in-Diff')
print(unlist(estimates))
synthdid_plot(estimates, se.method='placebo')
synthdid_units_plot(estimates, se.method='placebo')
Arguments to plotting functions can change the transparency, line thickness, etc. of individual elements. The output of every plotting function is a ggplot, so you can change theme, legend position, etc. as usual. We'll use these to match the style of Figure 1 in Arkhangelsky et al.
synthdid_plot(estimates, facet.vertical=FALSE, control.name='control', treated.name='california', lambda.comparable=TRUE, se.method = 'none', trajectory.linetype = 1, line.width=.75, effect.curvature=-.4, trajectory.alpha=.7, effect.alpha=.7, diagram.alpha=1, onset.alpha=.7) + theme(legend.position=c(.26,.07), legend.direction='horizontal', legend.key=element_blank(), legend.background=element_blank(), strip.background=element_blank(), strip.text.x = element_blank()) synthdid_units_plot(estimates, se.method='none') + theme(legend.background=element_blank(), legend.title = element_blank(), legend.direction='horizontal', legend.position=c(.17,.07), strip.background=element_blank(), strip.text.x = element_blank())
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.