* Author: Martin Eckhoff Andresen * This program is part of the mtefe package. cap program drop mtefeplot { program define mtefeplot version 13.0 syntax [namelist], [ /* */ normalci /* */ cropfigure(numlist) /* */ folder(string) /* */ names(string) /* */ graph_opts(string) /* */ legendtitle(string) /* */ level(integer 95) /* */ late /* */ att /* */ atut /* */ prte /* */ mprte1 /* */ mprte2 /* */ mprte3 /* */ SEParate /* */ MEMory /* */ TRIMSupport(numlist ascending min=2 max=2) /* */ points /* */ ] qui { if "`points'"=="" { loc plottype line loc cmissing cmissing(n) } else { loc plottype scatter loc cmissing msymbol(circle_hollow) } local numEsts: word count `namelist' if "`memory'"!="" loc use restore else loc use use if "`folder'"!="" loc folder `folder'/ if `numEsts'==0 { loc namelist base loc numEsts=1 } if "`separate'"!=""{ cap confirm matrix e(support1) if _rc!=0 { noi di in red "No potential outcomes found. These are not estimated with Local IV." exit } } if "`trimsupport'"!="" { tokenize `trimsupport' loc trimlow `1' loc trimhigh=`2' } if ("`prte'"!=""|"`late'"!=""|"`atut'"!=""|"`att'"!="")&`numEsts'>1 { di in red "Do not specify more than one MTE estimate when plotting weights." exit 301 } if strpos("`graph_opts'","ytitle")==0 loc graph_opts ytitle("Treatment effect") if "`cropfigure'"!="" { numlist "`cropfigure'" local numcrop: word count `r(numlist)' if !inlist(`numcrop',0,2) { di in red "Assign only two values to cropfigure option" exit 301 } loc counter=0 foreach value in `cropfigure' { loc counter=`counter'+1 loc crop`counter'=`value' } } preserve clear //Plot 1: Main MTE plot with ATE and ci bands OR Potential outcomes and MTE plots if `numEsts'==1&"`prte'"==""&"`late'"==""&"`atut'"==""&"`att'"=="" { if "`namelist'"!="base" estimates `use' `folder'`namelist' if "`e(cmd)'"!="mtefe" { if "`namelist'"=="base" di in red "Estimates in memory is not created by mtefe." else di in red "Stored estimates `namelist' estimate is not created by mtefe." exit 301 } tempname sup mte V mat `mte'=e(mte)' svmat `mte' mat `sup'= e(support) svmat `sup' loc min=`sup'[1,1] loc max=`sup'[rowsof(`sup'),1] loc cols=0 cap confirm matrix e(V) if _rc==0 { mat `V'=e(V) mat `V'=`V'["mte:","mte:"] if "`separate'"=="" { capture confirm scalar e(level) if _rc!=0 { qui ereturn display, level(`level') tempname r confint mat `r'=r(table) mat `confint'=`r'[rownumb(`r',"ll")..rownumb(`r',"ul"),colnumb(`r',"u`=`min'*100'")..colnumb(`r',"u`=`max'*100'")] mat `confint'=`confint'' loc conflevel=r(level) } else { noi di _rc tempname confint loc conflevel=e(level) if "`normalci'"!="" mat `confint'=e(ci_normal)' else mat `confint'=e(ci_percentile)' mat `confint'=`confint'[rownumb(`confint',"u`=`min'*100'")..rownumb(`confint',"u`=`max'*100'"),1..2] } svmat `confint' if "`cropfigure'"!="" { replace `confint'1=`crop1' if `confint'1<`crop1' replace `confint'2=`crop2' if `confint'2>`crop2' } loc twoway (rarea `confint'1 `confint'2 `sup'1, `cmissing' color(gs13)) loc labels label(1 "`conflevel'% CI") loc ++cols loc order order(2 1 3) } } loc twoway `twoway' (`plottype' `mte' `sup'1, lpattern(solid) `cmissing') loc ++cols loc labels `labels' label(`cols' "MTE") loc ++cols loc labels `labels' label(`=`cols'' "ATE") loc twoway `twoway' (function y=_b[effects:ate], range(`min' `max') lcolor(maroon) lpattern(dash)) if "`separate'"!="" { tempname Y1 Y0 support1 support0 tempfile plotdata forvalues i=0/1 { save `plotdata', replace clear mat `Y`i''=e(Y`i') svmat `Y`i'', names(`Y`i'') mat `support`i''=e(support`i') svmat `support`i'', names(`sup') merge 1:1 `sup'1 using `plotdata', nogen save `plotdata', replace loc ++cols loc labels `labels' label(`cols' "Y`i'") } loc twoway `twoway' (`plottype' `Y0'1 `Y1'1 `sup'1, yaxis(2) lpattern(dash dot) `cmissing') loc ytitle2 ytitle("Potential outcomes", axis(2)) } loc labels `labels' cols(`cols') } //Plot 2: Multiple MTE plots together. No weights or ci intervals if `numEsts'>1 { if "`names'"!="" { tokenize `names' local numnames: word count `names' } else loc numnames=0 loc counter=0 foreach estimate in `namelist' { loc counter=`counter'+1 if `counter'<=`numnames' loc labels `labels' label(`counter' "``counter''") else loc labels `labels' label(`counter' "`estimate'") if "`estimate'"!="base" estimates `use' `folder'`estimate' if `counter'==1 { tempname sup mainsupport mat `sup'= e(support) mat `mainsupport'=e(support)' loc rowsmain=rowsof(`sup') qui svmat `sup' } else { mat `sup'=e(support) if `rowsmain'==rowsof(`sup') loc test mreldif(`sup',`mainsupport')!=0 else loc test `rowsmain'!=rowsof(`sup') if `test' { loc merge merge tempname save save `save', replace clear qui svmat `sup' } else loc merge } tempname mte tempvar mte`estimate' mat `mte'=e(mte)' qui svmat `mte' rename `mte'1 `mte`estimate'' if "`cropfigure'"!="" { replace `mte`estimate''=. if `mte`estimate''<`crop1' replace `mte`estimate''=. if `mte`estimate''>`crop2' } if "`merge'"=="merge" { qui merge 1:1 `sup'1 using `save', nogen } loc twoway `twoway' (`plottype' `mte`estimate'' `sup'1, `cmissing') } loc labels `labels' cols(`numEsts') } //Plot 3: Treatment parameter weigths if "`prte'"!=""|"`late'"!=""|"`atut'"!=""|"`att'"!=""|"`mprte1'"!=""|"`mprte2'"!=""|"`mprte3'"!="" { local numParams: word count `prte' `late' `atut' `att' `mprte1' `mprte2' `mprte3' if "`namelist'"!="base" est `use' `folder'`namelist' tempname sup mte mat `sup'= e(support) qui svmat `sup' loc min=`sup'[1,1] loc max=`sup'[rowsof(`sup'),1] mat `mte'=e(mte)' svmat `mte' loc twoway (`plottype' `mte' `sup', `cmissing' yaxis(1 3)) (function y=_b[effects:ate], range(`min' `max') yaxis(1 3) lpattern(dash)) loc labels label(1 "MTE at mean") loc ylabelate ylabel(`=_b[effects:ate]' "ATE", axis(3) angle(horizontal)) loc no=0 loc order1 1 "MTE" if "`late'"!="" loc lateplus=1 else loc lateplus=0 foreach param in att atut prte late mprte1 mprte2 mprte3 { if "``param''"=="" continue loc no=`no'+1 cap confirm matrix e(mte`param') if _rc!=0 { di in red "No `param' estimate found in stored result." exit 301 } tempname mte`param' `param'weights mat `mte`param''=e(mte`param')' mat ``param'weights'=e(weights`param') svmat `mte`param'' svmat ``param'weights' if `no'==1 loc color maroon if `no'==2 loc color navy if `no'==3 loc color dkgreen if `no'==4 loc color dkorange loc twoway `twoway' (`plottype' `mte`param'' `sup', yaxis(1 3) `cmissing' lcolor(`color') lpattern(solid)) /// (scatter ``param'weights' `sup', yaxis(2) mcolor(`color') msymbol(smx)) /// (function y=_b[effects:`param'], yaxis(1 3) range(`min' `max') lcolor(`color') lpattern(dash)) loc ylabel`no' ylabel(`=_b[effects:`param']' "`=strupper("`param'")'", labcolor(`color') axis(3) add custom angle(horizontal)) loc order1 `order1' `=2*`no'+1' "MTE (`=strupper("`param'")')" loc order2 `order2' `=(`numParams'+1)*2+`no'+`lateplus'' "`=strupper("`param'")' weights" if "`param'"=="late" { loc twoway `twoway' (function y=e(iv), yaxis(1 3) range(`min' `max') lcolor(black) lpattern(dot) ) loc order2 `=(`numParams'+1)*2+1' "2SLS" `order2' } } if "`late'"=="" loc holes holes(`=`numParams'+2') loc order order(`order1' `order2') `holes' loc labels cols(`=`no'+1') size(small) loc yscale yscale(axis(2) alt) yscale(noline axis(3)) ylabel(, axis(3) noticks) loc ytitle2 ytitle("Weights", axis(2)) loc ytitle `ytitle', axis(3) } //Plot the specified MTE graph tempvar temp gen `temp'=round(`sup'1*100) qui tsset `temp' qui tsfill qui replace `sup'1=`temp'/100 if `sup'1==. qui replace `sup'1=round(`sup'1,0.01) if "`trimsupport'"!="" drop if !inrange(`sup',`trimlow',`trimhigh') qui sum `sup'1 loc min=`r(min)' loc max=`r(max)' twoway `twoway' /// , scheme(s2mono) graphregion(color(white)) plotregion(lcolor(black)) /// `graph_opts' `ytitle2' xtitle("Unobserved resistance to treatment") title("Marginal Treatment Effects") /// legend(`labels' title("`legendtitle'") `order') `yscale' `ylabelate' `ylabel1' `ylabel2' `ylabel3' `ylabel4' /// xscale(range(`min' `max')) xlabel(`=round(`min',0.1)'(0.1)`=round(`max',0.1)') name(mtePlot, replace) save tmp, replace restore } end }