import%20marimo%0A%0A__generated_with%20%3D%20%220.23.9%22%0Aapp%20%3D%20marimo.App(width%3D%22medium%22)%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20marimo%20as%20mo%0A%0A%20%20%20%20return%20(mo%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%20Spillover-aware%20DiD%3A%20the%20design%20way%20(Butts%202024)%0A%0A%20%20%20%20%3E%20%E2%9A%A0%EF%B8%8F%20**Teaching%20example%2C%20not%20a%20real%20causal%20study.**%20This%20notebook%20is%20a%20**simplified%2C%20illustrative**%20walk-through%20of%20spatial%20and%20causal%20methods.%20The%20numbers%20are%20**not**%20validated%20findings%20about%20livestock%20and%20ammonia%20and%20should%20not%20be%20cited%3B%20read%20every%20estimate%20as%20a%20demonstration%20of%20how%20a%20method%20behaves%20(and%20where%20it%20breaks).%0A%0A%20%20%20%20NH%E2%82%83%20**drifts**%2C%20so%20a%20control%20cell%20next%20to%20a%20treated%20cell%20is%20*partly%20treated*%2C%20which%0A%20%20%20%20biases%20a%20plain%20difference-in-differences%20(DiD).%20With%20positive%20drift%2C%20as%20here%2C%20the%20bias%20is%0A%20%20%20%20**toward%20zero**%3B%20in%20general%20the%20bias%20follows%20the%20spillover's%20sign%20(Butts%202024).%0A%0A%20%20%20%20The%20main%20practical%20**modelled**%20the%20spillover%20(a%20spatial-lag%20%2F%20SAR%20model).%20Here%20we%20use%20the%0A%20%20%20%20**design**%20alternative%20from%20Butts%20(2024)%2C%20*Difference-in-Differences%20with%20Spatial%20Spillovers*%3A%0A%0A%20%20%20%201.%20measure%20the%20counterfactual%20trend%20from%20**far-away%20controls**%20only%20(the%20drift%20can't%20reach%20them)%3B%0A%20%20%20%202.%20measure%20the%20spillover%20directly%20with%20**distance%20rings**%20(0%E2%80%932%20km%2C%202%E2%80%934%20km%2C%204%E2%80%936%20km%20from%20a%20treated%20cell).%0A%0A%20%20%20%20*(Our%20data%20only%20have%20net%20farm%20changes%202020%20%E2%86%92%202024%2C%20so%20this%20is%20a%20simple%20two-period%20version.)*%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20%23%20%E2%94%80%E2%94%80%20Setup%3A%20libraries%20%2B%20data%20%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%0A%20%20%20%20import%20warnings%0A%20%20%20%20warnings.filterwarnings(%22ignore%22)%0A%20%20%20%20import%20numpy%20as%20np%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20arrays%20%2F%20maths%0A%20%20%20%20import%20pandas%20as%20pd%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20data%20tables%0A%20%20%20%20import%20matplotlib.pyplot%20as%20plt%20%20%20%20%20%20%20%20%20%23%20plots%0A%20%20%20%20import%20statsmodels.formula.api%20as%20smf%20%20%20%23%20regressions%20(OLS%2C%20DiD)%0A%20%20%20%20from%20scipy.spatial%20import%20cKDTree%20%20%20%20%20%20%20%23%20fast%20nearest-neighbour%20distances%0A%20%20%20%20from%20pathlib%20import%20Path%0A%0A%20%20%20%20pd.set_option(%22display.float_format%22%2C%20lambda%20x%3A%20f%22%7Bx%3A.3f%7D%22)%0A%20%20%20%20plt.rcParams%5B%22figure.dpi%22%5D%20%3D%20120%0A%0A%20%20%20%20grid%20%3D%20pd.read_csv(Path(%22..%2Fdata%2Ffinal%2Fworkshop_grid_1km.csv%22))%0A%20%20%20%20nh3_cols%20%3D%20%5Bf%22nh3_%7B_y%7D%22%20for%20_y%20in%20range(2018%2C%202025)%5D%0A%20%20%20%20years%20%3D%20list(range(2018%2C%202025))%0A%0A%20%20%20%20%23%20Treatment%20%3D%20a%20cell%20that%20GAINED%20more%20than%20one%20livestock%20farm%2C%202020%20-%3E%202024.%0A%20%20%20%20grid%5B%22net_gain%22%5D%20%3D%20grid%5B%22n_livestock_2024%22%5D%20-%20grid%5B%22n_livestock_2020%22%5D%0A%0A%20%20%20%20%23%20Keep%20cells%20that%20have%20livestock%20in%202024%20(like-with-like)%2C%20then%20split%3A%0A%20%20%20%20%23%20%20%20treated%20%3D%20gained%20%3E%201%20farm%20%3B%20%20control%20%3D%20no%20gain%20(net%20%3C%3D%200).%0A%20%20%20%20cells%20%3D%20grid%5Bgrid%5B%22n_livestock_2024%22%5D%20%3E%200%5D.copy()%0A%20%20%20%20cells%5B%22treated%22%5D%20%3D%20(cells%5B%22net_gain%22%5D%20%3E%201).astype(int)%0A%20%20%20%20cells%20%3D%20cells%5B(cells%5B%22net_gain%22%5D%20%3C%3D%200)%20%7C%20(cells%5B%22net_gain%22%5D%20%3E%201)%5D.copy()%0A%20%20%20%20cells%5B%22delta_nh3%22%5D%20%3D%20cells%5B%22nh3_2024%22%5D%20-%20cells%5B%22nh3_2020%22%5D%0A%0A%20%20%20%20print(f%22Treated%20cells%20(gained%20%3E%201%20farm)%3A%20%7Bint(cells%5B'treated'%5D.sum())%3A%2C%7D%22)%0A%20%20%20%20print(f%22Control%20cells%20(no%20gain)%3A%20%20%20%20%20%20%20%20%20%7Bint((cells%5B'treated'%5D%20%3D%3D%200).sum())%3A%2C%7D%22)%0A%20%20%20%20return%20cKDTree%2C%20cells%2C%20grid%2C%20nh3_cols%2C%20np%2C%20pd%2C%20plt%2C%20smf%2C%20years%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20The%20idea%20in%20one%20picture%0A%0A%20%20%20%20**Plain%20DiD**%20%3D%20(change%20in%20treated%20cells)%20%E2%88%92%20(change%20in%20control%20cells).%20The%20control%0A%20%20%20%20change%20is%20our%20guess%20for%20what%20treated%20cells%20*would*%20have%20done%20without%20the%20farms.%0A%0A%20%20%20%20If%20NH%E2%82%83%20**drifts**%20onto%20nearby%20controls%2C%20their%20change%20is%20inflated%20by%20the%20treatment%2C%20so%0A%20%20%20%20the%20plain%20DiD%20is%20**biased%20toward%20zero**.%0A%0A%20%20%20%20**Butts's%20fix%3A**%0A%0A%20%20%20%20-%20build%20the%20control%20trend%20from%20**far-away%20controls**%20(%3E%206%20km%20from%20any%20treated%20cell)%2C%20the%20drift%20can't%20reach%20them%3B%0A%20%20%20%20-%20estimate%20the%20leftover%20spillover%20on%20**nearby**%20controls%20with%20**distance%20rings**.%0A%0A%20%20%20%20**Credible%20only%20if%3A**%20treated%20and%20far%20controls%20were%20on%20**parallel%20trends**%20(we%20eyeball%0A%20%20%20%20this%20below)%2C%20and%20spillovers%20are%20**local**%2C%20essentially%20gone%20beyond%20~6%20km.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(cKDTree%2C%20cells%2C%20np)%3A%0A%20%20%20%20%23%20%E2%94%80%E2%94%80%20Distance%20to%20the%20nearest%20treated%20cell%2C%20then%20exposure%20groups%20%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%0A%20%20%20%20%23%20Build%20an%20enriched%20copy%20so%20downstream%20cells%20depend%20on%20it%20explicitly.%0A%20%20%20%20cells_ring%20%3D%20cells.copy()%0A%20%20%20%20_treated_xy%20%3D%20cells_ring.loc%5Bcells_ring%5B%22treated%22%5D%20%3D%3D%201%2C%20%5B%22x_rd%22%2C%20%22y_rd%22%5D%5D.to_numpy()%0A%20%20%20%20_control%20%3D%20cells_ring%5B%22treated%22%5D%20%3D%3D%200%0A%20%20%20%20cells_ring%5B%22dist_km%22%5D%20%3D%20np.nan%0A%20%20%20%20cells_ring.loc%5B_control%2C%20%22dist_km%22%5D%20%3D%20cKDTree(_treated_xy).query(%0A%20%20%20%20%20%20%20%20cells_ring.loc%5B_control%2C%20%5B%22x_rd%22%2C%20%22y_rd%22%5D%5D.to_numpy())%5B0%5D%20%2F%201000%20%20%20%23%20metres%20-%3E%20km%0A%0A%20%20%20%20%23%20Three%20groups%3A%20treated%20%2F%20nearby%20control%20(%3C%3D6%20km)%20%2F%20far%20control%20(%3E6%20km).%0A%20%20%20%20cells_ring%5B%22group%22%5D%20%3D%20%22far%20control%20(%3E6%20km)%22%0A%20%20%20%20cells_ring.loc%5Bcells_ring%5B%22treated%22%5D%20%3D%3D%201%2C%20%22group%22%5D%20%3D%20%22treated%22%0A%20%20%20%20cells_ring.loc%5B_control%20%26%20(cells_ring%5B%22dist_km%22%5D%20%3C%3D%206)%2C%20%22group%22%5D%20%3D%20%22nearby%20control%20(%3C%3D6%20km)%22%0A%0A%20%20%20%20%23%20Distance%20rings%20among%20the%20controls%20(used%20by%20the%20spillover%20regression%20later).%0A%20%20%20%20cells_ring%5B%22ring_0_2km%22%5D%20%3D%20(_control%20%26%20(cells_ring%5B%22dist_km%22%5D%20%3C%3D%202)).astype(int)%0A%20%20%20%20cells_ring%5B%22ring_2_4km%22%5D%20%3D%20(_control%20%26%20cells_ring%5B%22dist_km%22%5D.between(2%2C%204%2C%20inclusive%3D%22right%22)).astype(int)%0A%20%20%20%20cells_ring%5B%22ring_4_6km%22%5D%20%3D%20(_control%20%26%20cells_ring%5B%22dist_km%22%5D.between(4%2C%206%2C%20inclusive%3D%22right%22)).astype(int)%0A%0A%20%20%20%20cells_ring.groupby(%22group%22)%5B%22delta_nh3%22%5D.agg(n_cells%3D%22size%22%2C%20mean_change%3D%22mean%22).round(3)%0A%20%20%20%20return%20(cells_ring%2C)%0A%0A%0A%40app.cell%0Adef%20_(cells_ring%2C%20grid%2C%20nh3_cols%2C%20plt%2C%20years)%3A%0A%20%20%20%20%23%20%E2%94%80%E2%94%80%20Where%20each%20group%20is%2C%20and%20how%20NH3%20moved%20over%20time%20%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%0A%20%20%20%20_colors%20%3D%20%7B%22treated%22%3A%20%22%23d95f0e%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22nearby%20control%20(%3C%3D6%20km)%22%3A%20%22%23756bb1%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22far%20control%20(%3E6%20km)%22%3A%20%22%232b8cbe%22%7D%0A%20%20%20%20_order%20%3D%20%5B%22treated%22%2C%20%22nearby%20control%20(%3C%3D6%20km)%22%2C%20%22far%20control%20(%3E6%20km)%22%5D%0A%0A%20%20%20%20_fig%2C%20(_ax_map%2C%20_ax_trend)%20%3D%20plt.subplots(1%2C%202%2C%20figsize%3D(14%2C%206))%0A%0A%20%20%20%20_ax_map.scatter(grid%5B%22x_rd%22%5D%2C%20grid%5B%22y_rd%22%5D%2C%20c%3D%22lightgrey%22%2C%20s%3D0.25%2C%20alpha%3D0.4%2C%20zorder%3D1)%0A%20%20%20%20%23%20Draw%20treated%20LAST%20%2F%20on%20top%20(zorder)%20and%20larger%2C%20otherwise%20the%20far%20controls%0A%20%20%20%20%23%20(by%20far%20the%20most%20numerous)%20paint%20over%20the%20handful%20of%20treated%20cells.%0A%20%20%20%20_zorder%20%3D%20%7B%22treated%22%3A%205%2C%20%22nearby%20control%20(%3C%3D6%20km)%22%3A%203%2C%20%22far%20control%20(%3E6%20km)%22%3A%202%7D%0A%20%20%20%20for%20_g%20in%20_order%3A%0A%20%20%20%20%20%20%20%20_sub%20%3D%20cells_ring%5Bcells_ring%5B%22group%22%5D%20%3D%3D%20_g%5D%0A%20%20%20%20%20%20%20%20_ax_map.scatter(_sub%5B%22x_rd%22%5D%2C%20_sub%5B%22y_rd%22%5D%2C%20c%3D_colors%5B_g%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20s%3D16%20if%20_g%20%3D%3D%20%22treated%22%20else%203%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20alpha%3D0.95%20if%20_g%20%3D%3D%20%22treated%22%20else%200.55%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20edgecolors%3D%22black%22%20if%20_g%20%3D%3D%20%22treated%22%20else%20%22none%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20linewidths%3D0.3%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20zorder%3D_zorder%5B_g%5D%2C%20label%3Df%22%7B_g%7D%20(%7Blen(_sub)%3A%2C%7D)%22)%0A%20%20%20%20_ax_map.set_title(%22Exposure%20groups%22)%0A%20%20%20%20_ax_map.set_aspect(%22equal%22)%0A%20%20%20%20_ax_map.set_axis_off()%0A%20%20%20%20_ax_map.legend(markerscale%3D2.5%2C%20fontsize%3D9%2C%20loc%3D%22lower%20left%22)%0A%0A%20%20%20%20_group_means%20%3D%20cells_ring.groupby(%22group%22)%5Bnh3_cols%5D.mean()%0A%20%20%20%20for%20_g%20in%20_order%3A%0A%20%20%20%20%20%20%20%20_ax_trend.plot(years%2C%20_group_means.loc%5B_g%5D%2C%20marker%3D%22o%22%2C%20lw%3D2%2C%20color%3D_colors%5B_g%5D%2C%20label%3D_g)%0A%20%20%20%20_ax_trend.axvline(2020.5%2C%20color%3D%22black%22%2C%20ls%3D%22--%22%2C%20lw%3D1.2%2C%20label%3D%22treatment%20window%22)%0A%20%20%20%20_ax_trend.set_title(%22Mean%20NH3%20over%20time%22)%0A%20%20%20%20_ax_trend.set_xlabel(%22year%22)%0A%20%20%20%20_ax_trend.set_ylabel(%22NH3%20(ug%2Fm3)%22)%0A%20%20%20%20_ax_trend.legend(fontsize%3D9)%0A%20%20%20%20_fig.tight_layout()%0A%20%20%20%20_fig%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(cells_ring%2C%20nh3_cols%2C%20pd%2C%20smf)%3A%0A%20%20%20%20%23%20%E2%94%80%E2%94%80%20Standard%20DiD%20(all%20controls)%20%20vs%20%20Butts%20DiD%20(far%20controls%20only)%20%E2%94%80%E2%94%80%0A%20%20%20%20_panel%20%3D%20cells_ring.melt(id_vars%3D%5B%22grid_row%22%2C%20%22grid_col%22%2C%20%22treated%22%2C%20%22group%22%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20value_vars%3Dnh3_cols%2C%20var_name%3D%22year%22%2C%20value_name%3D%22nh3%22)%0A%20%20%20%20_panel%5B%22year%22%5D%20%3D%20_panel%5B%22year%22%5D.str.replace(%22nh3_%22%2C%20%22%22%2C%20regex%3DFalse).astype(int)%0A%20%20%20%20_panel%5B%22post%22%5D%20%3D%20(_panel%5B%22year%22%5D%20%3D%3D%202024).astype(int)%0A%20%20%20%20_panel%5B%22cell_id%22%5D%20%3D%20_panel%5B%22grid_row%22%5D.astype(str)%20%2B%20%22_%22%20%2B%20_panel%5B%22grid_col%22%5D.astype(str)%0A%0A%20%20%20%20def%20_did(data)%3A%0A%20%20%20%20%20%20%20%20%22%22%22DiD%20%3D%20the%20'treated%3Apost'%20coefficient%20(2020%20vs%202024)%2C%20cluster-robust%20by%20cell.%22%22%22%0A%20%20%20%20%20%20%20%20_two%20%3D%20data%5Bdata%5B%22year%22%5D.isin(%5B2020%2C%202024%5D)%5D%0A%20%20%20%20%20%20%20%20_m%20%3D%20smf.ols(%22nh3%20~%20treated%20*%20post%22%2C%20data%3D_two).fit(%0A%20%20%20%20%20%20%20%20%20%20%20%20cov_type%3D%22cluster%22%2C%20cov_kwds%3D%7B%22groups%22%3A%20_two%5B%22cell_id%22%5D%7D)%0A%20%20%20%20%20%20%20%20return%20_m.params%5B%22treated%3Apost%22%5D%2C%20_m.pvalues%5B%22treated%3Apost%22%5D%0A%0A%20%20%20%20_far_only%20%3D%20_panel%5B(_panel%5B%22treated%22%5D%20%3D%3D%201)%20%7C%20(_panel%5B%22group%22%5D%20%3D%3D%20%22far%20control%20(%3E6%20km)%22)%5D%0A%20%20%20%20_est_all%2C%20_p_all%20%3D%20_did(_panel)%0A%20%20%20%20_est_far%2C%20_p_far%20%3D%20_did(_far_only)%0A%0A%20%20%20%20print(f%22Using%20only%20far%20controls%20changes%20the%20estimate%20by%20%7B_est_far%20-%20_est_all%3A%2B.2f%7D%20ug%2Fm3.%22)%0A%20%20%20%20print(%22-%3E%20the%20own-cell%20effect%20is%20about%200.5%20ug%2Fm3%20either%20way%3A%20contamination%20is%20small.%22)%0A%20%20%20%20pd.DataFrame(%0A%20%20%20%20%20%20%20%20%7B%22DiD%20estimate%22%3A%20%5B_est_all%2C%20_est_far%5D%2C%20%22p-value%22%3A%20%5B_p_all%2C%20_p_far%5D%7D%2C%0A%20%20%20%20%20%20%20%20index%3D%5B%22standard%20(all%20controls)%22%2C%20%22Butts%20(far%20controls)%22%5D).round(3)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(cells_ring%2C%20mo%2C%20pd%2C%20plt%2C%20smf)%3A%0A%20%20%20%20%23%20%E2%94%80%E2%94%80%20How%20big%20is%20the%20spillover%20at%20each%20distance%3F%20(ring%20regression)%20%E2%94%80%E2%94%80%E2%94%80%E2%94%80%0A%20%20%20%20%23%20Regress%20the%20NH3%20change%20on%3A%20treated%2C%20and%20the%20three%20control%20rings.%0A%20%20%20%20%23%20Far%20controls%20(%3E6%20km)%20are%20the%20baseline%2C%20so%20each%20coefficient%20reads%20%22vs%20far%20controls%22.%0A%20%20%20%20_ring_model%20%3D%20smf.ols(%0A%20%20%20%20%20%20%20%20%22delta_nh3%20~%20treated%20%2B%20ring_0_2km%20%2B%20ring_2_4km%20%2B%20ring_4_6km%22%2C%20data%3Dcells_ring%0A%20%20%20%20).fit(cov_type%3D%22HC3%22)%0A%0A%20%20%20%20_terms%20%3D%20%5B%22treated%22%2C%20%22ring_0_2km%22%2C%20%22ring_2_4km%22%2C%20%22ring_4_6km%22%5D%0A%20%20%20%20_labels%20%3D%20%5B%22treated%5Cn(own%20cell)%22%2C%20%22control%5Cn0-2%20km%22%2C%20%22control%5Cn2-4%20km%22%2C%20%22control%5Cn4-6%20km%22%5D%0A%0A%20%20%20%20_fig%2C%20_ax%20%3D%20plt.subplots(figsize%3D(8%2C%204.5))%0A%20%20%20%20_ax.axhline(0%2C%20color%3D%22black%22%2C%20lw%3D1)%0A%20%20%20%20_ax.errorbar(range(4)%2C%20_ring_model.params%5B_terms%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20yerr%3D1.96%20*%20_ring_model.bse%5B_terms%5D%2C%20fmt%3D%22o%22%2C%20ms%3D9%2C%20capsize%3D5%2C%20color%3D%22%232b8cbe%22)%0A%20%20%20%20_ax.set_xticks(range(4))%0A%20%20%20%20_ax.set_xticklabels(_labels)%0A%20%20%20%20_ax.set_ylabel(%22effect%20on%20NH3%20change%20(ug%2Fm3)%5Cnvs%20far%20controls%22)%0A%20%20%20%20_ax.set_title(%22Own%20effect%20%2B%20spillover%20by%20distance%22)%0A%20%20%20%20_fig.tight_layout()%0A%0A%20%20%20%20print(%22Own%20effect%20~0.5%3B%20the%20spillover%20onto%20controls%20decays%20with%20distance%22)%0A%20%20%20%20print(%22(0-2%20km%20clearly%20positive%2C%20gone%20by%204-6%20km)%20-%3E%20spillovers%20are%20real%20but%20LOCAL.%22)%0A%20%20%20%20mo.vstack(%5B%0A%20%20%20%20%20%20%20%20mo.md(%22**Own%20effect%20%2B%20spillover%20by%20distance%20ring**%20(baseline%20%3D%20far%20controls%20%3E%206%20km)%3A%22)%2C%0A%20%20%20%20%20%20%20%20pd.DataFrame(%7B%22effect%22%3A%20_ring_model.params%5B_terms%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22p-value%22%3A%20_ring_model.pvalues%5B_terms%5D%7D).round(3)%2C%0A%20%20%20%20%20%20%20%20_fig%2C%0A%20%20%20%20%5D)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%3E%20%23%23%23%23%20%F0%9F%94%A7%20Your%20turn%0A%20%20%20%20%3E%0A%20%20%20%20%3E%201.%20**Read%20the%20rings%20(no%20code%20change).**%20At%20what%20distance%20does%20the%20control%20spillover%0A%20%20%20%20%3E%20%20%20%20become%20indistinguishable%20from%200%3F%20That%20distance%20is%20the%20buffer%20your%20design%20is%0A%20%20%20%20%3E%20%20%20%20implicitly%20betting%20on.%0A%20%20%20%20%3E%202.%20**Move%20the%20buffer.**%20In%20the%20cell%20that%20builds%20%60group%60%2C%20change%20the%20far-control%0A%20%20%20%20%3E%20%20%20%20cutoff%20%60dist_km%20%3C%3D%206%60%20%E2%86%92%20%60%3C%3D%208%60%20(the%20label%20text%20is%20cosmetic).%20Does%20the%0A%20%20%20%20%3E%20%20%20%20far-control%20DiD%20(~0.5)%20move%3F%20Your%20answer%20to%20%22how%20local%20are%20spillovers%3F%22%20*is*%20the%0A%20%20%20%20%3E%20%20%20%20assumption%20the%20whole%20design%20rests%20on.%0A%20%20%20%20%3E%203.%20**Make%20all%20the%20models%20comparable%20by%20running%20them%20on%20the%20same%20grid%20as%20the%20main%0A%20%20%20%20%3E%20%20%20%20practical.%20Do%20the%20results%20change%3F%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Wrap-up%0A%0A%20%20%20%20**The%20five%20questions**%0A%0A%20%20%20%20%7C%20%23%20%7C%20Question%20%7C%20Answer%20%7C%0A%20%20%20%20%7C---%7C----------%7C--------%7C%0A%20%20%20%20%7C%201%20%7C%20treatment%20%7C%20a%20cell%20gained%20%3E%201%20livestock%20farm%2C%202020%20%E2%86%92%202024%20%7C%0A%20%20%20%20%7C%202%20%7C%20estimand%20%7C%20the%20effect%20on%20a%20treated%20cell's%20**own**%20NH%E2%82%83%20(%2B%20ring%20spillovers%20onto%20controls)%20%7C%0A%20%20%20%20%7C%203%20%7C%20comparison%20%7C%20treated%20vs%20**far-away**%20(%3E%206%20km)%20controls%3B%20spillover%20read%20off%20the%20rings%20%7C%0A%20%20%20%20%7C%204%20%7C%20credible%20if%20%7C%20parallel%20trends%20(treated%20vs%20far%20controls)%20**and**%20spillovers%20are%20local%20(%E2%89%A4%206%20km)%20%7C%0A%20%20%20%20%7C%205%20%7C%20fails%20when%20%7C%20the%206%20km%20cutoff%20is%20too%20short%2C%20or%20far%20controls%20differ%20systematically%20from%20treated%20cells%20%7C%0A%0A%20%20%20%20**Butts%20(design)%20vs%20SAR%20(model)**%20(on%20different%20datasets)%0A%0A%20%20%20%20%7C%20%20%7C%20SAR%20(main%20notebook)%20%7C%20Butts%20(here)%20%7C%0A%20%20%20%20%7C---%7C---%7C---%7C%0A%20%20%20%20%7C%20idea%20%7C%20*model*%20the%20spillover%20(W%2C%20%CF%81)%20%7C%20*redesign*%20the%20comparison%20(far%20controls%20%2B%20rings)%20%7C%0A%20%20%20%20%7C%20headline%20%7C%20total%20%E2%89%88%20**0.8**%20(own%200.3%20%2B%20%CF%81-feedback%20spillover)%20%7C%20own-cell%20%E2%89%88%20**0.5**%20%7C%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
984b18976f18339053d0f4a5b560e9bc