Announcement

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

  • Stata Graph

    Hi all,
    How could we plot a graph like this in Stata?
    Attached Files

  • #2
    a starting point would be a forestplot; see
    Code:
    help meta_forestplot

    Comment


    • #3
      It can be coded, but it might take a bit of time. The size of the disks has to be manually programmed.

      A good start point is this previous post:

      https://www.statalist.org/forums/for...rvals-in-stata

      A raw version of it has been adapted below (by Clyde Schechter )

      Code:
      clear
      input str5 agegrp float(rr lower higher)
      "18-20"    1  .81  8.56
      "21-25" 2.63  .82  8.45
      "26-30" 2.64  .88  9.37
      "31-35" 2.87  .97  10.3
      "36-40" 3.16  .83   9.8
      "41-45" 2.86 1.65 17.24
      "46-50" 5.33  .96 11.55
      "51-55" 3.33  .38  7.92
      "56-60" 1.74 1.33 16.66
      "61-65" 4.71 1.27 18.52
      "66-70" 4.85  .03   22
      end
      
      split agegrp, parse("-") gen(age) destring
      gen age = (age1+age2)/2
      
      graph twoway (scatter age rr ) (rcap lower higher age, horizontal)

      Comment


      • #4
        Also see coefplot from SSC.

        Code:
        ssc describe coefplot
        Code:
        webuse bcgset, clear
        gen label= author +","+ string(year)
        mkmat _meta_es _meta_cil _meta_ciu, mat(res) rownames(label)
        *WEIGHTING VAR SHOULD BE PRESENT
        set seed 08162025
        gen wvar= runiformint(1, 7)
        mat list res
        mat res= res'
        coefplot mat(res), ci((res[2] res[3])) weight(wvar) rename(\_et\_al\_ = " et al." _&_ = " & ", regex)
        Res.:

        Code:
        . mat list res
        
        res[13,3]
                        _meta_es   _meta_cil   _meta_ciu
        Aronson,1948  -.88931133  -2.0076675   .22904481
        Ferguso~1949  -1.5853887  -2.4499552  -.72082208
        Rosenth~1960  -1.3480731  -2.6112513  -.08489504
        Hart_&_~1977  -1.4415512  -1.7188015  -1.1643009
        Frimodt~1973  -.21754732   -.6610806   .22598595
        Stein_&~1953  -.78611559  -.94898869  -.62324248
        Vandivi~1973  -1.6208982  -2.5464854  -.69531107
        TPT_Mad~1980   .01195233  -.11140991   .13531458
        Coetzee~1968  -.46941765  -.93502445  -.00381085
        Rosenth~1961  -1.3713448  -1.9009878  -.84170178
        Comstoc~1974  -.33935883  -.55771864  -.12099901
        Comstoc~1969    .4459134  -.98433108   1.8761579
        Comstoc~1976  -.01731395  -.54104867   .5064207
        Click image for larger version

Name:	Graph.png
Views:	1
Size:	73.1 KB
ID:	1781084

        Comment


        • #5
          Andrew Musau your code for the coefplot command in #4 throws a r(198) error for me. I am not sure you can use the weighting variable if you are plotting a matrix. Can you double-check please? I am using version 1.8.7 of coefplot on Stata 19.5/MP.
          Last edited by Hemanshu Kumar; 17 Aug 2025, 10:31.

          Comment


          • #6
            The version I used to generate #4 is 1.8.6.

            Code:
            . which coefplot
            C:\~\ado\plus\c\coefplot.ado
            *! version 1.8.6  22feb2023  Ben Jann
            After updating, I can replicate your error. Whether intentional or not, it appears that weights must be passed through internal variables in version 1.8.7.

            Code:
            webuse bcgset, clear
            gen label= author +","+ string(year)
            *WEIGHTING VAR SHOULD BE PRESENT
            set seed 08162025
            gen wvar= runiformint(1, 7)
            mkmat _meta_es _meta_cil _meta_ciu wvar, mat(res) rownames(label)
            mat list res
            mat res= res'
            coefplot mat(res), ci((res[2] res[3])) aux(res[4]) weight(@aux) rename(_et_al_ = " et al." _&_ = " & " "_" = " ", regex)
            Res.:

            Code:
            . mat list res
            
            res[13,4]
                            _meta_es   _meta_cil   _meta_ciu        wvar
            Aronson,1948  -.88931133  -2.0076675   .22904481           1
            Ferguso~1949  -1.5853887  -2.4499552  -.72082208           4
            Rosenth~1960  -1.3480731  -2.6112513  -.08489504           1
            Hart_&_~1977  -1.4415512  -1.7188015  -1.1643009           5
            Frimodt~1973  -.21754732   -.6610806   .22598595           6
            Stein_&~1953  -.78611559  -.94898869  -.62324248           5
            Vandivi~1973  -1.6208982  -2.5464854  -.69531107           2
            TPT_Mad~1980   .01195233  -.11140991   .13531458           7
            Coetzee~1968  -.46941765  -.93502445  -.00381085           1
            Rosenth~1961  -1.3713448  -1.9009878  -.84170178           7
            Comstoc~1974  -.33935883  -.55771864  -.12099901           1
            Comstoc~1969    .4459134  -.98433108   1.8761579           7
            Comstoc~1976  -.01731395  -.54104867   .50642077           3
            Click image for larger version

Name:	Graph.png
Views:	1
Size:	57.6 KB
ID:	1781106

            Comment


            • #7
              Two additional features of the example plot in #1 are marker labels and a legend for the weights. One way to get the latter is to draw a separate plot for each weight. The following does this:

              Code:
              webuse bcgset, clear
              gen label= author +","+ string(year)
              *WEIGHTING VAR SHOULD BE PRESENT
              set seed 08162025
              gen wvar= runiformint(1, 7)
              
              forval i = 1/ 7 {
                  mkmat _meta_es _meta_cil _meta_ciu if wvar == `i', mat(res`i') rownames(label)
                  mat res`i' = res`i''
              }
              
              forval i = 1/7 {
                  local plotcmd `plotcmd' (mat(res`i'), ci((res`i'[2] res`i'[3])) msize(`i') label(`i') )
              }
              
              coefplot `plotcmd' , ///
                  rename(_et_al_ = " et al." _&_ = " & " "_" = " ", regex) ///
                  format(%4.3f) ///    
                  legend(title("Lesion Count")) ///
                  mlabel mlabpos(2) mc(stc1) ///
                  ciopts(lcolor(stc1))
              which produces:
              Click image for larger version

Name:	Screenshot 2025-08-18 at 9.31.42 AM.png
Views:	1
Size:	248.7 KB
ID:	1781114



              The downside is that the coefficients are ordered by weight. There should be a way to fix this -- perhaps Andrew Musau or someone else can pitch in?

              Last edited by Hemanshu Kumar; 17 Aug 2025, 22:06.

              Comment


              • #8
                Also flagging Ben Jann since the change in passing weights may be unintentional (it is not documented in the change notes here) and may break some people's code when they upgrade to v1.8.7.

                Comment


                • #9
                  Originally posted by Hemanshu Kumar View Post

                  The downside is that the coefficients are ordered by weight. There should be a way to fix this -- perhaps Andrew Musau or someone else can pitch in?
                  You could plot the ordered coefficients first, but supress their markers and CIs. Here is an approach (changes are highlighted):

                  Code:
                  webuse bcgset, clear
                  gen label= author +","+ string(year)
                  *WEIGHTING VAR SHOULD BE PRESENT
                  set seed 08162025
                  gen wvar= runiformint(1, 7)
                  sort _meta_es label
                  mkmat _meta_es _meta_cil _meta_ciu, mat(res0) rownames(label)
                  mat res0= res0'
                  
                  forval i = 1/ 7 {
                      mkmat _meta_es _meta_cil _meta_ciu if wvar == `i', mat(res`i') rownames(label)
                      mat res`i' = res`i''
                  }
                  
                  forval i = 1/7 {
                      local plotcmd `plotcmd' (mat(res`i'), ci((res`i'[2] res`i'[3])) msize(`i') label(`i') mlabc(stc1) )
                  }
                  
                  coefplot (mat(res0), ci((res0[2] res0[3])) ciopts(lc(none))  mc(none) mlabc(none)) `plotcmd' , ///
                      rename(_et_al_ = " et al." _&_ = " & " "_" = " ", regex) ///
                      format(%4.3f) ///    
                      legend(order(4 6 8 10 12 14 16) title("Lesion Count")) ///
                      mlabel mlabpos(2) mc(stc1) ///
                      ciopts(lcolor(stc1))


                  Click image for larger version

Name:	Graph.png
Views:	1
Size:	149.5 KB
ID:	1781118


                  Comment


                  • #10
                    Thanks Andrew Musau , that's a great idea!

                    Here is slightly modified and simplified code, which also takes care of the marker offset issue I noticed in #9. I also changed the sort order to be alphabetical in the labels, just as proof of concept. If the sort order is to be the coefficient size, that can be achieved much more simply by just adding the sort option to the coefplot command code in #7.

                    Code:
                    webuse bcgset, clear
                    gen label= author +","+ string(year)
                    *WEIGHTING VAR SHOULD BE PRESENT
                    set seed 08162025
                    gen wvar= runiformint(1, 7)
                    sort label
                    
                    mkmat _meta_es _meta_cil _meta_ciu, mat(res0) rownames(label)
                    mat res0 = res0'
                    
                    forval i = 1/ 7 {
                        mkmat _meta_es _meta_cil _meta_ciu if wvar == `i', mat(res`i') rownames(label)
                        mat res`i' = res`i''
                        local plotcmd `plotcmd' (mat(res`i'), ci((res`i'[2] res`i'[3])) msize(`i') label(`i') offset(0))
                    }
                    
                    coefplot ///
                        (mat(res0) , noci mc(none) mlabc(none) nokey) ///
                        `plotcmd' , ///
                        rename(_et_al_ = " et al." _&_ = " & " "_" = " ", regex) ///
                        format(%4.3f) ///    
                        legend(title("Lesion Count")) ///
                        mlabel mlabpos(2) mc(stc1) ///
                        ciopts(lcolor(stc1))
                    which produces:
                    Click image for larger version

Name:	Screenshot 2025-08-18 at 2.12.46 PM.png
Views:	1
Size:	248.5 KB
ID:	1781121

                    Last edited by Hemanshu Kumar; 18 Aug 2025, 02:46.

                    Comment


                    • #11
                      You can specify option nodrop if you want to run the example in #4 in v1.8.7. There has been a change in how coefplot drops the current data before drawing the graph (which is done for reasons of speed); this change implies that the weight() option can no longer be used in the way it is used in example #4, unless nodrop is specified so that the current data is not dropped. The uninformative r(198) error comes from twoway (which is called by coefplot), because weights are applied that are all missing, as in the following example:

                      Code:
                      . drop _all
                      
                      . set obs 10
                      Number of observations (_N) was 0, now 10.
                      
                      . drawnorm x y
                      
                      . gen wvar = .
                      (10 missing values generated)
                      
                      . twoway (scatter x y [aw=wvar])
                      r(198);
                      However, option weight() is really only meant to be used with internal variable as in #6.

                      (Looking into this I noticed that coefplot v1.8.7 crashes if the current data contains 0 observations, unless nodrop is specified; I'll fix this and post an update.)

                      ben

                      Comment

                      Working...
                      X