Announcement

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

  • A method to produce in-set plots within Stata

    Hi all,

    Over the years there's been a number post on this forum about whether its possible to produce "zoomed-in" inset-plots within Stata. A number of work-arounds have been proposed:But, to my knowledge at least, no one has yet offered a "full" solution that produces inset plots within the main graph area with the full functionality of a normal Stata graph. After several fruitless endeavours, I've landed on a method that pretty much ticks all of the above, and figured I would share it on here in the hope that it may be of some use to others who are/will be interested in creating such plots.

    The end result can be seen in the bottom panel of the graph below. Clearly, the inset plot is a useful visual aid when observations are so densely clustered. (note I don't currently have access to Stata, so am not able to use remove all the unnecessary filler)
    Click image for larger version

Name:	image_25132.png
Views:	1
Size:	210.5 KB
ID:	1641257









    In short, the method I use is to plot the zoomed-in observations on a second axis (as well as the main one), and then to simply make that axis invisible. The "trick", however, is to artificially (and somewhat randomly) alter the range of the second axis, so as to confine the inset plot within a small area of the main plot. To do this I use the excellent - addplot - package from SSC, which allows one to create the main graph, and then add separate plot layers on top of it (somewhat in line with the grammar of graphics which informs R's ggplot2 ). The same effect can potentially be achieved without addplot , though I have not yet tested it.

    The first step is to plot the inset box within the main graph along the main graph axis (and optionally a smaller box to highlight the area to be zoomed in on, and lines connecting the two). This is easily done with addplot by plotting immediate scatter - scatteri - and then using - recast(line) - while ensuring that the norescaling option of addplot is specified so as to preserve the original plot dimensions.
    Code:
    *** Add inset plot axes and connecting lines
    addplot 2: (scatteri -.002 -.002 .002 -.002 .002 .00625 -.002 .00625 -.002 -.002, recast(line) lpattern(solid) lcolor(black)) /* Small inset box (highlighting the area we want to zoom in)
     */ (pcarrowi -.002 .00625 -.021 -.09, recast(line) lpattern(solid) lwidth(vthin) lcolor(black)) /*  Lines connecting small inset box to main inset box
    */  (pci .002 -.002 -.0055 -.1385, lpattern(solid) lwidth(vthin) lcolor(black)) (scatteri -.021 -.09 -.021 -.1385 -.0055 -.1385 -.0055 -.09 -.021 -.09 , recast(line)
        lpattern(solid) lcolor(black)) /* Main inset box
    */  (pci -.021 -.133 -.0055 -.133, lpattern(shortdash) lcolor(black) lwidth(thin)) (pci -.013 -.1385 -.013 -.09, lpattern(shortdash) lcolor(black) lwidth(thin) norescaling
        legend(off)) /* Y/X-axis guide lines (dashed )  */
    The next, and final step, is then add the actual plots markers along a hidden second axis (be it scatter points, lines or really anything that Stata can offer). As I said above, the key is to alter the range of the second Y/X-axis so that the inset markers fall within the inset box. For this particular plot, I reduce the Y range from -0.2/0.2 on the main axis to -0.001/0.000975 on the inset axis so as to confine inset markers to that bottom half of the plot (that is, the bottom half of the second panel). The same logic applies to the X-axis range. To be sure, getting these axis ranges right is pretty much trial and error. But I've generally found that you will get rough idea after around 3 attempts, and then it's just a matter of making small iterative adjustments to get a good fit.
    Code:
    *** Plot inset markers on 2nd X-axis
    addplot 2: (scatter DFZdif_def DFZdif_mcap if pclass_1 == 1 & DFZdif_mcap <=.002, msymbol(oh) msize(small) mcolor(gs1%2) xaxis(2) yaxis(2) ylabel(-.0001 .000975, axis(2)) /* Group scatter no.1
    */  xlabel(-.0007 .00725, axis(2)) yscale(axis(2) off) mlwidth(thin) jitter(.1)) (scatter DFZdif_def DFZdif_mcap if pclass_1 == 2 & DFZdif_mcap <=.002, msymbol(oh) msize(small) /*
    */  mcolor(gs5%25*1.2) xaxis(2) yaxis(2) ylabel(-.0001 .000975, axis(2)) xlabel(-.0007 .00725, axis(2)) yscale(axis(2) off) mlwidth(thin) jitter(.1)) /* Group scatter no.1
    */  (scatter DFZdif_def DFZdif_mcap if pclass_1 == 3 & DFZdif_mcap <=.002, msymbol(oh) msize(small) mcolor(gs9%25*1.1) xaxis(2) yaxis(2) ylabel(-.0001 .000975, axis(2)) /* Group scatter no.3
    */  xlabel(-.0007 .00725, axis(2)) yscale(axis(2) off) mlwidth(thin) jitter(.1)) (scatter DFZdif_def DFZdif_mcap if pclass_1 == 4 & DFZdif_mcap <=.002, msymbol(oh) msize(small) /* Group scatter no.4
    */  mcolor(gs13%50) xaxis(2) yaxis(2) ylabel(-.0001 .000975, axis(2)) xlabel(-.0007 .00725, axis(2)) yscale(axis(2) off) xscale(axis(2)off) mlwidth(thin) norescaling legend(off))
    And that's pretty much it. The inset axes are then made invisible by adding xscale(axis(2)off), and once again include the norescaling option to preserve the dimensions of the main plot.

    Axix ticks and label can be added pretty easily too once the second axis has been created. Axis ticks are added via addplot as immediate paired coordinates - pci - while the added text option - text - can be used to specify axis label values (or any other text).
    Code:
    addplot 5: (pci 750 -2.23 750 -2.32, xaxis(2) yaxis(2) lpattern(solid) lwidth(thin) lcolor(black) text(750 -2.5 "750", size(9pt) xaxis(2) yaxis(2) just(left))) (pci 500 -2.23 500 -2.32, xaxis(2) yaxis(2) lpattern(solid) lwidth(thin) lcolor(black) text(500 -2.5 "500", size(9pt) xaxis(2) yaxis(2) just(left))) (pci 250 -2.23 250 -2.32, xaxis(2) yaxis(2) lpattern(solid) lwidth(thin) lcolor(black) text(250 -2.5 "250", size(9pt) xaxis(2) yaxis(2) just(left))) (pci 0 -2.23 0 -2.32, xaxis(2) yaxis(2) lpattern(solid) lwidth(thin) lcolor(black) text(0 -2.5 "0", size(9pt) xaxis(2) yaxis(2) just(left))) (pci 0 -2.15 0 2.25, xaxis(2) yaxis(2) lwidth(0.1) lpattern(shortdash) lcolor(black) norescaling)
    And the plot with ticks and labels (this time used to generate a sort zoomed-out effect)
    Click image for larger version

Name:	image_25133.png
Views:	1
Size:	167.8 KB
ID:	1641259

    Last edited by Matthew Alexander; 16 Dec 2021, 12:32.

  • #2
    Dear Matthew,

    Intriguing post but you start your code from addplot 2: without providing the data (using dataex) and required code to create the first plot,

    I look forward to be able to replicate your example.
    http://publicationslist.org/eric.melse

    Comment


    • #3
      Hi Eric,

      I'm afraid I don't currently have access to Stata , hence I was not able to use datex or provide a instantly replicable example. Sorry about that.

      Broadly, everything you need to produce these sorts of plot is included above. But I can send you a copy of the dataset and do-file used produce the first plot if you would like?
      Last edited by Matthew Alexander; 16 Dec 2021, 14:46.

      Comment

      Working...
      X