Amberopolis
Amberopolis

Reputation: 455

Sort graph bar by target variables, followed by sort variables

I make a lot of graphs comparing two groups (e.g., male/female) across a number of variables. The standard -graph bar- output groups all bars for men together, and all bars for women together. I am hoping to find a simple way to make bar graphs that group bars first by the target variable (i.e. the variables being graphed), and then by the -over- variable, such as gender.

I have a method for doing this, but it is quite cumbersome. See illustration below.

*Set seed + obs
clear
set seed 442
set obs 100

*Generate two outcomes
gen x1 = uniform()
gen x2 = uniform()

*Generate crossing variable
gen gender = 0 in 1/50
replace gender = 1 in 51/100
label define gender_lab 0 "Male" 1 "Female"
label values gender gender_lab

*Extract means by gender
gen b_male = .
gen b_female = .
sum x1 if gender == 0 
replace b_male = r(mean) in 1
sum x1 if gender == 1
replace b_female = r(mean) in 1
sum x2 if gender == 0
replace b_male = r(mean) in 2
sum x2 if gender == 1
replace b_female = r(mean) in 2

*Establish order of graph
gen index_male = _n*3 in 1/2
gen index_female = (_n*3) + 1 in 1/2


*This is what -graph bar- produces naturally
graph bar x1 x2, over(gender)

*This is closer to what I want
twoway bar b_male index_male || bar b_female index_female, xlabel(3.5 "x1" 6.5 "x2", notick labgap(4)) xmlabel(3 "Male" 4 "Female" 6 "Male" 7 "Female") legend(off)

Is there a simple way to use graph bar but still establish the sort order I want? I produce dozens of these graphs per day sometimes, so I want to avoid unnecessary steps as much as possible.

Upvotes: 1

Views: 1769

Answers (1)

Nick Cox
Nick Cox

Reputation: 37208

This is a model question: thank you very much!

I'll first copy your code, with some small simplifications which may be of interest any way.

*Set seed + obs
clear
set seed 442
set obs 100

*Generate two outcomes
gen x1 = runiform()
gen x2 = runiform()

*Generate crossing variable
gen gender = _n > 50 
label define gender_lab 0 "Male" 1 "Female"
label values gender gender_lab

*Extract means by gender
sum x1 if gender == 0 
gen b_male = r(mean) in 1
sum x1 if gender == 1
gen b_female = r(mean) in 1
sum x2 if gender == 0
replace b_male = r(mean) in 2
sum x2 if gender == 1
replace b_female = r(mean) in 2

*Establish order of graph
gen index_male = _n*3 in 1/2
gen index_female = (_n*3) + 1 in 1/2

*This is what -graph bar- produces naturally
graph bar x1 x2, over(gender) name(G1) 

*This is closer to what I want
twoway bar b_male index_male || bar b_female index_female, ///
xlabel(3.5 "x1" 6.5 "x2", notick labgap(4))                ///
xmlabel(3 "Male" 4 "Female" 6 "Male" 7 "Female") legend(off) name(G2)  

The good news is that there is a one-line solution once you have installed statplot by Eric A. Booth and myself from SSC. (The email address for Eric is the help file is no longer current.)

ssc inst statplot 
statplot x1 x2, over(gender)
statplot x1 x2, over(gender) recast(bar)
statplot x1 x2, over(gender) recast(bar) asyvars yla(, ang(h)) ///
bar(2, bcolor(orange*0.8)) bar(1, bcolor(blue*0.8))

Here is the last graph to show what is done.

statplot defaults to means, what is what you show, so you don't have to calculate means. Other statistics are available.

enter image description here

Upvotes: 3

Related Questions