Announcement

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

  • Stacked bar chart

    Dear all, I have an apparently simple question that I am not figuring out how to solve:

    I have the following data:

    Code:
    * Example generated by -dataex-. For more info, type help dataex
    clear
    input byte(id step) float value
    1 1 10.47024
    1 2 3.703998
    1 3 85.82577
    end

    and I would like to obtain a stacked bar chart, where the values of the variable 'value' are piled up in a unique column (whose the total lenght will be 100%).

    Anyway, with the command
    Code:
    graph bar value, over(step) stack
    I obtain three column, each located in values 1, 2 and 3 (the values of my variable 'step').

    Where do I am wrong? Thanks a lot in advance, best, Giorgio

  • #2
    graph bar won't stack bars with the same colo[u]r. To get different colours you need asyvars too, as in

    Code:
    graph bar (asis) value, over(step) stack asyvars 

    Comment


    • #3
      Dear Nick, thanks a lot, this works perfectly!

      I would add another question: is there any way to decrease le width of the bar? It is indeed too wide, but the option
      Code:
       barwidth
      seems to not be supported.

      Comment


      • #4
        If this is the entire dataset to be graphed, I would fool with the aspect ratio, and in any case I wouldn't stack!

        Stacking confirms that the values add to 100, but you know that. I am guessing that comparing values with each other is the real focus.

        Code:
        * Example generated by -dataex-. For more info, type help dataex
        clear
        input byte(id step) float value
        1 1 10.47024
        1 2 3.703998
        1 3 85.82577
        end
        
        capture set scheme stcolor 
        
        graph bar (asis) value, over(step) stack asyvars aspect(2) legend(col(1) pos(3) order(3 2 1)) ytitle(Better text here) name(G1, replace)
        
        graph hbar (asis) value, over(step) aspect(2) ytitle(Better text here) ysc(alt) blabel(bar, format(%2.1f)) name(G2, replace)
        Click image for larger version

Name:	both.png
Views:	1
Size:	20.7 KB
ID:	1777801

        Comment


        • #5
          Dear Nick, thanks a lot for your advise, it has been of inspiration to fine tune the graph.

          Still thanks!

          Comment


          • #6
            Dear Nick, dear all, I came back to this post for a follow-up: I would need to elaborate more my stacked bar, and I guess the best way to gain flexibility is to work with -twoway-.

            I arranged the following data, but with the command below (I think the way to stack the different parts of the bars is the option -base-), I obtain a result which is not in line with what expected (and I really do not see why): in the first bar, indeed, the second 'portion' does not appear to be properly stacked (despite I think I have well organized the -base- option).

            Any help would be super appreciated.

            Thanks a lot, Giorgio

            Code:
            * Example generated by -dataex-. For more info, type help dataex
            clear
            input byte id str1 source float coeff byte step float base
            1 "a" .0025888 1        0
            1 "b" .0020174 2 .0025888
            1 "c" .0629557 3 .0046062
            2 "a" .0074922 1        0
            2 "b"  .014895 2 .0074922
            2 "c" .0099416 3 .0223872
            end
            Code:
            egen xpos = group(id)
            
              twoway ///
             (bar coeff xpos if id == 1 & step == 1, base(0) barwidth(0.6) color(white) lcolor(black)) ///
              (bar coeff xpos if id == 1 & step == 2, base(.002589) barwidth(0.6) color(gs13) lcolor(black)) ///
               (bar coeff xpos if id == 1 &  step == 3, base(.004606) barwidth(0.6) color(gs9) lcolor(black)) ///
                (bar coeff xpos if id == 2 & step == 1, base(0) barwidth(0.6) color(white) lcolor(black)) ///
              (bar coeff xpos if id == 2 & step == 2, base(0.0074922) barwidth(0.6) color(gs13) lcolor(black)) ///
               (bar coeff xpos if id == 2 &  step == 3, base(0.0223872) barwidth(0.6) color(gs9) lcolor(black)) ///
             , ///
               xlabel(1 "1" 2 "1", angle(45)) ///
              legend(order(1 "part a" 2 "part b" 3 "part c") position(6) cols(3) size(small)) ///
              ytitle("Value")

            Comment


            • #7
              That's a misunderstanding of what twoway bar will do. It won't do any additions or stacking. In fact a simple test such as

              Code:
              . gen test = 1
              
              . twoway bar test id, base(2)
              will show that the bar drawn starts at 2 and ends at 1, so is downwards. It does not start at 2 and add 1 to take the bar to 3.


              To stack with twoway bar, you need to calculate your own cumulatives for every bar except the first. That's tedious but easier than your code to write and follow.

              I have no idea what these data are, but if they were my problem I would change the unit of measurement by a factor of the order of 1000.

              Also, stacking I suggest is oversold. Stacking makes some interpretation easier if you are strongly interested in totals -- assuming that the components are genuinely additive, which may be moot -- but it makes other interpretation harder. Stacking usually obliges use of a legend, at best a necessary evil; can make it hard to evaluate very small or zero values; and is not always easily consistent with annotation with the numeric values themselves.

              Here I show an alternative using tabplot from the Stata Journal

              Code:
              * Example generated by -dataex-. For more info, type help dataex
              clear
              input byte id str1 source float coeff byte step float base
              1 "a" .0025888 1        0
              1 "b" .0020174 2 .0025888
              1 "c" .0629557 3 .0046062
              2 "a" .0074922 1        0
              2 "b"  .014895 2 .0074922
              2 "c" .0099416 3 .0223872
              end
              
              bysort id (source) : gen a = coeff[1]
              by id: gen ab = a + coeff[2]
              by id : gen abc = ab + coeff[3]
              
              local opt barw(0.6)
              twoway bar a id, `opt' || rbar a ab id, `opt' || rbar ab abc id , `opt' ///
              legend(order(1 "part a" 2 "part b" 3 "part c") position(6) cols(3) size(small)) ///
              ytitle("Value") xla(1 2) name(G1, replace)
              
              tabplot source id [iw=coeff], showval yreverse sep(source) name(G2, replace)
              Click image for larger version

Name:	giorgio_G1.png
Views:	1
Size:	27.3 KB
ID:	1778012
              Click image for larger version

Name:	giorgio_G2.png
Views:	1
Size:	28.7 KB
ID:	1778013

              Comment


              • #8
                Dear Nick, thanks a lot for your response and your kind adivse on tabplot, I will consider to use it (even if for my purpose I believe it is important to maintain the idea of stacked bar).

                I have elaborated a bit the code you provided me, which it helped me a lot, and I arrived nearly there; still, I am struggling with another option: indeed, I would like to overlay three of my bars (corresponding to id = 3, 4 and 6) with three white bars, of the same height. I played a bit with the -rbar- command, but I was not able to find a satisfying solution for bar 4 and 6 (while 3 works well). Probably, the problem with bar 4 is that it has a part under the 0, and I should set the 'lower bound' of my new (white) bar accordingly. But i really do not understand why it remains a very tiny part in the bar 6, as well.

                Here the code and data:

                Code:
                bysort id (source) : gen a = value_[1]
                by id: gen ab = a + value_[2]
                by id : gen abc = ab + value_[3]
                by id : gen abcd = abc + value_[4]
                
                *create variables with values to add 3 overlayed bars of the same height of those in correspondance of x3, x4 and x6, that cover the 'original' ones. 
                gen base = 0
                gen highx3 = 0.01687434
                gen highx4 = 0.00295595
                gen highx6 = 0.00098889
                
                gen x3 = id == 3
                gen x4 = id == 4
                gen x6 = id == 6
                
                gen id3 = id if x3
                gen id4 = id if x4
                gen id6 = id if x6
                
                
                local opt barw(0.6)
                twoway bar a id, `opt' || rbar a ab id, `opt' || rbar ab abc id , `opt' || rbar abc abcd id , `opt' || rbar base highx3 id3, barw(0.6) /* color(gs13%40)*/ color(white)  sort ///
                || rbar base highx4 id4, barw(0.6) /* color(gs13%40)*/ color(white) sort || rbar base highx6 id6, barw(0.6) /* color(gs13%40)*/ color(white) sort ///
                legend(order(1 "part a" 2 "part b" 3 "part c" 4 "part d") position(6) cols(3) size(small)) ///
                ytitle("Value") xla(1 2 3 4 5 6) name(G1, replace)
                Code:
                clear
                input byte id float value_ byte step
                1  .062389 1
                1  .004427 2
                1 -.000271 3
                1  .002797 4
                2  .005279 1
                2  .007576 2
                2  .014154 3
                2  .006057 4
                3  .005871 1
                3  .002254 2
                3  .004932 3
                3  .003816 4
                4 -.000131 1
                4 -.003071 2
                4  .001499 3
                4  .001457 4
                5  .008834 1
                5  .003522 2
                5  .006553 3
                5   .00213 4
                6  .000051 1
                6  .000263 2
                6  .000276 3
                6  .000399 4
                end

                Thanks again in advance for your kindness and support.

                Best, GP

                Comment


                • #9
                  Sorry, but I don't follow what you're after there. White bars? In Stata 19 (the default version on Statalist now) the default graph scheme is stcolor and white bars aren't visible as such. If you're using an earlier version of Stata and/or a different graph scheme, you need to tell us.

                  I read the data in before I tried to draw a graph, which is how my copy of Stata works. Also, the code in #8 won't run unless you edit
                  source to step.

                  Here is as far as I got.

                  Code:
                  clear
                  input byte id float value_ byte step
                  1  .062389 1
                  1  .004427 2
                  1 -.000271 3
                  1  .002797 4
                  2  .005279 1
                  2  .007576 2
                  2  .014154 3
                  2  .006057 4
                  3  .005871 1
                  3  .002254 2
                  3  .004932 3
                  3  .003816 4
                  4 -.000131 1
                  4 -.003071 2
                  4  .001499 3
                  4  .001457 4
                  5  .008834 1
                  5  .003522 2
                  5  .006553 3
                  5   .00213 4
                  6  .000051 1
                  6  .000263 2
                  6  .000276 3
                  6  .000399 4
                  end
                  
                  bysort id (step) : gen a = value_[1]
                  by id: gen ab = a + value_[2]
                  by id : gen abc = ab + value_[3]
                  by id : gen abcd = abc + value_[4]
                  
                  *create variables with values to add 3 overlayed bars of the same height of those in correspondance of x3, x4 and x6, that cover the 'original' ones.
                  gen base = 0
                  gen highx3 = 0.01687434
                  gen highx4 = 0.00295595
                  gen highx6 = 0.00098889
                  
                  gen x3 = id == 3
                  gen x4 = id == 4
                  gen x6 = id == 6
                  
                  gen id3 = id if x3
                  gen id4 = id if x4
                  gen id6 = id if x6
                  
                  
                  local opt barw(0.6)
                  
                  twoway bar a id, `opt' ///
                  || rbar a ab id, `opt' ///
                  || rbar ab abc id , `opt' ///
                  || rbar abc abcd id , `opt' ///
                  || rbar base highx3 id3, `opt' color(white) sort ///
                  || rbar base highx4 id4, `opt' color(white) sort ///
                  || rbar base highx6 id6, `opt' color(white) sort ///
                  legend(order(1 "part a" 2 "part b" 3 "part c" 4 "part d") position(6) cols(3) size(small)) ///
                  ytitle("Value") xla(1/6) name(G1, replace)
                  Last edited by Nick Cox; 28 May 2025, 11:33.

                  Comment


                  • #10
                    Dear Nick, thanks a lot for your reply, and sorry if my request of 'white bars' seem weird, maybe I did not explain well myself, if so apologize.

                    Basically, I would like to obtain a graph where bar 3, 4 and 6 would appear entirely white (not stacked as the 1,2 and 5) with just the outline color in black. In your graph there is the same 'problem' I was running into, namely that, while bar 3 is finely white (without the outline black, but this is not difficult to specify), in bar 4 there are still two 'stacked pieces' (yellow and green) visible, and in bar 6 one 'stacked piece' (yellow) visible. My aim would be to entirely cover (with the overlayed white bar), in these two latter bars, also the yellow and green pieces that remain visible.

                    Thanks a lot again for your kind support.

                    Best, Giorgio

                    Comment


                    • #11
                      Please answer the question about Stata version and graph scheme you are using. Showing the graph you got from your latest code is also a good idea.

                      Comment


                      • #12
                        Dear Nick, I am using Stata 18, and I did not set any particular graph scheme (so I assume I am using the standard).

                        Here the picture (I did not uploaded before because I remember was kind of discouraged by the Forum rules, sorry about that)

                        Thanks, Giorgio
                        Click image for larger version

Name:	G1.jpg
Views:	1
Size:	25.4 KB
ID:	1778137

                        Comment


                        • #13
                          There aren't any "rules" about not posting graph attachments. We have been encouraging and practising that since 2014. We try not to use the word rules at all: the ideal is that all our suggestions are requests, for all of which there are good reasons.

                          Otherwise I think I've got a better idea of what you want, so thanks, but a white colour -- both fill and outline -- will at best blank out what you previously plotted in the same place.

                          The graph in #12 was produced with different code as the bar width is 1.

                          This may help, even if you change some of the suggestions here. I don't see that you need to create quite so many new variables.

                          Code:
                          clear
                          input byte id float value_ byte step
                          1  .062389 1
                          1  .004427 2
                          1 -.000271 3
                          1  .002797 4
                          2  .005279 1
                          2  .007576 2
                          2  .014154 3
                          2  .006057 4
                          3  .005871 1
                          3  .002254 2
                          3  .004932 3
                          3  .003816 4
                          4 -.000131 1
                          4 -.003071 2
                          4  .001499 3
                          4  .001457 4
                          5  .008834 1
                          5  .003522 2
                          5  .006553 3
                          5   .00213 4
                          6  .000051 1
                          6  .000263 2
                          6  .000276 3
                          6  .000399 4
                          end
                          
                          bysort id (step) : gen a = value_[1]
                          by id: gen ab = a + value_[2]
                          by id : gen abc = ab + value_[3]
                          by id : gen abcd = abc + value_[4]
                          
                          * create variables with values to add 3 overlaid bars of the same height 
                          * as those in correspondance of x3, x4 and x6, that cover the 'originals'.
                          gen highx3 = 0.01687434
                          gen highx4 = 0.00295595
                          gen highx6 = 0.00098889
                          
                          local opt barw(0.6)
                          local opt2 fcolor(none) lcolor(black) 
                          
                          twoway bar a id, `opt' ///
                          || rbar a ab id, `opt' ///
                          || rbar ab abc id , `opt' ///
                          || rbar abc abcd id , `opt' ///
                          || bar highx3 id if id == 3, `opt' `opt2' ///
                          || bar highx4 id if id == 4, `opt' `opt2' ///
                          || bar highx6 id if id == 6, `opt' `opt2' ///
                          legend(order(4 "part d" 3 "part c" 2 "part b" 1 "part a") col(1) ring(0) position(1)) ///
                          ytitle("Value") xla(1/6) name(G3, replace)

                          Click image for larger version

Name:	giorgjo_G3.png
Views:	1
Size:	36.1 KB
ID:	1778142

                          Comment

                          Working...
                          X