Home > Programming > Export tables to Excel

Export tables to Excel

There is a new command in Stata 13, putexcel, that allows you to easily export matrices, expressions, and stored results to an Excel file. Combining putexcel with a Stata command’s stored results allows you to create the table displayed in your Stata Results window in an Excel file.

A stored result is simply a scalar, macro, or matrix stored in memory after you run a Stata command. The two main types of stored results are e-class (for estimation commands) and r-class (for general commands). You can list a command’s stored results after it has been run by typing ereturn list (for estimation commands) and return list (for general commands). Let’s try a simple example by loading the auto dataset and running correlate on the variables foreign and mpg

. sysuse auto
(1978 Automobile Data)

. correlate foreign mpg

             |  foreign      mpg
     foreign |   1.0000
         mpg |   0.3934   1.0000

Because correlate is not an estimation command, use the return list command to see its stored results.

. return list

                  r(N) =  74
                r(rho) =  .3933974152205484

                  r(C) :  2 x 2

Now we can use putexcel to export these results to Excel. The basic syntax of putexcel is

putexcel excel_cell=(expression) … using filename [, options]

If you are working with matrices, the syntax is

putexcel excel_cell=matrix(expression) … using filename [, options]

It is easy to build the above syntax in the putexcel dialog. There is a helpful video on Youtube about the dialog here. Let’s list the matrix r(C) to see what it contains.

. matrix list r(C)

symmetric r(C)[2,2]
           foreign        mpg
foreign          1
    mpg  .39339742          1

To re-create the table in Excel, we need to export the matrix r(C) with the matrix row and column names. The command to type in your Stata Command window is

putexcel A1=matrix(r(C), names) using corr

Note that to export the matrix row and column names, we used the names option after we specifed the matrix r(C). When I open the file corr.xlsx in Excel, the table below is displayed.


Next let’s try a more involved example. Load the auto dataset, and run a tabulation on the variable foreign. Because tabulate is not an estimation command, use the return list command to see its stored results.

. sysuse auto
(1978 Automobile Data)

. tabulate foreign

   Car type |      Freq.     Percent        Cum.
   Domestic |         52       70.27       70.27
    Foreign |         22       29.73      100.00
      Total |         74      100.00

. return list

                  r(N) =  74
                  r(r) =  2

tabulate is different from most commands in Stata in that it does not automatically save all the results we need into the stored results (we will use scalar r(N)). We need to use the matcell() and matrow() options of tabulate to save the results produced by the command into two Stata matrices.

. tabulate foreign, matcell(freq) matrow(names)

   Car type |      Freq.     Percent        Cum.
   Domestic |         52       70.27       70.27
    Foreign |         22       29.73      100.00
      Total |         74      100.00

. matrix list freq

r1  52
r2  22

. matrix list names

r1   0
r2   1

The putexcel commands used to create a basic tabulation table in Excel column 1 row 1 are

putexcel A1=("Car type") B1=("Freq.") C1=("Percent") using results, replace
putexcel A2=matrix(names) B2=matrix(freq) C2=matrix(freq/r(N)) using results,

Below is the table produced in Excel by these commands.


Again this is a basic tabulation table. You probably noticed that we did not have the Cum. column or the Total row in the export table. Also our Car type column contains the numeric values (0,1), not the value lables (Domestic, Foreign) of the variable foreign, and our Percent column is not formatted correctly. To get the exact table displayed in the Results window into an Excel file takes a little programming. With a few functions and a forvalues loop, we can easily export any table produced by running the tabulate command on a numeric variable.

There are two extended macro functions, label and display, that can help us. The label function can extract the value labels for each variable, and the display function can correctly format numbers for our numeric columns. Last, we use forvalues to loop over the rows of the returned matrices to produce our final tables. Our do-file to produce the tabulate table in Excel looks like

sysuse auto
tabulate foreign, matcell(freq) matrow(names)

putexcel A1=("Car type") B1=("Freq.") C1=("Percent") D1=("Cum.") using results, replace

local rows = rowsof(names)
local row = 2
local cum_percent = 0

forvalues i = 1/`rows' {

        local val = names[`i',1]
        local val_lab : label (foreign) `val'

        local freq_val = freq[`i',1]

        local percent_val = `freq_val'/`r(N)'*100
        local percent_val : display %9.2f `percent_val'

        local cum_percent : display %9.2f (`cum_percent' + `percent_val')

        putexcel A`row'=("`val_lab'") B`row'=(`freq_val') C`row'=(`percent_val') ///
                D`row'=(`cum_percent') using results, modify
        local row = `row' + 1

putexcel A`row'=("Total") B`row'=(r(N)) C`row'=(100.00) using results, modify

The above commands produce this table in Excel:


The solution above works well for this one table, but what if we need to export the tabulation table for 100 variables to the same Excel spreadsheet? It would be very tedious to run the same do-file 100 times, each time changing the cell and row numbers. Now we could easily change our do-file into the Stata command (ado-file) called tab2xl. The syntax for our new command could be

tab2xl varname using filename, row(rownumber) col(colnumber) [replace sheet(name)]

The pseudocode of our program (file tab2xl.ado) looks like

program tab2xl
  /* parse command syntax */

  /* tabulate varname */

  /* get column letters based on starting column number passed in */

  /* write header row to filename in starting row number passed in */

  /* loop over rows of returned matrix and calculate/write values to filename */

  /* write total row to filename */

If you would like to download a working version of our tab2xl command, type

net install http://www.stata.com/users/kcrow/tab2xl

in Stata.

Categories: Programming Tags: , , , ,
  • Michael Smith

    This is exactly what I needed today! …and then I remembered I have stata 12, and was sad.

  • Harrison Startz

    It’d be awesome to be able to format Excel tables from within Stata, for example, make the first row all bold.

  • West Addison

    I second Harrison’s request. I had been hoping to use -putexcel- with the modify option to fill values into nicely formatted Excel table shells. Unfortunately, -putexcel- ignores (overwrites) the existing formatting in the Excel spreadsheet, changing the font to a default font, removing any Excel number formatting such as percentage and number of decimal places, etc. Would it be possible to add an option to -putexcel- that would keep any existing Excel formatting in place (i.e., an option that would make -putexcel- work like the Paste Special -> Values command in Excel)?

  • Kevin Crow

    We will look at adding both of the below features to putexcel in a future
    update or version of Stata.

    1) Retain a cell’s format after writing data to it
    2) Cell formatting

  • West Addison

    Excellent! That would be most welcome.

  • Ana Abreu

    Hi Kelvin,

    I need to export results from a survey estimation to excel but I have several rows to export. Therefore. I would need a loop to export all the values in a row wise manner. I have several regions and for each one i would need this stratification.

    foreach x of varlist edad1-edad11{
    svy, sub(`x’): proportion curr_smk if entidad==”25″ & area==2
    svy, sub(`x’): proportion curr_smk if entidad==”25″ & area==1
    svy, sub(`x’): proportion curr_smk if entidad==”25″ & area==2 &sexo==2
    svy, sub(`x’): proportion curr_smk if entidad==”25″ & area==2 &sexo==1
    svy, sub(`x’): proportion curr_smk if entidad==”25″ & area==1 &sexo==2
    svy, sub(`x’): proportion curr_smk if entidad==”25″ & area==1 &sexo==1

    There is a way to have a loop within putexcel command?

  • Pingback: The Stata Blog » Retaining an Excel cell’s format when using putexcel

  • Karola

    Hi I know this is not related to the post, however would anyone know how to calculate the boone indicator for competition in stata?

  • Ricardo

    Is there a way to add brackets or parenthesis when exporting standard errors via putexcel?

  • Christian

    hi kevin, i am not familiar with STATA, but I have to gain some tablulated data throught remote commands.
    Q: how can i generate XLS from the TABSTAT command?

  • Pingback: Un ejemplo sobre cómo combinar Stata y R para análisis de datos | Chanchullo Político

  • Kevin Crow

    You can use putexcel in your loop, but you will probably want to use the advanced syntax. Your do-file would look something like

    putexcel set myfile.xlsx, modify sheet(“mysheet”)
    local row = 1
    foreach x of varlist edad1-edad11{
    svy, sub(`x’) …
    putexcel A`row’ …
    local row = `row’ + 1
    svy, sub(`x’)…
    putexcel A`row’ …
    local row = `row’ + 1

  • Kevin Crow

    I don’t believe there is a command to do this in Stata, but you might try emailing tech-support@stata.com to make sure that there is not.

  • Kevin Crow

    Yes you can. You will have to do a little programming to recreate the entire table, but you can get the numbers generated in tabstat with the save option.

    . tabstat mpg for, save
    stats | mpg foreign
    mean | 21.2973 .2972973

    . return list
    r(StatTotal) : 1 x 2

    . matrix list r(StatTotal)
    mpg foreign
    mean 21.297297 .2972973

  • Kevin Crow

    You can use the : display extended macro function. For example,

    . clear
    . qui sysuse auto, clear
    . qui regress for mpg weight

    . local se : display “[" _se[mpg] “]”

    . di “`se’”

    See help extended_fcn for more help.

  • DidemG

    Hi Kevin,
    I am trying to export a correlation matrix from stata. However, the syntax gives me error “file corr.xlsx could not be saved”. I would appreciate your help.
    Many thanks,

  • Kevin Crow

    Where are you saving the file corr.xlsx? Make sure you have permission to save to the directory in question.

  • Jeef

    Using putexcel in a loop, I am trying to add data across columns. I understand how to post data down rows. My syntax was:
    local row 5
    foreach var of varlist *_high{
    sum `var’
    putexcel set “column.xls”, sheet(“summary”)modify
    local high = r(sum)
    local high : display %9.0f `high’
    putexcel H`row’=(`high’)
    local row=`row’ +1

    How can I have the data put into A1 B1 C1 etc