etable
: new features in
fixest
0.10.2vignettes/etable_new_features.Rmd
etable_new_features.Rmd
This document illustrates the new features of etable
,
the tool to export estimation tables in fixest
, in version
0.10.2.
Version 0.10.2 comes with majors changes in the Latex engine of
etable
. The most notable one is the ability to transform
Latex tables into PNG files and display them either in RStudio’s viewer,
either directly in HTML markdown documents (like all the tables in this
document).
However, it requires that the following software are installed and work properly on the user-side:
tinytex
(very likely already installed),pdftools
.Now we’re good to start. Let’s first define a global dictionary: it
will rename the variables and will also include pre-defined notes that
can be fetched from etable
.
library(fixest)
# Let's define a dictionary and set it globally.
# We also define notes, not just variable names.
# (The function 'dsb()' is like 'glue()' and is not important here.)
dict = c("(Intercept)" = "Constant",
Petal.Length = "Petal length", Petal.Width = "Petal width",
Sepal.Length = "Sepal length", Sepal.Width = "Sepal width",
note1 = dsb("*Notes*: This is a note that illustrates how to access notes ",
"from the dictionary."),
source = "*Sources*: Somewhere from the net.")
setFixest_dict(dict)
Then let’s define a few global options for the table. The philosophy
is to set all the style components common across tables only once and
for all thanks to setFixest_etable
. The goal is, to
increase maintainability, to use only table-specific arguments in later
calls to etable
. Hence, if the table style has to be
changed, only one modification is needed (in
setFixest_etable
), and etable
calls stay the
same.
# The style of the table
my_style = style.tex("aer", model.format = "(i)")
# markdown = TRUE is only useful in Rmarkdown documents
setFixest_etable(style.tex = my_style, markdown = TRUE, page.width = "a4")
The arguments markdown
and page.width
will
be explained in the next section. And now the estimation we’ll use
throughout this document.
One major improvement is the ability to generate PNG snapshots of
Latex tables (I wish to thank Or Avishay-Rizi for the suggestion!). It
works very intuitively: first a standalone Latex document is compiled to
generate a PDF containing only the table, then imagemagick is used to
convert the PDF into a PNG file. Note that image generation is not
instantaneous because of the Latex compilation (but output can be
cached, as explained later). These images are then accessible with the
arguments view
and markdown
.
view
In any call of etable
(i.e. tex = TRUE
is
not required), on can use view = TRUE
to display the table
snapshot in Rstudio’s viewer. The table will fit the viewer’s window,
being as large as possible without overflowing horizontally nor
vertically.
This feature is, ironically, very hard to display in this document
since there’s no viewer: so to see it at work, you should try it! Using
the current example, just run etable(est, view = TRUE)
.
Note that if the same tables are to be displayed several times, it
can be useful to cache the PNG outputs to avoid the compilation
run-time. To enable caching, use
setFixest_etable(view.cache = TRUE)
. The images are then
saved in a temporary directory that the algorithm tries to find even
across sessions – hence it enables long-term caching.
markdown
This is a peculiar option that works only within
Rmarkdown
documents and is ignored otherwise. If
markdown = TRUE
the output becomes always a Latex table,
even when tex = FALSE
(default). Second, and most
importantly, the output within the Rmarkdown
document
becomes contingent to the type of file generated. If the document is to
be a PDF, then the code of a regular Latex table is returned.
If the document is not a PDF (especially if it is an
HTML file), then:
images/etable/
, so that successive calls don’t need to
re-generate the PNGs (i.e. this is caching),<img>
tag,<img>
tag is inserted in a
<div>
container of class etable
.This ensures that the tables are the same whether the output is a PDF
or an HTML document. Since the table is embedded in a
<div>
container, you can even add some custom CSS to
further customize how it looks.
All the images of the tables in this document are generated using
markdown = TRUE
, set globally in
setFixest_etable
.
page.width
As mentioned, the tables are embedded in a standalone Latex document. The main consequence of this is that the table fits the PDF file completely, without any margin on any side. This means that whatever the width of the table (be it two or twenty columns), it will always take 100% of the width of the PDF.
While this property is fine when displaying on the viewer (since we usually want to see the full table), it makes the tables look odd and inconsistent in an HTML document. Indeed, since tables of two columns will take the same width as table of twenty columns, the font will look extra large for the former and extra small for the latter. That’s not something we usually want in a document.
Hence, here comes the page.width
argument. This argument
sets the width and side margins of the page in which will be inserted
the table. The goal of this argument is to mimic the placement of the
table in a real PDF document (i.e. in your article). This
ensures that the PNG will look as in the PDF. For instance,
page.width = "a4"
will set an A4 page width and 2cm side
margins on both sides. This argument can be customized at will:
e.g. 8.5in, 1.1in
will lead to a page width of 8.5 inches
with 1.1 inch side margins (the only constraint is that the unit of the
width should be the same as the unit of the margin).
When page.width
is set up, all tables in an HTML
document will be consistent: the font will be the same across tables. On
top of that, it also enables a couple of specific features. First, if
the table is too narrow, you can use a tabularx table (with the
argument tabluar
) and the table will be as large as the
“text” width (not the HTML text but the hypothetical PDF text). Second,
if the table overflows, you can adjust it with the argument
adjustbox
to make it fit the text width.
makecell
support
Now almost any user-added text supports markdown markup for
italics/bold/bold-italics with *
, **
and
***
. Further, there is native support for
makecell
: simply using "\n"
enables it. Here’s
an example:
etable(est, headers = .("\n\n Short header" = 2, "*Very* \n **long** \n ***header***" = 2))
There is native support for the Latex package
threeparttable
. This option can be set via the function
style.tex()
. Further (and this is also new), you can access
notes via the global dictionary to avoid repetitions:
etable(est,
style.tex = style.tex(tpt = TRUE, notes.tpt.intro = "\\footnotesize"),
notes = c("note1", "source"))
The table notes now are adjusted to the table width thanks to
threeparttable
and the notes are accessed directly with
their keys. The argument notes.tpt.intro
inserts Latex code
right before the first \\item
of threeparttable: in this
case, it sets the font to footnotesize
.
In general, it is advised to set the value of tpt
and
the notes.tpt.intro
globally. Then if one wants to change
the value of notes.tpt.intro
, instead of typing
style.tex = style.tex(notes.tpt.intro = "stuff")
, the first
element of notes
will replace notes.tpt.intro
if it starts with an "@"
:
# Setting up tpt globally
my_style = style.tex(tpt = TRUE,
notes.tpt.intro = "\\footnotesize")
setFixest_etable(style.tex = my_style)
# Below is identical to:
# etable(est,
# style.tex = style.tex(notes.tpt.intro = "\\Large"),
# notes = "These notes are large.")
etable(est, notes = c("@\\Large", "These notes are large."))
Now there is native support for the Latex package
adjustbox
. This nests the table into an
adjustbox
environment which will resize the image of the
table at the appropriate dimensions, as provided by the user. This is
especially useful for tables that overflow but can also be used to force
a small table to fit a particular size.
By default if adjustbox = TRUE
, the
adjustbox
environment is created with the options
width = 1\\textwidth, center
. This argument can be equal to
a number, in which case it will be treated as the desired text width.
Otherwise it accepts any character string.
Let’s have an example with a large table that would otherwise overflow:
# mvsw == 'multiverse' stepwise (thanks to Resul Umit's suggestion)
est_many = feols(.[nm[1]] ~ mvsw(.[, nm[2:4]]), iris)
etable(est_many, adjustbox = 1.1)
Highlighting coefficients is often very useful, especially in presentations. There are now three main ways, natively implemented, to highlight the coefficients:
The first two can be accessed via the highlight
argument. The last is implemented in the coef.style
argument.
By default, the highlight
argument superimposes a frame
around the coefficients of interest. This is done thanks to some
tickz
magic that I barely understand found in tex
stack exchange.
Anyway, back to the argument. The syntax is
"options" = "coefficients location"
. The coefficient
location can be expressed in several ways:
Petal.L
will select the Petal.Length
row.@
and column ranges:
in the coefficient row, only selects the given columns. Ex:
Petal.L@1,3-4
will select, in the row
Petal.Length
, the columns 1, 3 and 4.c("Petal.L@2", "Petal.W@3")
will select a range from the second column of Petal.Length
to the third column of Petal.Width
.Let’s have an example illustrating the three ways to select the
coefficients and some options. We also increase the row heights with
arraystretch
to facilitate the highlighting:
etable(est, arraystretch = 1.5,
highlight = .("Sepal@1",
"cyan4, square" = "Petal.L@3-4",
"thick5, sep8, darkgreen!90, se" = "Petal.W"))