Announcement

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

  • lasagna plot package

    Greetings. I'm working on an .ado file that handles lasagna plots. It relies on the -twoway contour- command and works more or less as expected. Code and example usage are below.

    I'd like to distribute as a package, but there are a few things that need to be resolved first. Specifically, when there are many (>25 or so) units represented on the Y axis, I cannot seem to get them spaced so that there is a reasonable amount of vertical padding between them (as seen in the example). Secondly, it would be more appropriate to generate the yId variable as a tempvar. But if I do so, I cannot seem to pass it to -twoway contour- without an error (var does not exist).

    Any suggestions are appreciated.

    Cheers,
    Geoff

    Code:
    capture program drop lasagna
    program define lasagna 
         
        syntax varlist(min=3 max=3) [if] [in], label(varname)
        tokenize `varlist'
    
        *number the y values consecutively so that they display evenly on graph 
        cap drop yId
        egen yId=group(`2') 
    
        * get a unique list of y values to make labels for each 
        preserve 
        duplicates drop yId, force
        local max=_N 
         
        * add the text label for each one to the labels local 
        foreach i of numlist 1/`max' {
            local labelText=`label'[`i']
            local ylab `"`ylab'`i' "`labelText'" "'
        }
    
        * get our original data back and make the graph      
        restore 
        
        twoway contour   `1' yId `3', heatmap levels(5) ///
            ylabel(`ylab',  angle(horizontal) labsize(vsmall) )     
    
        cap drop Yid    
    end
    
    *use http://www.stata-press.com/data/r15/nlswork.dta, clear
    *save nlswork, replace 
    
    use nlswork, clear
    
    * keep a reasonable number of years for graphing 
    keep if inrange(year,82,88) 
    
    * randomly assign each respondent to a state so we can see how the graph labeling works
    bys idcode: gen fips=runiformint(1, 56) if _n==1
    
    bys idcode: replace fips=fips[1]
    
    * generate a longitudinal file by state
    collapse (mean) ln_wage, by(fips year) 
    
    * get names for the respondent fips codes 
    statastates, fips(fips) 
    
    keep if _merge==3
    
    lasagna ln_wage fips year, label(state_name)

  • #2
    At first sight the bug arises because you restore the original data before you graph, but the problem remains even if that is fixed.

    This is as far as I got.

    A glitch in your test script is that you assume that statastates (SSC) is installed. Beyond that, your program promises support for if and in but doesn't yet implement that.

    Code:
    capture program drop lasagna2
    program define lasagna2 
         
        syntax varlist(min=3 max=3) [if] [in], label(varname)
        tokenize `varlist'
    
        *number the y values consecutively so that they display evenly on graph 
        tempvar yId 
        egen `yId' =group(`2') 
    
        * get a unique list of y values to make labels for each 
        preserve 
        quietly duplicates drop `yId', force
        local max=_N 
         
        * add the text label for each one to the labels local 
        forval i = 1/`max' {
            local labelText = `label'[`i']
            local ylab `"`ylab'`i' "`labelText'" "'
        }
    
        * make the graph      
        summarize    
        twoway contour   `1' `yId' `3', heatmap levels(5) ///
            ylabel(`ylab',  angle(horizontal) labsize(vsmall) )     
    end
    
    use http://www.stata-press.com/data/r15/nlswork.dta, clear
    
    * keep a reasonable number of years for graphing 
    keep if inrange(year,82,88) 
    
    * randomly assign each respondent to a state so we can see how the graph labeling works
    bys idcode: gen fips=runiformint(1, 56) if _n==1
    
    bys idcode: replace fips=fips[1]
    
    * generate a longitudinal file by state
    collapse (mean) ln_wage, by(fips year) 
    
    * ssc install statastates 
    * get names for the respondent fips codes 
    statastates, fips(fips) 
    keep if _merge == 3 
    lasagna2 ln_wage fips year, label(state_name)

    Comment


    • #3
      Hi, Nick. Thanks for the reply. The preserve/restore is a ham-handed way to get a unique list of Y values so that they can be rescaled into consecutive values (which makes them display evenly) and labeled. So the data do need to be restored before the -twoway- is issued. The tempvar was being created prior to the preserve statement (i.e., in place of egen yId) so I'm not sure why it wouldn't be available after the restore.

      I've reworked this a bit to avoid the use of statastates and to pursue a more standard implementation of the value labeling, which I hope will clarify the remaining question regarding the spacing of the graph. You can see the issue to which I'm referring here.

      Code:
      capture program drop lasagna
      program define lasagna 
           
          syntax varlist(min=3 max=3) [if] [in] [, label(varname) levels(integer 5) *]
          
           display "`options'"
          
          tokenize `varlist'
          marksample touse 
          
          local yLabel: value label `2' 
          
          *number the y values consecutively so that they display evenly on graph 
          cap drop yId
          egen yId=group(`2') 
      
          * get a unique list of y values to make labels for each 
          preserve 
          
          keep if `touse' 
          duplicates drop yId, force
          local max=_N 
           
          * if there is no user-defined label defined for the Y variable, 
          * create text labels with original Y values  
          if "`yLabel'"=="" {    
              foreach i of numlist 1/`max' {
                  local labelText=`2'[`i']
                  local ylab `"`ylab'`i' "`labelText'" "'
              }
          }
          else {
              * If there's a user-defined label, assign those strings to the rescaled Y value
              tempvar textVal 
              decode `2', gen(`textVal') 
              foreach i of numlist 1/`max' {
                  local labelText=`textVal'[`i']
                  local ylab `"`ylab'`i' "`labelText'" "'
              }
          }
          * get our original data back and make the graph 
          restore 
          
          twoway contour   `1' yId `3' if `touse', heatmap levels(`levels') ///
              ylabel(`ylab',  angle(horizontal) labsize(vsmall) )     
      
          cap drop Yid    
      end
      *use http://www.stata-press.com/data/r15/nlswork.dta, clear
      *save nlswork, replace 
      
      use nlswork, clear
      
      keep if inrange(year,82,88) 
      
      bys idcode: gen fips=runiformint(1, 56) if _n==1
      
      bys idcode: replace fips=fips[1]
      
      collapse (mean) ln_wage, by(fips year) 
       
      
      label define state 1 "ALABAMA"  2 "ALASKA"  4 "ARIZONA"  5 "ARKANSAS"  6 "CALIFORNIA"  8 "COLORADO"  9 "CONNECTICUT"  10 "DELAWARE"  ///
       11 "DISTRICT OF COLUMBIA"  12 "FLORIDA"  13 "GEORGIA"  15 "HAWAII"  16 "IDAHO"  17 "ILLINOIS"  18 "INDIANA"  19 "IOWA"  20 "KANSAS" ///
       21 "KENTUCKY"  22 "LOUISIANA"  23 "MAINE"  24 "MARYLAND"  25 "MASSACHUSETTS"  26 "MICHIGAN"  27 "MINNESOTA"  28 "MISSISSIPPI"  29 "MISSOURI" ///
       30 "MONTANA"  31 "NEBRASKA"  32 "NEVADA"  33 "NEW HAMPSHIRE"  34 "NEW JERSEY"  35 "NEW MEXICO"  36 "NEW YORK"  37 "NORTH CAROLINA" ///
       38 "NORTH DAKOTA"  39 "OHIO"  40 "OKLAHOMA"  41 "OREGON"  42 "PENNSYLVANIA"  44 "RHODE ISLAND"  45 "SOUTH CAROLINA"  46 "SOUTH DAKOTA" ///
       47 "TENNESSEE"  48 "TEXAS"  49 "UTAH"  50 "VERMONT"  51 "VIRGINIA"  53 "WASHINGTON"  54 "WEST VIRGINIA"  55 "WISCONSIN"  56 "WYOMING"  
      
      label values fips state
       
      lasagna ln_wage fips year

      Comment


      • #4
        I think you're right on preserve and restore but I can't add illumination on why twoway contour doesn't see the temporary variable. On another level, I am queasy about how much mangling of the data you (seem to) have to do before you call your main command. As a user, that would put me off, but I may be misunderstanding what's happening.

        Comment

        Working...
        X