Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Controlling empty categories and colour order in twoway ( bar , by ...

    Dear Statalist users. I have used twoway to produce a bar chart(s) representing multiple categorical variables, with SD error bars. Dataex and exact syntax for creating my figure are presented below (only variable / value labels have been modified). Stata 18 on Windows 11.

    1. One of the category levels ('control') for my dependent variable ('treat') does not exist for the second level ('knockout') of my 'by' variable ('ctype') (please see image attached).
    However, Stata has reserved a space for the bar of this non-existent category level.
    Could anyone advise how to avoid this? i.e. I want to remove the 'control' part from the 'Knockout' side of the figure.

    2. Another -probably- related issue is that the order of colours is disrupted on the right-hand chart.
    I would like it to match the left-hand chart while omitting that control category. i.e. I would like the bars for the 'Knockout' chart to be grey and red (left to right).
    I wonder if this may sort itself following a solution to number 1. above.
    Nevertheless, if there is a way to target specific bars for editing in such a 'bar, by..' graph, please suggest the appropriate syntax.

    Thank you in advance for your support.

    Code:
    clear
    input float(fi treat ctype exp)
    29 0 0 2
    28 0 0 2
    27 0 0 2
    95 1 0 2
    96 1 0 2
    94 1 0 2
    38 2 0 2
    45 2 0 2
    30 2 0 2
    78 1 1 2
    80 1 1 2
    76 1 1 2
    69 2 1 2
    72 2 1 2
    67 2 1 2
    end
    label values treat forglab
    label def forglab 0 "Control", modify
    label def forglab 1 "Untreated", modify
    label def forglab 2 "Treat-G", modify
    label values ctype shl
    label def shl 0 "WT", modify
    label def shl 1 "Knockout", modify
    Code:
    preserve
    collapse (mean) meanfi2e=fi (sd) sdfi2e=fi (count) n=fi if exp==2, by (treat ctype)
    gen sdhi2e = meanfi2e + sdfi2e
    gen sdlo2e = meanfi2e - sdfi2e
    
    twoway (bar meanfi2e treat, by(ctype, note("") legend(off) imargin(tiny)) ylabel(0(10)100, nogrid) barwidth(0.9) lcolor(black) lwidth(medthick) colorvar(treat) colorlevels(3) colorlist(gs1 gs6 red*0.8) colorfillonly clegend(off) xtitle("")) (rcap sdhi2e sdlo2e treat, lcolor(black) msize(medlarge) note("")), xlabel(0 "Control" 1 "Untreated" 2 "Treat-G", noticks nogrid) ytitle("Blank Index (%)", size(4)) ysize(4) xsize(3.5) plotregion(margin(b=0) fcolor(white) lstyle(none)) yscale(lwidth(medthick)) xscale(lwidth(medthick)) subtitle(, size(4) ring(6) position(6) nobox fcolor(none) margin(t=2)) name(figex, replace)
    restore
    Attached Files
    Last edited by Ryan McC; 01 Mar 2024, 00:16. Reason: Stata ver. + OS

  • #2
    You can get consistent bar colors by ensuring that all levels of "treat" are observed for each group of "ctype". The command -fillin- can help you with this, see

    Code:
    help fillin
    Code:
    clear
    input float(fi treat ctype exp)
    29 0 0 2
    28 0 0 2
    27 0 0 2
    95 1 0 2
    96 1 0 2
    94 1 0 2
    38 2 0 2
    45 2 0 2
    30 2 0 2
    78 1 1 2
    80 1 1 2
    76 1 1 2
    69 2 1 2
    72 2 1 2
    67 2 1 2
    end
    label values treat forglab
    label def forglab 0 "Control", modify
    label def forglab 1 "Untreated", modify
    label def forglab 2 "Treat-G", modify
    label values ctype shl
    label def shl 0 "WT", modify
    label def shl 1 "Knockout", modify
    
    *preserve
    collapse (mean) meanfi2e=fi (sd) sdfi2e=fi (count) n=fi if exp==2, by (treat ctype)
    gen sdhi2e = meanfi2e + sdfi2e
    gen sdlo2e = meanfi2e - sdfi2e
    fillin treat ctype
    
    twoway (bar meanfi2e treat, by(ctype, note("") legend(off) imargin(tiny)) ylabel(0(10)100, nogrid) ///
    barwidth(0.9) lcolor(black) lwidth(medthick) colorvar(treat) colorlevels(3) colorlist(gs1 gs6 red*0.8) ///
    colorfillonly clegend(off) xtitle("")) (rcap sdhi2e sdlo2e treat, lcolor(black) msize(medlarge) note("")), ///
    xlabel(0 "Control" 1 "Untreated" 2 "Treat-G", noticks nogrid) ytitle("Blank Index (%)", size(4)) ysize(4) xsize(3.5) ///
    plotregion(margin(b=0) fcolor(white) lstyle(none)) yscale(lwidth(medthick)) xscale(lwidth(medthick)) ///
    subtitle(, size(4) ring(6) position(6) nobox fcolor(none) margin(t=2)) name(figex, replace)
    Click image for larger version

Name:	figex.png
Views:	1
Size:	14.7 KB
ID:	1745145





    Now, the -by()- option is all about consistency. You cannot insist that you want one category in one group but not in another. If you want such a graph, you have to differentiate each bar and then forego the -by()- option.

    Code:
    clear
    input float(fi treat ctype exp)
    29 0 0 2
    28 0 0 2
    27 0 0 2
    95 1 0 2
    96 1 0 2
    94 1 0 2
    38 2 0 2
    45 2 0 2
    30 2 0 2
    78 1 1 2
    80 1 1 2
    76 1 1 2
    69 2 1 2
    72 2 1 2
    67 2 1 2
    end
    label values treat forglab
    label def forglab 0 "Control", modify
    label def forglab 1 "Untreated", modify
    label def forglab 2 "Treat-G", modify
    label values ctype shl
    label def shl 0 "WT", modify
    label def shl 1 "Knockout", modify
    
    *preserve
    collapse (mean) meanfi2e=fi (sd) sdfi2e=fi (count) n=fi if exp==2, by (treat ctype)
    gen sdhi2e = meanfi2e + sdfi2e
    gen sdlo2e = meanfi2e - sdfi2e
    
    *DETERMINE GAPS MANUALLY
    bys ctype (treat): gen bars= cond(!ctype,_n*2, (_n*2)+8)
    egen colorvar=group(bars)
    
    twoway (bar meanfi2e bars, ylabel(0(10)100, nogrid) colorvar(colorvar) colorlist(gs1 gs6 red*0.8 gs6 red*0.8) ///
    colorfillonly clegend(off) barwidth(1.8) lcolor(black) lwidth(medthick)  xtitle("")) (rcap sdhi2e sdlo2e bars, lcolor(black) ///
    msize(medlarge) note("")), xlabel(2 "Control" 4 "Untreated" 6 "Treat-G" 10 "Untreated" 12 "Treat-G", labsize(small) ///
    noticks nogrid) xsc(r(2 14)) ytitle("Blank Index (%)", size(4)) ysize(4) xsize(3.5) plotregion(margin(b=0) fcolor(white) lstyle(none)) ///
    yscale(lwidth(medthick)) xscale(lwidth(medthick)) subtitle(, size(4) ring(6) position(6) nobox fcolor(none) margin(t=2)) ///
    name(figex, replace) leg(off)
    Click image for larger version

Name:	figex2.png
Views:	1
Size:	13.7 KB
ID:	1745146





    You can now insert the group labels using the -text()- option or tw scatteri and extend the lower margin, which I will not illustrate here.
    Last edited by Andrew Musau; 01 Mar 2024, 03:11.

    Comment


    • #3
      Andrew thank you very much for your fantastic response, I have learned a lot from this!

      Comment

      Working...
      X