Using esttab (or similar)

webdoc does not provide specific tools for producing tables. However, you can use other programs such as listtex (see ideas.repec.org/c/boc/bocode/s423201.html) or esttab (see repec.org/bocode/e/estout) to write a table in HTML format and then add the result to your HTML document using webdoc append. Below is an example based on esttab. The procedure for listtex or other commands would be similar.

webdoc init, header(width(700px))

/***
<p>Table 1 shows two regression models explaining the price of cars.</p>
***/

webdoc stlog, nolog
    sysuse auto
    regress price mpg weight
    estimates store m1
    regress price mpg weight foreign turn
    estimates store m2
    esttab m1 m2 using mytable.html, replace label wide nomtitle ///
        nostar b(2) align(right) width(500) title(Table 1: A regression table)
webdoc stlog close
webdoc append mytable.html
Code
1.png

The commands computing the results and generating the table are included in a webdoc stlog, nolog section so that the Stata output of these commands will not be displayed in the HTML document.

[top]

Improved esttab table

The table written by esttab, html is very basic and not very well suited for custom formatting. A better result can be achieved by changing some of the defaults (using options such as prehead()) and adding stylesheet definitions.

Wide format

Here is a basic example for a regression table in wide format (t-stats beside coefficients):

webdoc init, header(width(700px))

/***
<style>
.esttab-wide {
    width: 100%;
    border-spacing: 0;
}
.esttab-wide > caption {
    text-align: left;
    color: #808080;
    padding-top: 5px;
    padding-bottom: 5px;
}
.esttab-wide > thead > tr > td,
.esttab-wide > tbody > tr > td,
.esttab-wide > tfoot > tr > td {
  vertical-align: top;
  padding: 5px 8px 5px 8px;
}
.esttab-wide > thead > tr > td:first-child,
.esttab-wide > tbody > tr > td:first-child,
.esttab-wide > tfoot > tr > td:first-child {
    font-weight: bold;
    text-align: left;
}
.esttab-wide > thead > tr > td:not(:first-child),
.esttab-wide > tbody > tr > td:not(:first-child),
.esttab-wide > tfoot > tr > td:not(:first-child) {
    text-align: right;
    position: relative;
}
.esttab-wide > thead > tr > td {
    font-weight: bold;
}
.esttab-wide > thead > tr:first-child > td:not(:first-child) {
    border-bottom: 1px solid #dddddd;
}
.esttab-wide > tbody > tr > td > sup {
    position: absolute;
}
.esttab-wide > thead > tr:first-child > td {
    text-align: center;
    border-top: 2px solid #dddddd;
}
.esttab-wide > thead > tr:last-child > td {
    border-bottom: 1px solid #dddddd;
}
.esttab-wide > tfoot > tr:first-child > td {
    border-top: 1px solid #dddddd;
}
.esttab-wide > tfoot > tr:last-child > td {
    font-weight: normal;
    font-size: 85%;
    border-top: 2px solid #dddddd;
}
</style>
***/

webdoc stlog, nolog
    sysuse auto
    regress price mpg weight
    estimates store m1
    regress price mpg weight foreign turn
    estimates store m2
    regress price mpg weight foreign turn i.rep78
    estimates store m3
    esttab m1 m2 m3 using mytable.html, replace label wide nonumbers ///
        b(2) title(Table 1: A regression table) dropped("(ref.)") ///
        mlabels("Model 1" "Model 2" "Model 3", prefix(<colspan="@span">) span) ///
        substitute("td><colspan" "td colspan") collabels("Coef." "(t-value)") ///
        prehead(<table class="esttab-wide"><caption>@title</caption><thead>) ///
        posthead(</thead><tbody>) prefoot(</tbody><tfoot>) ///
        postfoot(<tr><td colspan="@span">@starlegend</td></tfoot></table>)
webdoc stlog close
webdoc append mytable.html
Code
2.png
[top]

Long format

And here is an example for a table in long format (t-stats below coefficients):

webdoc init, header(width(700px))

/***
<style>
.esttab-long {
    width: 100%;
    border-spacing: 0;
}
.esttab-long > caption {
    text-align: left;
    color: #808080;
    padding-top: 5px;
    padding-bottom: 5px;
}
.esttab-long > thead > tr > td,
.esttab-long > tbody > tr > td,
.esttab-long > tfoot > tr > td {
  vertical-align: top;
  padding: 5px 8px 5px 8px;
}
.esttab-long > thead > tr > td:first-child,
.esttab-long > tbody > tr > td:first-child,
.esttab-long > tfoot > tr > td:first-child {
    font-weight: bold;
    text-align: left;
}
.esttab-long > thead > tr > td:not(:first-child),
.esttab-long > tbody > tr > td:not(:first-child),
.esttab-long > tfoot > tr > td:not(:first-child) {
    text-align: right;
    position: relative;
}
.esttab-long > thead > tr > td:last-child,
.esttab-long > tbody > tr > td:last-child,
.esttab-long > tfoot > tr > td:last-child {
    padding-right: 20px;
}
.esttab-long > thead > tr > td {
    font-weight: bold;
}
.esttab-long > tbody > tr > td > sup {
    position: absolute;
}
.esttab-long > thead > tr:first-child > td {
    border-top: 2px solid #dddddd;
}
.esttab-long > thead > tr:last-child > td {
    border-bottom: 1px solid #dddddd;
}
.esttab-long > tfoot > tr:first-child > td {
    border-top: 1px solid #dddddd;
}
.esttab-long > tfoot > tr:last-child > td {
    font-weight: normal;
    font-size: 85%;
    border-top: 2px solid #dddddd;
}
</style>
***/

webdoc stlog, nolog
    sysuse auto
    regress price mpg 
    estimates store m1
    regress price mpg weight
    estimates store m2
    regress price mpg weight foreign
    estimates store m3
    regress price mpg weight foreign turn
    estimates store m4
    regress price mpg weight foreign turn i.rep78
    estimates store m5
    esttab m1 m2 m3 m4 m5 using mytable.html, ///
        replace label nonumbers nogap ar2 onecell b(2) dropped(" ") ///
        title(Table 1: A regression table (t statistics in parentheses)) ///
        mlabels("Model 1" "Model 2" "Model 3" "Model 4" "Model 5") ///
        coeflabels(1.rep78 "Repair record (ref=1)" 2.rep78 "– level 2" ///
            3.rep78 "– level 3" 4.rep78 "– level 4" 5.rep78 "– level 5") ///
        prehead(<table class="esttab-long"><caption>@title</caption><thead>) /// 
        posthead(</thead><tbody>) prefoot(</tbody><tfoot>) ///
        postfoot(<tr><td colspan="@span">@starlegend</td></tfoot></table>)
webdoc stlog close
webdoc append mytable.html
Code
3.png
[top]

Creating custom tables

Using webdoc write/webdoc put

As an alternative to using one of the existing tabulation programs, you can also create a custom table using webdoc write and webdoc put. Here is a simple example, in which a table is created from the contents of a matrix:

webdoc init, header(width(700px))

/***
<style>
table { width: 100%; border-spacing: 0; }
table caption { text-align: left; color: #808080; padding-top: 8px; }
th, td { text-align: left; vertical-align: top; padding: 8px; }
th { font-weight: bold; }
thead > tr:last-child > th { border-bottom: 2px solid #dddddd; }
tbody > tr:not(:last-child) > th,
tbody > tr:not(:last-child) > td { border-bottom: 1px solid #dddddd; }
</style>
***/

matrix M = (1, 2) \ (3, 4)
matrix colnames M = "column 1" "column 2"
matrix rownames M = "row 1" "row 2"

local coln: colnames M, quoted
local c = colsof(M)
local rown: rownames M, quoted
webdoc put <table>
webdoc put <caption>Table 1: A simple 2-by-2 matrix</caption>
webdoc write <thead><tr><th></th>
foreach col of local coln {
    webdoc write <th>`col'</th>
}
webdoc put </thead>
webdoc put <tbody>
local i 0
foreach row of local rown {
    local ++i
    webdoc write <tr><th>`row'</th>
    forv j = 1/`c' {
        local value: display M[`i', `j']
        webdoc write <td>`value'</td>
    }
    webdoc put </tr>
}
webdoc put </tbody></table>
Code
4.png

Of course it is always a good idea to turn code like this into a little program so you can reuse it, as in the following example:

program mytable
    syntax name(name=M) [, Title(str) Format(str) ]
    if "`format'"=="" local format "%9.0g"
    local coln: colnames `M', quoted
    local c = colsof(`M')
    local rown: rownames `M', quoted
    webdoc put <table class="table">
    if `"`title'"'!="" {
         webdoc put <caption>`title'</caption>
    }
    webdoc write <thead><tr><th></th>
    foreach col of local coln {
        webdoc write <th>`col'</th>
    }
    webdoc put </thead>
    webdoc put <tbody>
    local i 0
    foreach row of local rown {
        local ++i
        webdoc write <tr><th>`row'</th>
        forv j = 1/`c' {
            local value: display `format' `M'[`i', `j']
            webdoc write <td>`value'</td>
        }
        webdoc put </tr>
    }
    webdoc put </tbody></table>
end

webdoc init, header(width(700px))

/***
<style>
table { width: 100%; border-spacing: 0; }
table caption { text-align: left; color: #808080; padding-top: 8px; }
th, td { text-align: left; vertical-align: top; padding: 8px; }
th { font-weight: bold; }
thead > tr:last-child > th { border-bottom: 2px solid #dddddd; }
tbody > tr:not(:last-child) > th,
tbody > tr:not(:last-child) > td { border-bottom: 1px solid #dddddd; }
</style>
***/

matrix M = matuniform(4,4)
mytable M, title(Table 1: A random 4-by-4 table)

matrix M = matuniform(6,8)
mytable M, title(Table 2: A random 6-by-8 table) format(%9.4f)
Code
5.png
[top]

Using the file command

Note that webdoc write and webdoc put directly write to the main output document, so that the results you want to tabulate have to be computed each time you process your do-file (that is, the nodo option is of no use). It might thus be better write to an external file using the file command (see help file) and then include the file using the webdoc append command. Example:

// program to tabulate results from r(table) returned by estimation commands
program myregtab
    tempname M
    matrix `M' = r(table)'
    matrix `M' = `M'[1..., 1..6]
    local format "%9.0g %9.0g %9.2f %9.3f %9.0g %9.0g"
    local c = colsof(`M')
    local rown: rownames `M', quoted
    tempname fh
    file open `fh' using ${WebDoc_stname}.html, write replace
    file write `fh' `"<table class="table">"' _n
    file write `fh' `"<caption>@title</caption>"' _n
    file write `fh' `"<thead><tr><th></th>"'
    foreach col in "Coef." "Std. Err." "t" "P&gt;|t|" {
        file write `fh' `"<th>`col'</th>"'
    }
    file write `fh' `"<th colspan="2">[95% Conf. Interval]</th>"'
    file write `fh' `"</thead>"' _n
    file write `fh' `"<tbody>"' _n
    local i 0
    foreach row of local rown {
        local ++i
        file write `fh' `"<tr><th>`row'</th>"'
        forv j = 1/`c' {
            local fmt: word `j' of `format'
            local value: display `fmt' `M'[`i', `j']
            file write `fh' `"<td>`value'</td>"'
        }
        file write `fh' `"</tr>"' _n
    }
    file write `fh' `"</tbody></table>"'
end

// initialize output document
webdoc init, header(width(700px))

// table styling
/***
<style>
table { width: 100%; border-spacing: 0; }
table caption { text-align: left; color: #808080; padding-top: 8px; }
th, td { text-align: right; vertical-align: top; padding: 8px; }
th { font-weight: bold; }
tbody th { text-align:left; }
thead > tr:last-child > th { border-bottom: 2px solid #dddddd; }
tbody > tr:not(:last-child) > th,
tbody > tr:not(:last-child) > td { border-bottom: 1px solid #dddddd; }
</style>
***/

// compute and tabulate results
webdoc stlog, nolog
    sysuse auto
    regress price weight foreign mpg
    myregtab
webdoc stlog close
webdoc append `s(name)'.html, substitute(@title "Table 1: A regression table")
Code
6.png

This way, you can apply the nodo option to rerun the do-file (i.e. typing webdoc do filename, nodo) without having to redo the computations (e.g., if you just want to change the title of the regression table). The name of the external file holding the table is determined by ${WebDoc_stname}.html, where WebDoc_stname is a global macro maintained by webdoc stlog containing the name (and relative path) of the current Stata log section (see the remark on global macros in the help file).