epitable.Rmd
epitable contains some example data on trade balances:
library(epitable)
tradebalance
#> # A tibble: 12 x 7
#> industry import_level import_share export_level export_share
#> <chr> <dbl> <dbl> <dbl> <dbl>
#> 1 Total c… 403. 1 111. 1
#> 2 Agricul… 2.3 0.006 17.3 0.156
#> 3 Mining -0.1 0 8.5 0.077
#> 4 Oil and… 0.1 0 6.8 0.062
#> 5 Mineral… 0.1 0 1.7 0.015
#> 6 Manufac… 401. 0.994 80 0.72
#> 7 Nondura… 44.1 0.109 3.5 0.032
#> 8 Food 3.2 0.008 2.5 0.023
#> 9 Beverag… 0.1 0 0.2 0.002
#> 10 Textile… 11.8 0.0290 0.4 0.004
#> 11 Apparel 20.7 0.051 0.1 0.001
#> 12 Leather… 8.3 0.02 0.3 0.003
#> # … with 2 more variables: balance_level <dbl>, balance_share <dbl>
Here is the simplest use of epitable:
epitable(tradebalance, rownamesvar = industry)
import_level | import_share | export_level | export_share | balance_level | balance_share | |
---|---|---|---|---|---|---|
Total change | 403.2 | 1 | 111.1 | 1 | -292.1 | 1 |
Agriculture, forestry, fishing, and hunting | 2.3 | 0.006 | 17.3 | 0.156 | 15 | -0.051 |
Mining | -0.1 | 0 | 8.5 | 0.077 | 8.6 | -0.03 |
Oil and gas | 0.1 | 0 | 6.8 | 0.062 | 6.8 | -0.023 |
Minerals and ores | 0.1 | 0 | 1.7 | 0.015 | 1.6 | -0.005 |
Manufacturing | 400.8 | 0.994 | 80 | 0.72 | -320.8 | 1.098 |
Nondurable goods | 44.1 | 0.109 | 3.5 | 0.032 | -40.6 | 0.139 |
Food | 3.2 | 0.008 | 2.5 | 0.023 | -0.6 | 0.002 |
Beverage and tobacco products | 0.1 | 0 | 0.2 | 0.002 | 0.1 | 0 |
Textile mills and textile product mills | 11.8 | 0.029 | 0.4 | 0.004 | -11.4 | 0.039 |
Apparel | 20.7 | 0.051 | 0.1 | 0.001 | -20.7 | 0.071 |
Leather and allied products | 8.3 | 0.02 | 0.3 | 0.003 | -7.9 | 0.027 |
Note that you must specify the row names, either as a variable in the above, or as vector:
library(dplyr)
myrownames <- paste(c("My row"),seq(1:12))
tradebalance %>% select(-industry) %>% epitable(rownames = myrownames)
import_level | import_share | export_level | export_share | balance_level | balance_share | |
---|---|---|---|---|---|---|
My row 1 | 403.2 | 1 | 111.1 | 1 | -292.1 | 1 |
My row 2 | 2.3 | 0.006 | 17.3 | 0.156 | 15 | -0.051 |
My row 3 | -0.1 | 0 | 8.5 | 0.077 | 8.6 | -0.03 |
My row 4 | 0.1 | 0 | 6.8 | 0.062 | 6.8 | -0.023 |
My row 5 | 0.1 | 0 | 1.7 | 0.015 | 1.6 | -0.005 |
My row 6 | 400.8 | 0.994 | 80 | 0.72 | -320.8 | 1.098 |
My row 7 | 44.1 | 0.109 | 3.5 | 0.032 | -40.6 | 0.139 |
My row 8 | 3.2 | 0.008 | 2.5 | 0.023 | -0.6 | 0.002 |
My row 9 | 0.1 | 0 | 0.2 | 0.002 | 0.1 | 0 |
My row 10 | 11.8 | 0.029 | 0.4 | 0.004 | -11.4 | 0.039 |
My row 11 | 20.7 | 0.051 | 0.1 | 0.001 | -20.7 | 0.071 |
My row 12 | 8.3 | 0.02 | 0.3 | 0.003 | -7.9 | 0.027 |
As you’ve noticed, by default epitable’s output shows up in the RStudio viewer. You can also write the table snippet to a file:
epitable(tradebalance, rownamesvar=industry, file = "mytable.html")
That file will only contain the snippet of HTML that is the table. To write a fully self-contained web page, use the selfcontained
option:
epitable(tradebalance, rownamesvar=industry, file = "mytable.html", selfcontained=TRUE)
To display the raw HTML of the table snippet in the console, try
print(epitable(tradebalance, rownamesvar=industry), useViewer=FALSE)
#> <table>
#>
#> <thead>
#> <tr><th scope="col"></th> <th scope="col" style="text-align: right;" > import_level </th> <th scope="col" style="text-align: right;" > import_share </th> <th scope="col" style="text-align: right;" > export_level </th> <th scope="col" style="text-align: right;" > export_share </th> <th scope="col" style="text-align: right;" > balance_level </th> <th scope="col" style="text-align: right;" > balance_share </th></tr>
#> </thead>
#>
#> <tbody>
#> <tr>
#> <th style="min-width:12em;" scope="row">Total change</th>
#> <td style="font-variant-numeric: tabular-nums; text-align: right;" > 403.2 </td>
...
An easy way to format decimal points, percent signs, etc., is to use the scales package, which transforms columns of your dataset into character strings:
library(scales)
tradebalance_fmt <- tradebalance %>%
mutate_at(vars(ends_with("level")), ~number(.,accuracy=0.1, big.mark=",")) %>%
mutate_at(vars(ends_with("share")), ~percent(.,accuracy=0.1))
epitable(tradebalance_fmt, rownamesvar=industry)
import_level | import_share | export_level | export_share | balance_level | balance_share | |
---|---|---|---|---|---|---|
Total change | 403.2 | 100.0% | 111.1 | 100.0% | -292.1 | 100.0% |
Agriculture, forestry, fishing, and hunting | 2.3 | 0.6% | 17.3 | 15.6% | 15.0 | -5.1% |
Mining | -0.1 | 0.0% | 8.5 | 7.7% | 8.6 | -3.0% |
Oil and gas | 0.1 | 0.0% | 6.8 | 6.2% | 6.8 | -2.3% |
Minerals and ores | 0.1 | 0.0% | 1.7 | 1.5% | 1.6 | -0.5% |
Manufacturing | 400.8 | 99.4% | 80.0 | 72.0% | -320.8 | 109.8% |
Nondurable goods | 44.1 | 10.9% | 3.5 | 3.2% | -40.6 | 13.9% |
Food | 3.2 | 0.8% | 2.5 | 2.3% | -0.6 | 0.2% |
Beverage and tobacco products | 0.1 | 0.0% | 0.2 | 0.2% | 0.1 | 0.0% |
Textile mills and textile product mills | 11.8 | 2.9% | 0.4 | 0.4% | -11.4 | 3.9% |
Apparel | 20.7 | 5.1% | 0.1 | 0.1% | -20.7 | 7.1% |
Leather and allied products | 8.3 | 2.0% | 0.3 | 0.3% | -7.9 | 2.7% |
Row name indendation is handled by the rowlevels option:
import_level | import_share | export_level | export_share | balance_level | balance_share | |
---|---|---|---|---|---|---|
Total change | 403.2 | 100.0% | 111.1 | 100.0% | -292.1 | 100.0% |
Agriculture, forestry, fishing, and hunting | 2.3 | 0.6% | 17.3 | 15.6% | 15.0 | -5.1% |
Mining | -0.1 | 0.0% | 8.5 | 7.7% | 8.6 | -3.0% |
Oil and gas | 0.1 | 0.0% | 6.8 | 6.2% | 6.8 | -2.3% |
Minerals and ores | 0.1 | 0.0% | 1.7 | 1.5% | 1.6 | -0.5% |
Manufacturing | 400.8 | 99.4% | 80.0 | 72.0% | -320.8 | 109.8% |
Nondurable goods | 44.1 | 10.9% | 3.5 | 3.2% | -40.6 | 13.9% |
Food | 3.2 | 0.8% | 2.5 | 2.3% | -0.6 | 0.2% |
Beverage and tobacco products | 0.1 | 0.0% | 0.2 | 0.2% | 0.1 | 0.0% |
Textile mills and textile product mills | 11.8 | 2.9% | 0.4 | 0.4% | -11.4 | 3.9% |
Apparel | 20.7 | 5.1% | 0.1 | 0.1% | -20.7 | 7.1% |
Leather and allied products | 8.3 | 2.0% | 0.3 | 0.3% | -7.9 | 2.7% |
Here is an example of how you might do this a little less randomly:
thelevels <- tradebalance_fmt %>%
mutate(level = 3) %>%
mutate(level = ifelse(grepl("Total change|Agriculture, forestry|Mining|Manufacturing", .$industry), 1, level)) %>%
mutate(level = ifelse(grepl("Oil and gas|Minerals and ores|Nondurable goods|Industrial supplies", .$industry), 2, level)) %>%
select(level) %>%
pull()
epitable(tradebalance_fmt, rownamesvar=industry, rowlevels=thelevels)
import_level | import_share | export_level | export_share | balance_level | balance_share | |
---|---|---|---|---|---|---|
Total change | 403.2 | 100.0% | 111.1 | 100.0% | -292.1 | 100.0% |
Agriculture, forestry, fishing, and hunting | 2.3 | 0.6% | 17.3 | 15.6% | 15.0 | -5.1% |
Mining | -0.1 | 0.0% | 8.5 | 7.7% | 8.6 | -3.0% |
Oil and gas | 0.1 | 0.0% | 6.8 | 6.2% | 6.8 | -2.3% |
Minerals and ores | 0.1 | 0.0% | 1.7 | 1.5% | 1.6 | -0.5% |
Manufacturing | 400.8 | 99.4% | 80.0 | 72.0% | -320.8 | 109.8% |
Nondurable goods | 44.1 | 10.9% | 3.5 | 3.2% | -40.6 | 13.9% |
Food | 3.2 | 0.8% | 2.5 | 2.3% | -0.6 | 0.2% |
Beverage and tobacco products | 0.1 | 0.0% | 0.2 | 0.2% | 0.1 | 0.0% |
Textile mills and textile product mills | 11.8 | 2.9% | 0.4 | 0.4% | -11.4 | 3.9% |
Apparel | 20.7 | 5.1% | 0.1 | 0.1% | -20.7 | 7.1% |
Leather and allied products | 8.3 | 2.0% | 0.3 | 0.3% | -7.9 | 2.7% |
Use more descriptive column names:
epitable(tradebalance_fmt,
rownamesvar=industry,
rowlevels=thelevels,
colnames=c("Import levels",
"Import shares",
"Export levels",
"Export shares",
"Trade balance levels",
"Trade balance shares")
)
Import levels | Import shares | Export levels | Export shares | Trade balance levels | Trade balance shares | |
---|---|---|---|---|---|---|
Total change | 403.2 | 100.0% | 111.1 | 100.0% | -292.1 | 100.0% |
Agriculture, forestry, fishing, and hunting | 2.3 | 0.6% | 17.3 | 15.6% | 15.0 | -5.1% |
Mining | -0.1 | 0.0% | 8.5 | 7.7% | 8.6 | -3.0% |
Oil and gas | 0.1 | 0.0% | 6.8 | 6.2% | 6.8 | -2.3% |
Minerals and ores | 0.1 | 0.0% | 1.7 | 1.5% | 1.6 | -0.5% |
Manufacturing | 400.8 | 99.4% | 80.0 | 72.0% | -320.8 | 109.8% |
Nondurable goods | 44.1 | 10.9% | 3.5 | 3.2% | -40.6 | 13.9% |
Food | 3.2 | 0.8% | 2.5 | 2.3% | -0.6 | 0.2% |
Beverage and tobacco products | 0.1 | 0.0% | 0.2 | 0.2% | 0.1 | 0.0% |
Textile mills and textile product mills | 11.8 | 2.9% | 0.4 | 0.4% | -11.4 | 3.9% |
Apparel | 20.7 | 5.1% | 0.1 | 0.1% | -20.7 | 7.1% |
Leather and allied products | 8.3 | 2.0% | 0.3 | 0.3% | -7.9 | 2.7% |
Add column groups:
epitable(tradebalance_fmt,
rownamesvar = industry,
rowlevels = thelevels,
colnames = rep(c("Levels (\\$billions)", "Share of total change"), 3),
colgroups = list(
names = c("Imports", "Exports", "Trade balance"),
pattern = c(2, 2, 2))
)
Imports | Exports | Trade balance | ||||
---|---|---|---|---|---|---|
Levels ($billions) | Share of total change | Levels ($billions) | Share of total change | Levels ($billions) | Share of total change | |
Total change | 403.2 | 100.0% | 111.1 | 100.0% | -292.1 | 100.0% |
Agriculture, forestry, fishing, and hunting | 2.3 | 0.6% | 17.3 | 15.6% | 15.0 | -5.1% |
Mining | -0.1 | 0.0% | 8.5 | 7.7% | 8.6 | -3.0% |
Oil and gas | 0.1 | 0.0% | 6.8 | 6.2% | 6.8 | -2.3% |
Minerals and ores | 0.1 | 0.0% | 1.7 | 1.5% | 1.6 | -0.5% |
Manufacturing | 400.8 | 99.4% | 80.0 | 72.0% | -320.8 | 109.8% |
Nondurable goods | 44.1 | 10.9% | 3.5 | 3.2% | -40.6 | 13.9% |
Food | 3.2 | 0.8% | 2.5 | 2.3% | -0.6 | 0.2% |
Beverage and tobacco products | 0.1 | 0.0% | 0.2 | 0.2% | 0.1 | 0.0% |
Textile mills and textile product mills | 11.8 | 2.9% | 0.4 | 0.4% | -11.4 | 3.9% |
Apparel | 20.7 | 5.1% | 0.1 | 0.1% | -20.7 | 7.1% |
Leather and allied products | 8.3 | 2.0% | 0.3 | 0.3% | -7.9 | 2.7% |
epitable_append()
combines multiple tables into one. Note also the use of header=FALSE
for table2 below:
# add dollar sign to Total change
data1 <- tradebalance_fmt %>%
filter(industry == "Total change") %>%
mutate_at(vars(ends_with("level")), ~paste0("$",.))
data2 <- tradebalance_fmt %>% filter(industry != "Total change")
table1 <- epitable(data1,
rownamesvar = industry,
colnames = rep(c("Levels (\\$billions)", "Share of total change"),3),
colgroups = list(
names = c("Imports", "Exports", "Trade balance"),
pattern = c(2, 2, 2))
)
table2 <- epitable(data2,
rownamesvar=industry,
rowlevels=thelevels[2:length(thelevels)],
header=FALSE
)
epitable_append(table1, table2)
Imports | Exports | Trade balance | ||||
---|---|---|---|---|---|---|
Levels ($billions) | Share of total change | Levels ($billions) | Share of total change | Levels ($billions) | Share of total change | |
Total change | $403.2 | 100.0% | $111.1 | 100.0% | $-292.1 | 100.0% |
Agriculture, forestry, fishing, and hunting | 2.3 | 0.6% | 17.3 | 15.6% | 15.0 | -5.1% |
Mining | -0.1 | 0.0% | 8.5 | 7.7% | 8.6 | -3.0% |
Oil and gas | 0.1 | 0.0% | 6.8 | 6.2% | 6.8 | -2.3% |
Minerals and ores | 0.1 | 0.0% | 1.7 | 1.5% | 1.6 | -0.5% |
Manufacturing | 400.8 | 99.4% | 80.0 | 72.0% | -320.8 | 109.8% |
Nondurable goods | 44.1 | 10.9% | 3.5 | 3.2% | -40.6 | 13.9% |
Food | 3.2 | 0.8% | 2.5 | 2.3% | -0.6 | 0.2% |
Beverage and tobacco products | 0.1 | 0.0% | 0.2 | 0.2% | 0.1 | 0.0% |
Textile mills and textile product mills | 11.8 | 2.9% | 0.4 | 0.4% | -11.4 | 3.9% |
Apparel | 20.7 | 5.1% | 0.1 | 0.1% | -20.7 | 7.1% |
Leather and allied products | 8.3 | 2.0% | 0.3 | 0.3% | -7.9 | 2.7% |
epitable allows extra rows to be added to a table. The syntax is somewhat complicated (suggestions to improve it are very welcome!), but let’s see how it works with another example dataset educwages
provided by the epitable package that contains mean wages by educational group:
epitable(educwages, rownamesvar = year)
educ1 | educ2 | educ3 | educ4 | educ5 | stat | |
---|---|---|---|---|---|---|
2000 | 12.59 | 17.85 | 20.32 | 31.27 | 39.47 | level |
2007 | 13.03 | 18.06 | 20.46 | 31.95 | 40.6 | level |
2017 | 13.66 | 18.25 | 20.01 | 33.17 | 42.39 | level |
2018 | 13.68 | 18.45 | 20.34 | 33.36 | 43.8 | level |
2000–2018 | 0.005 | 0.002 | 0 | 0.004 | 0.006 | change |
2000–2007 | 0.005 | 0.002 | 0.001 | 0.003 | 0.004 | change |
2007–2018 | 0.004 | 0.002 | -0.001 | 0.004 | 0.007 | change |
2017–2018 | 0.001 | 0.011 | 0.016 | 0.006 | 0.033 | change |
The stat=level
and stat=change
amounts happen to be in dollars and percent, respectively. We can make that more clear in the resulting epitable by adding extra rows. First let’s format the data and create legible column names:
educwages_fmt <- educwages %>%
mutate_at(
vars(starts_with("educ")),
~ifelse(
stat=="level",
paste0("$",number(., accuracy = 0.11)),
percent(.,accuracy=0.1)
)
) %>%
select(year,starts_with("educ"))
educwages_colnames <- c(
"Less than high school",
"High school graduate",
"Some college",
"College graduate",
"Advanced degree"
)
Now let’s add extra rows. To do this, include an argument called extrarowN that is a list of additional arguments. The extra row will be added before row N of the table.
The simplest example is to define the extrarowN list as the name
of the row:
epitable(educwages_fmt,
rownamesvar = year,
colnames = educwages_colnames,
extrarow1 = list(name = "Levels"),
extrarow5 = list(name = "Annualized percent changes")
)
Less than high school | High school graduate | Some college | College graduate | Advanced degree | |
---|---|---|---|---|---|
Levels | |||||
2000 | $12.54 | $17.82 | $20.35 | $31.24 | $39.49 |
2007 | $12.98 | $18.04 | $20.46 | $31.90 | $40.59 |
2017 | $13.64 | $18.26 | $20.02 | $33.22 | $42.35 |
2018 | $13.64 | $18.48 | $20.35 | $33.33 | $43.78 |
Annualized percent changes | |||||
2000–2018 | 0.5% | 0.2% | 0.0% | 0.4% | 0.6% |
2000–2007 | 0.5% | 0.2% | 0.1% | 0.3% | 0.4% |
2007–2018 | 0.4% | 0.2% | -0.1% | 0.4% | 0.7% |
2017–2018 | 0.1% | 1.1% | 1.6% | 0.6% | 3.3% |
You could also use what EPI’s website calls “pseudoheader” rows:
epitable(educwages_fmt,
rownamesvar = year,
colnames = educwages_colnames,
extrarow1 = list(name = "Levels", pseudoheader=TRUE),
extrarow5 = list(name = "Annualized percent change", pseudoheader=TRUE)
)
Less than high school | High school graduate | Some college | College graduate | Advanced degree | |
---|---|---|---|---|---|
Levels | |||||
2000 | $12.54 | $17.82 | $20.35 | $31.24 | $39.49 |
2007 | $12.98 | $18.04 | $20.46 | $31.90 | $40.59 |
2017 | $13.64 | $18.26 | $20.02 | $33.22 | $42.35 |
2018 | $13.64 | $18.48 | $20.35 | $33.33 | $43.78 |
Annualized percent change | |||||
2000–2018 | 0.5% | 0.2% | 0.0% | 0.4% | 0.6% |
2000–2007 | 0.5% | 0.2% | 0.1% | 0.3% | 0.4% |
2007–2018 | 0.4% | 0.2% | -0.1% | 0.4% | 0.7% |
2017–2018 | 0.1% | 1.1% | 1.6% | 0.6% | 3.3% |
Finally, the easiest table to read might be to include additional lists of colgroups
in the extrarowX lists. These require a vector of names and a vector of spanning patterns.
epitable(educwages_fmt,
rownamesvar = year,
colnames = educwages_colnames,
extrarow1 = list(colgroups = list(names = c("Levels"),
pattern = c(5))),
extrarow5 = list(colgroups = list(names = c("Annualized percent changes"),
pattern = c(5)))
)
Less than high school | High school graduate | Some college | College graduate | Advanced degree | |
---|---|---|---|---|---|
Levels | |||||
2000 | $12.54 | $17.82 | $20.35 | $31.24 | $39.49 |
2007 | $12.98 | $18.04 | $20.46 | $31.90 | $40.59 |
2017 | $13.64 | $18.26 | $20.02 | $33.22 | $42.35 |
2018 | $13.64 | $18.48 | $20.35 | $33.33 | $43.78 |
Annualized percent changes | |||||
2000–2018 | 0.5% | 0.2% | 0.0% | 0.4% | 0.6% |
2000–2007 | 0.5% | 0.2% | 0.1% | 0.3% | 0.4% |
2007–2018 | 0.4% | 0.2% | -0.1% | 0.4% | 0.7% |
2017–2018 | 0.1% | 1.1% | 1.6% | 0.6% | 3.3% |