--- title: "Adding Rows to a panelsummary Table" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Adding Rows to a panelsummary Table} %\VignetteEncoding{UTF-8} %\VignetteEngine{knitr::rmarkdown} editor_options: chunk_output_type: console --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>", fig.align = "center", fig.height = 4 ) ``` ```{js, echo = F} $( document ).ready(function() { $(".lightable-classic").removeClass("table").css("display", "table"); }); ``` This vignette shows how to add rows to `panelsummary` tables. Since `panelsummary::panelsummary` returns `kableExtra` objects, adding rows is impossible using the base function `panelsummary::panelsummary`. This can be a nuisance when you want to include additional statistics to your table. However, the workaround is to use the `panelsummary::panelsummary_raw` function. ## panelsummary::panelsummary_raw The `panelsummary::panelsummary_raw` function returns a dataframe that can be manipulated. The trade-off is that the table will need to be customized using the `kableExtra` package, although some of this customization can be completed using the `panelsummary::clean_raw` function (see example). ## Workflow If you want to create a table with panels that has additional statistical rows, the workflow will be the following: * Estimate your models (preferably with the `fixest` package). * Pass your models into `panelsummary::panelsummary_raw` to get a manipulable dataframe. * Manipulate the dataframe (preferably with `dplyr::add_row`). * Use `panelsummary::clean_raw` to return a `kableExtra` object. * Use `kableExtra::pack_rows` to create panel labels. ## Example: Adding Additional Rows to Each Panel To demonstrate how to add a row to each panel of a `panelsummary::panelsummary_raw` table, I will assume that each panel needs one additional row for the wild-cluster-bootstrap p-values of the `cyl` column from the `mtcars` data. While I will not explicitly calculate these (in fact, they will be completely made up), the following steps will show how to complete such task. Consider the following models, estimated using the `fixest` package: ```{r setup} library(panelsummary) ## Panel A: mpg dependent variable mpg_1 <- fixest::feols(mpg ~cyl + disp, data = mtcars) mpg_2 <- fixest::feols(mpg ~ cyl + am, data = mtcars) ## Panel B: wt dependent variable wt_1 <- fixest::feols(wt ~ cyl + disp, data = mtcars) wt_2 <- fixest::feols(wt ~ cyl + am, data = mtcars) ``` Recall that putting each of these two models in a list will result in multiple specifications per-panel. ```{r} ## putting each panel's models into a list—one for each panel panel_a_mpg <- list(mpg_1, mpg_2) panel_b_wt <- list(wt_1, wt_2) ``` Now, I will pass these two lists into `panelsummary::panelsummary_raw`. Note that this function shares many of the same arguments as `panelsummary::panelsummary`. In the following, I will also use the arguments `stars` (significance stars), `mean_dependent` (for dependent variable mean), and `gof_omit` (to omit $R^2$ statistics): ```{r} ## creating the dataframe panelsummary_raw(panel_a_mpg, panel_b_wt, stars = "econ", mean_dependent = T, gof_omit = "^R") ``` The return value of this output is a dataframe without panel labels. Given that it is a dataframe, you can use `dplyr` functions to easily manipulate. For instance, I will use the `dplyr::add_rows` function to add the pseudo wild-cluster-bootstrap p-values to the table: ```{r} ## adding rows using dplyr::add_row bootstrap_table <- panelsummary_raw(panel_a_mpg, panel_b_wt, stars = "econ", mean_dependent = T, gof_omit = "R") |> dplyr::add_row(term = "Wild Cluster Boot P-value (cyl)", `Model 1` = ".001", `Model 2` = ".002", .before = 10) |> dplyr::add_row(term = "Wild Cluster Boot P-value (cyl)", `Model 1` = ".001", `Model 2` = ".005", .before = 22) bootstrap_table ``` Now the dataframe is ready to be passed into `kableExtra::kbl` to further customize it with panel headers/column names etc. Alternatively, you can use the `panelsummary::clean_raw` function to get a few desirable traits and speed up the process. In particular, the `panelsummary::clean_raw` function does the following by default: * Passes the dataframe into `kableExtra::kbl` * Changes the alignment to Left for the first column, and Center for all remaining columns. * Changes the names of the columns to a blank white space for the first column, and consecutive numbers in the remaining columns. However, you can also pass in a caption using the `caption` argument: ```{r} ## creating a kableExtra object with a few desirable defaults bootstrap_table |> clean_raw(caption = "A customized panelsummary table with added rows.") ``` Finally, to get the desired panel labels, you will need to use `kableExtra::pack_rows`: ```{r} ## creating the final panels. bootstrap_table |> clean_raw(caption = "A customized panelsummary table with added rows.") |> kableExtra::pack_rows("Panel A: MPG", 1, 14, italic = T, bold = F) |> kableExtra::pack_rows("Panel B: Cyl", 15, 28, italic = T, bold = F) |> kableExtra::footnote(list("* p < 0.1, ** p < 0.05, *** p < 0.01")) |> kableExtra::kable_classic(full_width = F, html_font = "Cambria") ```