Announcement

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

  • How to create a tabplot-like graph with two categories per cell?

    Hi everyone,

    I would like to create in Stata a figure similar to the one shown at the end of this post, using the example dataset provided (shown with dataex).

    With this dataset, I can create two separate tabplot graphs (from SSC): one showing the percentage of zero and another showing the percentage of missings for a firm-level variable. These plots are structured by firm cohort (i.e., created in 2019, 2020, or 2021) and calendar year.

    I would like to combine the information from these two tabplots into a single figure, as in the example below, since this provides a clearer visualization of the patterns of zeros and missings across years for the different firm cohorts.

    Could you please advise on how to create a figure like this in Stata?

    Many thanks in advance!

    Best,
    Otavio



    Code:
    * Example generated by -dataex-. For more info, type help dataex
    clear
    input str15 taxpayer_creation_group int year float(proportion_missing proportion_zero)
    "Created in 2019" 2019  .6 .35
    "Created in 2019" 2020 .45  .3
    "Created in 2019" 2021  .5 .25
    "Created in 2020" 2019  .4 .28
    "Created in 2020" 2020 .55 .33
    "Created in 2020" 2021 .48 .31
    "Created in 2021" 2019 .32 .18
    "Created in 2021" 2020 .38 .22
    "Created in 2021" 2021 .45 .27
    end




    Click image for larger version

Name:	mockup_figure.png
Views:	1
Size:	38.8 KB
ID:	1784442

  • #2
    tabplot should be considered as originating from the Stata Journal (see https://journals.sagepub.com/doi/10....867X1601600214). First, you should reshape your data into a long layout. Then you may proceed along the following lines, noting that percentages are just proportions multiplied by 100.

    Code:
    * Example generated by -dataex-. For more info, type help dataex
    clear
    input str15 taxpayer_creation_group int year float(proportion_missing proportion_zero)
    "Created in 2019" 2019  .6 .35
    "Created in 2019" 2020 .45  .3
    "Created in 2019" 2021  .5 .25
    "Created in 2020" 2019  .4 .28
    "Created in 2020" 2020 .55 .33
    "Created in 2020" 2021 .48 .31
    "Created in 2021" 2019 .32 .18
    "Created in 2021" 2020 .38 .22
    "Created in 2021" 2021 .45 .27
    end
    
    *RESHAPE
    reshape long proportion_, i(taxpayer_creation_group year) j(which) string
    
    *GRAPH BAR
    gr hbar proportion , by(year, row(1) note("")) over(which) over( taxpayer) ///
    asyvars blab(total) ytitle("") ylabel(none)
    
    *USE GRAPH EDITOR TO REMOVE DUPLICATED LABELS
    forval i= 2/3{
        forval graphs= 1/3{
            gr_edit .plotregion1.grpaxis[`i'].major.delete_tick 1
        }
    }
    gr save gr1.gph, replace
    
    *TABPLOT
    tabplot which year [iw= proportion_ ], sort by( taxpayer_creation_group , col(1) note(""))  ///
    title("") separate(which) showval(format(%3.2f) ) ytitle("") xtitle("") horiz
    gr save gr2.gph, replace
    
    gr combine gr1.gph gr2.gph, row(2)
    Click image for larger version

Name:	Graph.png
Views:	1
Size:	62.5 KB
ID:	1784497

    Last edited by Andrew Musau; 24 Jan 2026, 05:13.

    Comment


    • #3
      Thanks for the data example and clear question.

      tabplot itself is better cited as coming from the Stata Journal. Here is an edited version of search results highlighting the 2016 paper and the latest public update. (In my own files the help has been updated to 2025 with, among other additions, a reference from Charles Booth in 1889.)

      Code:
      SJ-22-2 gr0066_3  . . . . . . . . . . . . . . . .  Software update for tabplot
              (help tabplot if installed) . . . . . . . . . . . . . . . .  N. J. Cox
              Q2/22   SJ 22(2):467
              bug fixed; help file updated to include further references
      
      SJ-16-2 gr0066  . . . . . .  Speaking Stata: Multiple bar charts in table form
              (help tabplot if installed) . . . . . . . . . . . . . . . .  N. J. Cox
              Q2/16   SJ 16(2):491--510
              provides multiple bar charts in table form representing
              contingency tables for one, two, or three categorical variabl
      es


      tabplot is focused on one outcome as a function of up to three controls. So here is one of many takes on that dataset.

      Code:
      * Example generated by -dataex-. For more info, type help dataex
      clear
      input str15 taxpayer_creation_group int year float(proportion_missing proportion_zero)
      "Created in 2019" 2019  .6 .35
      "Created in 2019" 2020 .45  .3
      "Created in 2019" 2021  .5 .25
      "Created in 2020" 2019  .4 .28
      "Created in 2020" 2020 .55 .33
      "Created in 2020" 2021 .48 .31
      "Created in 2021" 2019 .32 .18
      "Created in 2021" 2020 .38 .22
      "Created in 2021" 2021 .45 .27
      end
      
      reshape long proportion_ , i(taxpayer_creation_group year) j(Problem) string
      
      encode Problem, gen(problem)
      
      gen percent = proportion_ * 100
      
      tabplot problem year [iw=percent], by(taxpayer_creation_group, row(1) note("percent")) ///
      showval(offset(0.04) mlabsize(medlarge)) xtitle("") ytitle("") yla(, labsize(medlarge)) ///
      separate(problem) name(G1, replace)
      Click image for larger version

Name:	ott_G1.png
Views:	1
Size:	43.2 KB
ID:	1784499



      Going back to your original data layout, you can make quite a lot of progress with graph hbar,



      Code:
      clear
      
      input str15 taxpayer_creation_group int year float(proportion_missing proportion_zero)
      "Created in 2019" 2019  .6 .35
      "Created in 2019" 2020 .45  .3
      "Created in 2019" 2021  .5 .25
      "Created in 2020" 2019  .4 .28
      "Created in 2020" 2020 .55 .33
      "Created in 2020" 2021 .48 .31
      "Created in 2021" 2019 .32 .18
      "Created in 2021" 2020 .38 .22
      "Created in 2021" 2021 .45 .27
      end
      
      gen pc_missing = 100 * proportion_missing
      gen pc_zero = 100 * proportion_zero
      
      graph hbar (asis) pc_*, by(taxpayer_creation_group, note("") col(1) legend(pos(12))) subtitle(, pos(9) fcolor(none) nobexpand) over(year) legend(order(1 "% with missing" 2 "% with zero") row(1)) blabel(bar) name(G2, replace)
      Click image for larger version

Name:	ott_G2.png
Views:	1
Size:	39.1 KB
ID:	1784500



      Precisely what you've mocked up might need more customized coding.

      EDIT: I didn't see Andrew Musau's posting until I had posted mine, which took more than 2 minutes to draft.

      Comment


      • #4
        Here is another solution, using the twoway collection of graphing commands, and with some jiggery-pokery:

        Code:
        encode taxpayer_creation_group, gen(_groups)
        recode _groups (3=1) (1=3), gen(groups)
        drop _groups
        
        gen groups_missing = groups + 0.15
        gen groups_zero = groups - 0.15  
        gen zeros = 0
        
        gen label_missing = string(proportion_missing * 100, "%2.0f") + "%"
        gen label_zero = string(proportion_zero * 100, "%2.0f") + "%"
        
        twoway  (rbar zeros proportion_missing groups_missing, horizontal barwidth(0.3)) ///
                (rbar zeros proportion_zero groups_zero, horizontal  barwidth(0.3)) ///
                (scatter groups_missing proportion_missing, msym(i) mlabel(label_missing)) ///      
                (scatter groups_zero proportion_zero, msym(i) mlabel(label_zero)) ///
                , by(year, legend(pos(6)) row(1) note("")) ///
                xscale(noline) xlabel(none) ///
                ylabel(1 "Created in 2021" 2 "Created in 2020" 3 "Created in 2019") ///
                legend(order(1 2) label(1 "% with missing") label(2 "% zero") row(1))
        which produces:
        Click image for larger version

Name:	Screenshot 2026-01-24 at 8.40.46 PM.png
Views:	1
Size:	936.5 KB
ID:	1784504

        Last edited by Hemanshu Kumar; 24 Jan 2026, 08:19.

        Comment


        • #5
          Dear all,

          Many thanks for the great advice.

          Best,
          Otavio

          Comment

          Working...
          X