Example II

Coefplot in combination with the "mean" command

This section is recommended to you especially if you analyze data from an RCT, or you want to plot means over some form of groups and display whether they differ significantly. You can do this with the coefplot command, as shown in the following examples:

Examples

The syntax for the graphs depends on your Stata version: Between version 15 and 16, the mean command was changed, such that it stores the results differently. As the coefplot accesses these results, this causes problems when switching between versions.

You could simply copy the code below, but to be fully able to adjust it, you need to understand what is going on. Let's imagine you run the following:

mean price, over(foreign)

In Stata 15, the mean command names the coefficients based on the value labels of the group variable (i.e., foreign). This means, if you run this for different outcome variables (e.g., price, length, weight), the coefficients will always be named the same --> the coefplot command assumes they belong together. To separate them by equations, i.e., for each outcome, you have to put the option "eqstrict". You can label the different outcomes using the "eqlabel" option. Also, you can only alter the different outcome plots by referring to their equation name, while you alter the treatment status/group level coefficients by using to the coefficient name that the mean command assigned (type "mat list r(table)" after the mean command to see how they are named).

In Stata 16, the mean command names the coefficients based on the outcome variable, then an "@", and then the level and the variable name of the group variable (e.g., c.price @ 0.foreign and c.price @ 1.foreign). This means, the coefplot already recognizes all outcome coefficients as different, and plots them after another. What you might want to do is to attach a label to the subgroups. You can do this in several ways:

One option is to specify "eqstrict" and "asequation", and then use "eqlabels()" to specify the labels (one after each other, in quotes). Another, more flexible possibility is using the "groups" option, where you specify how which group of coefficients (you can use wildcards such as "*") should be put next to each other and how they should be labeled. This allows you to group coefficients irrespective of the equation.

You can alter the different outcome plots by referring to the equation or the variable name of the outcome variable (put a "*" at the beginning & end of the name, or a c. at the beginning and a "*" at the end, as they are labelled c.varname @ 0.group etc.).

Code for shown examples

sysuse auto.dta, clear

		
** Option 1a: Label/define outcomes by hand & place labels to the left **

// Stata 16: Using the groups option
version 16	
	estimates clear
	local list
	foreach v of varlist rep78 headroom gear_ratio {
		qui: mean `v', over(foreign)					
		estimates store e_`v'
	}
	coefplot *, recast(bar) citop fint(*.75) graphr(c(white)) nooffset			///
		coeflab(*0.foreign="Domestic" *1.foreign="Foreign") nokey			///
		groups(*rep78*="Repairs" *head*="Headroom" *gear*="Gear Ratio", angle(horizontal))
	
// Stata 16: Using the eqstrict & asequation options		
version 16	
	estimates clear
	local list
	foreach v of varlist rep78 headroom gear_ratio {
		qui: mean `v', over(foreign)					
		estimates store e_`v'
	}
	coefplot *, recast(bar) citop fint(*.75) graphr(c(white)) nooffset			///
		coeflab(*0.foreign="Domestic" *1.foreign="Foreign") nokey			///
		aseq eqstrict eqlab("Repairs" "Headroom" "Gear Ratio", angle(horizontal))
		  
// Stata 15
version 15
	est clear
	local list
	foreach v of varlist rep78 headroom gear_ratio {
		qui: mean `v', over(foreign)
		est store e_`v'			
	}
	coefplot *, recast(bar) citop fint(*.75) graphr(c(white)) nooffset			///
		nokey										///
		eqstrict eqlab("Repairs" "Headroom" "Gear Ratio", angle(horizontal))

		
	
** Option 2a: Label/define outcomes automatically & display in the legend **

// Stata 16
version 16
	est clear
	local list
	foreach v of varlist rep78 headroom gear_ratio {
		local lab: var la `v'
		qui mean `v', over(foreign)
		est store e_`v'			
		local list `list' (e_`v', lab(`lab')) 
	}
	coefplot `list', recast(bar) citop fint(*.75) graphr(c(white)) nooffset 		///
		coeflab(*0.foreign="Domestic" *1.foreign="Foreign")  

// Stata 15
version 15
	est clear
	local list
	local glist
	foreach v of varlist rep78 headroom gear_ratio {
		local lab: var la `v'
		qui mean `v', over(foreign)
		est store e_`v'			
		local list `list' (e_`v', lab(`lab')) 
	}
	coefplot `list', recast(bar) citop fint(*.75) graphr(c(white)) nooffset 		///
		eqstrict noeqlab  
	

	
** Option 2b: Label/define outcomes automatically & place labels to the left **

// Stata 16: Using the groups option
version 16
	est clear
	local glist
	foreach v of varlist rep78 headroom gear_ratio {
		local lab: var la `v'
		qui mean `v', over(foreign)
		est store e_`v'			
		local glist `glist' *`v'*=`"`lab'"'
	}
	coefplot *, recast(bar) citop fint(*.75) graphr(c(white)) nooffset			///
		coeflab(*0.foreign="Domestic" *1.foreign="Foreign") nokey			///
		groups(`glist', angle(horizontal)) 
	
// Stata 16: Using the eqstrict & asequation options		
version 16
	est clear
	local glist
	foreach v of varlist rep78 headroom gear_ratio {
		local lab: var la `v'
		qui mean `v', over(foreign)
		est store e_`v'			
		local glist `"`glist' "`lab'""'
	}
	coefplot *, recast(bar) citop fint(*.75) graphr(c(white)) nooffset			///
		coeflab(*0.foreign="Domestic" *1.foreign="Foreign") nokey			///
		eqstrict aseq eqlab(`glist', angle(horizontal))
	
// Stata 15		
version 15
	est clear
	local list
	foreach v of varlist rep78 headroom gear_ratio {
		local lab: var la `v'
		qui mean `v', over(foreign)
		est store e_`v'			
		local list `list' (e_`v', lab(`lab')) 
	}
	coefplot `list', recast(bar) citop fint(*.75) graphr(c(white)) nooffset 		///
		eqstrict eqlab(,label angle(horizontal)) nokey 	
			
Significance stars

As described at the end of the coefplot help-file, coefplot stores internal variables. These can be used to adjust graphs very flexibly, e.g. with text in the plot area, marker size, etc. (check http://repec.sowi.unibe.ch/stata/coefplot). We can use this to display significance stars based on a simple hypothesis test. We use the "cond" function to determine what should be displayed based on the p-value. We then attach this as marker value to each plot.

If you do not recast the graph, all work is done. If you use recast to get a bar graph, you need to add an ("invisible") scatter plot, as the bar graph does not support marker labels. So we will use the scatter plot to use the marker labels, but make the scatter plot itself (i.e. it markers, the "dots") invisible. For this, we make use of the internal variables again. The marker labels are stored in @mlbl. To make sure that the right position is met, we can use @at, which contains information where each plot is located, and @ll, @b, or @ul, which stand for the lower CI boundary, the coefficient estimate, and the upper CI. The option ms(i) within the addplot() option makes sure that the markers of the scatter plot are invisible. The option mlabcolor(none) outside the addplot() option make sure that the marker labels are not set in the main graph (which leads to weird results).

Partly inspired by http://repec.sowi.unibe.ch/stata/coefplot/markers.html.

** Option 2b with significance stars **

version 16	
	est clear
	local list
	local glist
	foreach v of varlist rep78 headroom gear_ratio {
		local lab: var la `v'
		qui: mean `v', over(foreign)
		est store e_`v'			
		qui test `v'@0.foreign=`v'@1.foreign		// remember how coefficients are stored
		local s = cond(`r(p)'<.01, "***", cond(`r(p)'<.05, "**", cond(`r(p)'<.1, "*","")))
		local list `list' (e_`v', mlabels(*1.foreign = 1 "`s'")) 
		local glist `glist' *`v'*=`"`lab'"'
	}
	coefplot `list', recast(bar) citop fint(*.75) nooffset graphr(c(white))			///
		coeflab(*0.foreign="Domestic" *1.foreign="Foreign") nokey			///
		groups(`glist', angle(horizontal)) mlabcolor(none)				///
		addplot(scatter @at @b, ms(i) mlabel(@mlbl) mlabcolor(black) mlabpos(1))
	
version 15
	est clear
	local list
	foreach v of varlist rep78 headroom gear_ratio {
		local lab: var la `v'
		qui mean `v', over(foreign)
		est store e_`v'			
		qui test Domestic=Foreign			// remember how coefficients are stored
		local s = cond(`r(p)'<.01, "***", cond(`r(p)'<.05, "**", cond(`r(p)'<.1, "*","")))
		local list `list' (e_`v', mlabels(Foreign = 1 "`s'")) 
	}
	coefplot `list', recast(bar) citop fint(*.75) graphr(c(white)) nooffset 		///
		eqstrict eqlab(,label angle(horizontal)) nokey mlabcolor(none)			///
		addplot(scatter @at @b, ms(i) mlabel(@mlbl) mlabcolor(black) mlabpos(1))			
			
Controlling the colors

You might want to have different colors for the different groups instead of the different outcomes. Again, there are several options how to implement this. One is to estimate the mean separately for each group, as this allows you to adjust the plot for each group separately. However, this means that the coefficients obtained from the mean estimation will be named the same for the same outcome, irrespective of the group. Hence, the coefplot command will try to display them at the same spot. You can shift single plots by using the "offset" option.

You can either change the color of the plots by hand, or use a simple trick with the "pcycle" option. This is an option of the twoway command and can be used for the coefplot. It sets after how many plots the default colors are repeated. When using the legend, please notice that the coefplot counts the coefficient estimate as first plot, the confidence interval as second plot and so on. Hence, you need to restrict the legend to the 1st and 3rd plot in the case of two groups, the 1st, 3rd and 5th in the case of three groups and so on.

*** Option 3: Treatment & control have different colors ***

// works for version 15 and 16
	est clear
	local elist
	foreach v of varlist rep78 headroom gear_ratio {
		local lab: var la `v'
		qui mean `v' if foreign==0			// alternatively, use a loop
		est store e_`v'0			
		qui mean `v' if foreign==1
		est store e_`v'1
		local elist `elist' (e_`v'0, offset(1/6)) (e_`v'1, offset(-1/6))
	}
	coefplot `elist', recast(bar) citop fint(*.75) graphr(c(white)) 			///
		barw(0.33) pcycle(2) 								///
		legend(order(1 3) lab(1 "Domestic") lab(3 "Foreign"))	
			
Additional hints

To have the bars start directly at the axis (without a gap), add the option

  • plotr(margin(zero))

To have no grid lines, add the options

  • ytick(, nogrid)
  • grid(none)

To have grid lines the other way round, add the options

  • ytick(, nogrid)
  • xlab(, grid)