Creating a neat table with Kable()

Hi there,

I am in the process of working out how to create a neat table (and have never made a table at all before so just starting out!).

I am looking at the PHS open data for unintentional injuries and making a table looking at total Scotland data for 2018. I have made a table which looks ok - but I would like to create subdivision of rows to divide the results by male and female to make it look neater, as well as format the heading font size and make it a more attractive appearance. I have tried a couple of things in kableExtra but couldn't get it to work. Code below. Does anyone have any suggestions?

# Read in mortality data
orig_ui_deaths = read_csv("https://www.opendata.nhs.scot/dataset/b0135993-3d8a-4f3b-afcf-e01f4d52137c/resource/89807e07-fc5f-4b5e-a077-e4cf59491139/download/ui_deaths_2020.csv")
# Create table of number of deaths by injury type, age, and sex
# Pipe in orig_ui_deaths dataset
orig_ui_deaths %>%
  # Apply filters in same was as in plots so looking at one year, whole of Scotland, and exlucing "All" entries
  filter(Year == "2018", HBR == "S92000003", AgeGroup != "All" & Sex != "All", InjuryType != "Accidental exposure" & InjuryType != "All")%>%
# Group the table according to injury type, age, and sex
  group_by(InjuryType, AgeGroup, Sex) %>%
# Create a summary of total number of deaths for neater appearance to the table and demonstration of the figures
  summarise(total_deaths = sum(NumberOfDeaths)) %>%
# Change the orientation of the table so that age groups become the variable headings
  pivot_wider(names_from = AgeGroup, values_from = total_deaths) %>%
# Create table to present the data]
  knitr::kable(caption = "Deaths from unintentional injuries in Scotland")
  

Many thanks!

subdivision of rows to divide the results by male and female

is unclear. It's simple enough to create separate tables by sex.

Editorial suggestion: remove the top and bottom pair of rows and add a note that there were no injuries of those types.

kable has a option to set font size

kable(dt) %>%
  kable_styling(bootstrap_options = "striped", font_size = 7)

See this post

Thanks very much that's helpful. I'm trying to split the table so that the results can be seen by female and then male separately rather than just as subsequent rows in the table. I can't work out how to do this within the same table but wondered if there is a split function for the code so that two smaller tables could be created, one for female and one for male?

Many thanks again

Hi CM1,

There's an option to create groups where you exclude the factor Sex when generating the table in knitr::kable, but you can still use Sex as a grouping index in kableExtra::pack_rows.

EDITS:

  • Contents are now in a Rmarkdown file.
  • Changed kable output format from html to LaTeX.
  • Added LaTeX package caption to set up larger captions in YAML header of rmarkdown document.
---
title: "Table-kable"
output: pdf_document
geometry: margin=0.5in
header-includes:
- \usepackage{caption}
- \captionsetup{font=Large}
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE, message = FALSE)
```

```{r}
library("knitr")
library("kableExtra")
library("dplyr")
library("readr")
library("tidyr")
library("forcats")

orig_ui_deaths = read_csv("https://www.opendata.nhs.scot/dataset/b0135993-3d8a-4f3b-afcf-e01f4d52137c/resource/89807e07-fc5f-4b5e-a077-e4cf59491139/download/ui_deaths_2020.csv")

summary_tab <- orig_ui_deaths %>%
  # Apply filters in same was as in plots so looking at one year, whole of Scotland, and exlucing "All" entries
  filter(Year == "2018", HBR == "S92000003", AgeGroup != "All" & Sex != "All", InjuryType != "Accidental exposure" & InjuryType != "All") %>%
# Group the table according to injury type, age, and sex
  group_by(InjuryType, AgeGroup, Sex) %>%
# Create a summary of total number of deaths for neater appearance to the table and demonstration of the figures
  summarise(total_deaths = sum(NumberOfDeaths)) %>%
# Change the orientation of the table so that age groups become the variable headings
  pivot_wider(names_from = AgeGroup, values_from = total_deaths) %>%
  mutate(Sex = factor(Sex)) %>%
  arrange(Sex) %>%
  select(Sex, everything())

# Create table to present the data]
Fig_2 <- kable(summary_tab[, -1], 
  caption = "Deaths from unintentional injuries in Scotland",
    format = "latex", booktabs = TRUE) %>%
  kable_styling(font_size = 10) %>%
  pack_rows(tab_kable, colnum = 1,
    index = table(fct_inorder(summary_tab$Sex), useNA = "no"))
```
```{r, results='asis'}
Fig_2
```

2 Likes

Hi Jim,

This is absolutely brilliant, thanks so much for helping with this. Exactly what I was looking to do. Just wondered if you or anyone else might know how to make the font size of the title bigger?

Many thanks again,

CM

Hi CM,
I've edited my answer to address the issue of making the title larger.

1 Like

Hi Jim,

This is so helpful, thanks very much. Just running it in R studio and I can't seem to print the table. When I enter in this script exactly (loading the packages too) it comes up with an empty space. I tried to assign it to an object with -> Fig_2 at the end and then print and this also didn't work. Not quite sure this is happening now as previous code printed?

Thanks so much again for all of your help,

Clare

Hi Clare,
I've updated the formatting in my answer. It should work if it is run as an Rmarkdown file, knitting to a pdf output. You may have to install a version of LaTeX, such as installed from the R package tinytex, as well as the LaTeX package "caption" via tinytex::tlmgr_install("caption").

Jim