Home  /  Resources & support  /  FAQs  /  Stata 6: Using while loops when the by command is not an option
Note: This FAQ is for users of Stata 6. It is not relevant for more recent versions.

Stata 6: What do I do if the command that I need cannot be used with by?

Title   Stata 6: Using while loops when the by command is not an option
Author Jeremy B. Wernow, StataCorp

There are several commands in Stata that will not allow the by command as an option. Two examples are the tab1 command and the graph commands with the saving() option. One way to get around this feature is to put the command you want to execute in a while loop:

 . sysuse auto, clear

 . sort rep78

 . by rep78: tab1 mpg price

 -> rep78=       1  
 request may not be combined with by
 (error occurred while loading tab1.ado)
 r(190);

That does not work. We know, however, that rep78 has values between 1 and 5, so let us try a while loop in a do-file:

 local i = 1
 while `i' <=5 {
      tab1 mpg price if rep78 == `i'
      local i = `i' + 1
 }

Here is the output from executing this file:

 . local i = 1

 . while `i' <=5 {
   2.      tab1 mpg price if rep78 == `i'
   3.      local i = `i' + 1
   4. }

 -> tabulation of mpg if rep78 == 1 

     Mileage |
       (mpg) |      Freq.     Percent        Cum.
 ------------+-----------------------------------
          18 |          1       50.00       50.00
          24 |          1       50.00      100.00
 ------------+-----------------------------------
       Total |          2      100.00

 -> tabulation of price if rep78 == 1 
 
       Price |      Freq.     Percent        Cum.
 ------------+-----------------------------------
       4,195 |          1       50.00       50.00
       4,934 |          1       50.00      100.00
 ------------+-----------------------------------
       Total |          2      100.00

 -> tabulation of mpg if rep78 == 2 

     Mileage |
       (mpg) |      Freq.     Percent        Cum.
 ------------+-----------------------------------
          14 |          1       12.50       12.50
          16 |          1       12.50       25.00

 ...

What if rep78 has missing values? In this case, you can use the egen command to create a new variable that categorizes each value in rep78.

Here is the modified do-file:

 local i = 1
 egen y = group(rep78), missing
 while `i' <=6 {
      tab1 mpg price if y == `i'
      local i = `i' + 1
 }

By using the missing option with the egen command, the missing values of rep78 will be coded with a value of 6 (remembering that rep78 has values of 1 to 5). Note that the output from this do-file will now contain tabulations for mpg and price for the missing values of rep78 as well.

...output omitted...

 -> tabulation of mpg if y == 6 

     Mileage |
       (mpg) |      Freq.     Percent        Cum.
 ------------+-----------------------------------
          14 |          1       20.00       20.00
          19 |          1       20.00       40.00
          22 |          1       20.00       60.00
          26 |          2       40.00      100.00
 ------------+-----------------------------------
       Total |          5      100.00

 -> tabulation of price if y == 6 

       Price |      Freq.     Percent        Cum.
 ------------+-----------------------------------
       3,799 |          1       20.00       20.00
       4,424 |          1       20.00       40.00
       4,453 |          1       20.00       60.00
       6,486 |          1       20.00       80.00
      12,990 |          1       20.00      100.00
 ------------+-----------------------------------
       Total |          5      100.00

Now let us move on to a more difficult example. A user recently wanted to use the by command with the graph command and the saving() option.

 .  by rep78: graph mpg price

 -> rep78=       1  
 -> rep78=       2  
 -> rep78=       3  
 -> rep78=       4  
 -> rep78=       5  
 -> rep78=       .  

 .  by rep78: graph mpg price, saving(graph.wmf)

 -> rep78=       1  
 request may not be combined with by
 r(190);

by cannot be used with the graph, saving() option because of naming issues (how would you name each individual graph?). This can be solved with another do-file:

 local i = 1
 egen y = group(rep78), missing
 while `i' <=6 {
      graph mpg price if y == `i', saving(graph`i',replace)      
      local i = `i' + 1
 }

The output of this do-file is

 . local i = 1

 . egen y = group(rep78), missing
 
 . while `i' <=6 {
   2.      graph mpg price if y == `i', saving(graph`i',replace)      
   3.      local i = `i' + 1
   4. }
 (Note: file graph1.gph not found)
 (Note: file graph2.gph not found)
 (Note: file graph3.gph not found)
 (Note: file graph4.gph not found)
 (Note: file graph5.gph not found)
 (Note: file graph6.gph not found)

 . 
 end of do-file

That worked just as we wanted.

There is a lot that you can do with this concept. As a final and even more complex example, the same user also said he wanted to use the by() option with the saving() option, graphing those against another variable, and he needed this done for a list of variables. This probably sounds confusing at first (and it was). Essentially, we needed to

by var1: graph var2 var3, saving(graph) by(var4)

Several different variables were to be used in place of var3.

The solution is to use a for command inside a while loop. Here is an example using the auto dataset:

 local i = 1
 egen y = group(rep78), missing
 while `i' <=6 {
    sort y foreign
    for var mpg length weight: graph price X if y == `i', /*
       */   by(foreign) \ gphprint, saving("priceX`i'.wmf",replace)
    local i = `i' + 1
 }

This results in

 . local i = 1

 .         egen y = group(rep78), missing

 .         while `i' <=6 {
   2.           sort y foreign
   3.           for var mpg length weight: graph price X if y == `i', /*
                */   by(foreign) \ gphprint, saving("priceX`i'.wmf",replace)
   4.           local i = `i' + 1
   5.         }
 
 ->  graph price mpg if y == 1, by(foreign)
 
 ->  gphprint, saving("pricempg1.wmf",replace)

 ->  graph price length if y == 1, by(foreign)

 ->  gphprint, saving("pricelength1.wmf",replace)

 ->  graph price weight if y == 1, by(foreign)

 ->  gphprint, saving("priceweight1.wmf",replace)

 ->  graph price mpg if y == 2, by(foreign)

 ->  gphprint, saving("pricempg2.wmf",replace)

 ->  graph price length if y == 2, by(foreign)

 ->  gphprint, saving("pricelength2.wmf",replace)

 ->  graph price weight if y == 2, by(foreign)

 ->  gphprint, saving("priceweight2.wmf",replace)

 ...

 end of do-file