Announcement

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

  • Creating inset graphs - for example, a zoomed section of a graph (i.e. not graph combine or addplot)

    Hi all,

    I have done a search of the forum and cannot find a relevant command to inset one graph inside another. Essentially, I have a line graph that shows some points which are very close together and therefore difficult to read (graph 1). I have created another graph which has a smaller axis to show these points, and it also has labelling of each line (graph 2). I would like to inset graph 2 into graph 1. An example image of this is Figure 3 here (note: I tried to upload this several times but was not able to): https://www.nejm.org/doi/full/10.1056/nejmoa2034577


    I do not have reproducible code to share as I haven't been able to find any commands to do this. Here is some example code for the types of graph I am trying to do:

    Code:
    *large graph (graph 1)
    graph twoway (connected age_under2yr age_2_5yr age_5_10yr age_10_20yr age_20_30yr age_30_40yr age_40_50yr age_50_60 age_60_70 age_70_80 age_over80 year, name(graph1, replace))
    
    *small graph (graph 2) - 25% of graph 1 size
    graph twoway (connected age_under2yr age_2_5yr age_5_10yr age_10_20yr age_20_30yr age_30_40yr age_40_50yr age_50_60 age_60_70 age_70_80 age_over80 year if year>=2016, fysize(25) fxsize(25) name(graph2, replace)) || ///
    (scatteri 17.312404 2020 "0-<2 years", msymbol(none) mlabsize(vsmall) mlabcolor(black)) || ///
    (scatteri 6.3826965 2020 "2-<5 years", msymbol(none) mlabsize(vsmall) mlabcolor(black)) || ///
    (scatteri 2.0296656 2020 "5-<10 years", msymbol(none) mlabsize(vsmall) mlabcolor(black)) || ///
    (scatteri .94445709 2020 "10-<20 years", msymbol(none) mlabsize(vsmall) mlabcolor(black)) || ///
    (scatteri 1.3032674 2020 "20-<30 years", msymbol(none) mlabsize(vsmall) mlabcolor(black)) || ///
    (scatteri 2.3703822 2020 "30-<40 years", msymbol(none) mlabsize(vsmall) mlabcolor(black)) || ///
    (scatteri 3.6785837 2020 "40-<50 years", msymbol(none) mlabsize(vsmall) mlabcolor(black)) || ///
    (scatteri 4.5065522 2020 "50-<60 years", msymbol(none) mlabsize(vsmall) mlabcolor(black)) || ///
    (scatteri 6.3089339 2020 "60-<70 years", msymbol(none) mlabsize(vsmall) mlabcolor(black)) || ///
    (scatteri 6.437849 2020 "70-<80 years", msymbol(none) mlabsize(vsmall) mlabcolor(black)) || ///
    (scatteri 12.434849 2020 "≥80 years", msymbol(none) mlabsize(vsmall) mlabcolor(black))
    
    *code to inset graph 2 in graph 1
    [none]
    Thanks!
    Last edited by Monica Larissa; 12 May 2022, 22:23.

  • #2
    Mead Over has done some work in this area. See, e.g., https://www.statalist.org/forums/for...hs-using-stata.

    Comment


    • #3
      Dear Monica,

      Possibly this post is helpful: A method to produce in-set plots within Stata
      http://publicationslist.org/eric.melse

      Comment


      • #4
        Thank you both- I found (and tried) both of these solutions but could not get them to work. I was hoping new solutions may be available as the newest post is over a year old. I will add specific questions for the solutions on their respective threads.

        Comment


        • #5
          Monica Larissa , it would help if you explain why the solutions presented above do not work.

          Here is an attempt to apply your code to some imaginary data. First I generate the data which hopefully bears at least some resemblance to your real data.

          Code:
          *    Generate the year variable for 1940 through 2020
          clear
          mata: mata clear
          
          set obs 82
          gen year = 1939 + _n
          
          mat define y2020 = ///
          (17.312404  \  ///
           6.3826965  \  ///
           2.0296656  \  ///
           .94445709  \  ///
           1.3032674  \  ///
           2.3703822  \  ///
           3.6785837  \  ///
           4.5065522  \  ///
           6.3089339  \  ///
           6.437849   \  ///
           12.434849  )
           
          *    List the Stata matrix containing the 2020 values
          matrix list y2020
           
          
          *    For each age group,  ...
          local i = 0
          foreach v in age_under2yr age_2_5yr age_5_10yr age_10_20yr age_20_30yr age_30_40yr age_40_50yr age_50_60 age_60_70 age_70_80 age_over80 {
              local ++i
              
              //  Create a variable which declines linearly from year 1940 to its 2020 value
              gen `v'0 = y2020[`i',1] if year == 2020
              
              replace `v'0 = 2*y2020[`i',1] if year == 1940
              
              ipolate `v'0 year ,  gen(`v')
              drop `v'0
          
              //  Add some random noise to make the artificial data look more real
              qui sum `v'
              replace `v' = `v' + rnormal(0,0.2*`r(sd)')
          }
          des
          sum
          I then apply -gr combine- as I suggested in post https://www.statalist.org/forums/for...hs-using-stata with the following code.

          Code:
          *large graph (graph 1)
          graph twoway (connected age_under2yr age_2_5yr age_5_10yr age_10_20yr age_20_30yr age_30_40yr age_40_50yr age_50_60 age_60_70 age_70_80 age_over80 year), legend(off) ylabel(0(20)60)  scheme(s2color) name(graph1, replace)
          
          *small graph (graph 2) - 25% of graph 1 size
          graph twoway (connected age_under2yr age_2_5yr age_5_10yr age_10_20yr age_20_30yr age_30_40yr age_40_50yr age_50_60 age_60_70 age_70_80 age_over80 year if year>=2016,  ///
              msize(vsmall vsmall vsmall vsmall vsmall vsmall vsmall vsmall vsmall vsmall vsmall ) fysize(25) fxsize(25)) || ///
              (scatteri 2.0296656 2020 "5-<10 years", msymbol(none) mlabsize(vsmall) mlabcolor(black)) || ///
              (scatteri .94445709 2020 "10-<20 years", msymbol(none) mlabsize(vsmall) mlabcolor(black)) || ///
              (scatteri 1.3032674 2020 "20-<30 years", msymbol(none) mlabsize(vsmall) mlabcolor(black)) || ///
              (scatteri 2.3703822 2020 "30-<40 years", msymbol(none) mlabsize(vsmall) mlabcolor(black)) || ///
              (scatteri 6.3826965 2020 "2-<5 years", msymbol(none) mlabsize(vsmall) mlabcolor(black)) || ///
              (scatteri 3.6785837 2020 "40-<50 years", msymbol(none) mlabsize(vsmall) mlabcolor(black)) || ///
              (scatteri 17.312404 2020 "0-<2 years", msymbol(none) mlabsize(vsmall) mlabcolor(black)) || ///
              (scatteri 4.5065522 2020 "50-<60 years", msymbol(none) mlabsize(vsmall) mlabcolor(black)) || ///
              (scatteri 6.3089339 2020 "60-<70 years", msymbol(none) mlabsize(vsmall) mlabcolor(black)) || ///
              (scatteri 6.437849 2020 "70-<80 years", msymbol(none) mlabsize(vsmall) mlabcolor(black)) || ///
              (scatteri 12.434849 2020 "≥80 years", msymbol(none) mlabsize(vsmall) mlabcolor(black)) , ///
              legend(off) ylabel(,labsize(vsmall)) xlabel(2016(1)2022,labsize(vsmall) angle(45))  scheme(s2color) name(graph2, replace)
          
          graph combine graph1 graph2 graph2, holes(3) imargin(0 0 0 0) scheme(s2color) name(combined, replace)  
          
          _gm_edit .combined.plotregion1.graph3.dragable = 1
          _gm_edit .combined.plotregion1.graph3.DragBy 60 -35
          _gm_edit .combined.plotregion1.graph2.draw_view.setstyle, style(no)
          
          graph display combined
          When I save the resulting graph as a "png" file, here is the result. The resulting graph seems to me to fit your needs except for the too-large margins below and to the right of the graph.

          Click image for larger version

Name:	combined.png
Views:	1
Size:	306.7 KB
ID:	1665081

          If you use a graph scheme with a white background such as -s2clr_on_white-, the blue margin of the inset graph disappears, but the right and bottom margins remain too large. The scheme -s2clr_on_white- can be located and installed with the command:
          Code:
          view net describe scheme_s2clr_on_white, from(http://digital.cgdev.org/doc/stata/MO/Misc)

          Code:
          gr display combined, scheme(s2clr_on_white)
          Click image for larger version

Name:	combined_on_white.png
Views:	1
Size:	296.9 KB
ID:	1665082


          At this point, I don't know how to suppress the excessive margins within Stata. Perhaps someone else on Statalist can suggest how to do that. However, using an image editing program like IrfanView to crop the margins of this -png- file gives:
          Click image for larger version

Name:	combined_cropped.png
Views:	1
Size:	278.5 KB
ID:	1665083

          If you could tell us why this graph does not work for your purposes, perhaps someone on the list could be of more help.
          Last edited by Mead Over; 17 May 2022, 13:39.

          Comment


          • #6
            Monica Larissa If you still require an inset for a zoomed in section of a graph that is fully reproducible in Stata, then send your data/do-file my way through private message and I will send you back the required code. Note I am the OP of https://www.statalist.org/forums/for...s-within-stata, which was suggested to you above.

            Comment


            • #7
              Or, Monica Larissa , simply adapt the following to your needs.

              First, I use the exact same data generation process posted by Mead Over above in #5 (I hope he does not mind).

              Then I do the following:

              Code:
              local insetops lwidth(vthin vthin vthin vthin vthin vthin vthin vthin vthin ) msize(vsmall vsmall vsmall vsmall vsmall vsmall vsmall vsmall vsmall)
              graph twoway connected age_under2yr age_2_5yr age_5_10yr age_10_20yr age_20_30yr age_30_40yr age_40_50yr age_50_60 age_60_70 age_70_80 age_over80 year ///
              || connected age_2_5yr age_5_10yr age_10_20yr age_20_30yr age_30_40yr age_40_50yr age_50_60 age_60_70 age_70_80 year if year >= 2000 , `insetops' xaxis(2) yaxis(2) ylabel(-30 10, axis(2)) xlabel(1970 2020, axis(2)) xscale(axis(2) off) yscale(axis(2) off) ///
              || scatteri 0.25 1999.5 10 1999.5 10 2021 0.25 2021 0.25 1999.5 , recast(line) lwidth(medthin) lcolor(black) ///
              || scatteri 0 1999.5 10 1999.5 10 2021 0 2021 0 1999.5 , recast(line) lwidth(medthin) lcolor(black) xaxis(2) yaxis(2) ///
              || scatteri 10 1999.5 30 1987.1, recast(line) lcolor(black) lwidth(medthin) ///
              || scatteri 10 2021 30 2021.5, recast(line) lcolor(black) lwidth(medthin) legend(off) scheme(s1color)
              Click image for larger version

Name:	insetg.png
Views:	1
Size:	185.3 KB
ID:	1666845



              The above plot zooms in on data between 2000 and 2020 (excluding the upper two groups), so I set the upper limit of the second x-axis to 2020 and the lower limit to 1970 so as to constrain the inset within the right-third of the graph. One slight issue is that the colours of the inset are not synchronised with those in the main graph, but this is easily corrected. You will also need to properly format the legend. From there, you can play around with the axis and plot ranges; for example, if you wanted to zoom in on data between 1940-1960, then you would need to adjust the range of the second x-axis (the inset axis), so that the the upper limit is 1960 and the lower limit is, I would estimate, around 1910ish (you might want to remove the connecting lines too). Hope this helps!
              Last edited by Matthew Alexander; 29 May 2022, 17:48.

              Comment

              Working...
              X