user3900349
user3900349

Reputation: 55

Control text wrapping and hyphenation in kable tables

I have an Rmarkdown document with embedded tables but I have trouble understanding the underlying rules for text wrapping and hyphenation for the table contents. Searching through stackoverflow and other resources hasn't provided a lot of insight.

An example is provided below, the columns widths specified are only necessary in the example to reproduce the problem I have with the real table. After some trial and error, I was able to get the last column header to hyphenate by entering it as " Manufacturer " but this trick does not work in the rows below that header. Additional examples of problems with text in cells either getting cut off or spilling into adjacent cells are shown in the third column (Result) and the formatting of cell entries is displayed in the second column. I've added a border between the third and fourth columns to highlight the problems. The real table has 8 columns and I've adjusted those column widths as much as possible while preserving readability.

---
title: 'Table_7_problem'
fontsize: 11pt
output:
  bookdown::pdf_document2:
   toc: false
   number_sections: false 
   latex_engine: xelatex
tables: yes
header-includes:
- \usepackage{booktabs}
- \usepackage{longtable}
- \usepackage{colortbl} # to set row stripe colors
- \usepackage{tabu}
- \setlength{\tabcolsep}{1pt} 
---
```

```{r setup, echo = TRUE, cache = FALSE, warning = FALSE, message = FALSE}
{r setup, echo = FALSE, cache = FALSE, warning = FALSE, message = FALSE}

library(knitr)

```

# Table 7: Appliance durability

This table contains fictional data.

```{r table7, echo = FALSE, cache = FALSE, warning = FALSE, message = FALSE}
{r table7, echo = FALSE, cache = FALSE, warning = FALSE, message = FALSE}

table7 <- data.frame(
  Column_1 = c('Very long string #1 that requires a wide column to accomodate and maintain readability' ,'Very long string #2... and more of the same down rows for this column...','Very long string #3','Very long string #4','Very long string #5','Very long string #6', 'Very long string #7'),
  Column_2 = c('"SampleText"',
               '"Sample Text"',
               '" SampleText"',
               '"SampleText "',
               '" SampleText "',
               '"SampleText #2"',
               '"Sample Text #2"'),
  Column_3 = c('SampleText',
               'Sample Text',
               ' SampleText',
               'SampleText ',
               ' SampleText ',
               'SampleText #2',
               'Sample Text #2"'),
  Column_4 = c('Manufacturer', 
               ' Manufacturer', 
               'Manufacturer ',
               ' Manufacturer ',
               ' LongManufacturerName',
               'Long_Manufacturer_Name',
               "Long Manufacturer Name")
)

###

colnames(table7) <- c("Name", "Cell Content Format", "Result", " Manufacturer ")

library(kableExtra)

  table7 %>% 
  kbl(longtable = TRUE, align = "lllc", booktabs = TRUE) %>% 
  kable_styling(full_width = FALSE, font_size = 8, latex_options = c("repeat_header", "striped"), stripe_color = "gray!15", repeat_header_text = "Table 7 \\textit{continued...}") %>%
  row_spec(0, bold = TRUE) %>% 
  column_spec(1, width = "1.5in") %>%
  column_spec(2, width = "3.825in") %>%
  column_spec(3, width = "0.5in") %>%
  column_spec(4, width = "0.45in", border_left = TRUE)
```

The above code produces this:

enter image description here

Any advice or solutions on how to control the hyphenation and word wrapping to resolve these problems?

*** UPDATE 2022-09-07

Updating the status - I've explored several packages for making the table and so far none will do everything I was looking for but, for me, it seems the flextable package will do most of what I wanted. The updated code and pdf result are shown below. It may not be pretty but it gets the job done. Seems some conflicts arise when piping the formatting commands but they seem to work just fine if entered one at a time, which is why there are multiple t7 <-... statements (I played around with much more elaborate formatting and the same strategy of using individual statements worked).


table7 <- data.frame(
  Column_1 = c('Very long string #1 that requires a wide column to accomodate and maintain readability' ,'Very long string #2... and more of the same down rows for this column...','Very long string #3','Very long string #4','Very long string #5','Very long string #6', 'Very long string #7'),
  Column_2 = c('"SampleText"',
               '"Sample Text"',
               '" SampleText"',
               '"SampleText "',
               '" SampleText "',
               '"SampleText #2"',
               '"Sample Text #2"'),
  Column_3 = c('SampleText',
               'Sample Text',
               ' SampleText',
               'SampleText ',
               ' SampleText ',
               'SampleText #2',
               'Sample Text #2"'),
  Column_4 = c('Manufacturer', 
               ' Manufacturer', 
               'Manufacturer ',
               ' Manufacturer ',
               ' LongManufacturerName',
               'Long_Manufacturer_Name',
               "Long Manufacturer Name")
)

###

colnames(table7) <- c("Name", "Cell Content Format", "Result", "Manu-\nfacturer")

library(flextable)
library(stringr)

set_flextable_defaults(
  font.family = gdtools::match_family(font = "Serif"), 
  font.size = 8,
  padding = 3)

table7$`Manu-\nfacturer` <- str_replace(string = table7$`Manu-\nfacturer`, pattern = 'Manufacturer', replacement = 'Manu-\nfacturer')

t7 <- table7 %>% flextable() %>% 
  width(., width = c(1.5, 3.825, 0.5, 0.45), unit = "in") %>% 
  #add_header_lines(., values = "Table 7") %>% 
  theme_zebra(.)

t7 <- hline(t7, i = 1, border = officer::fp_border(color = "black"), part = "header")
t7 <- flextable::align(t7, i = 1, j = 1, align = "left", part = "header")

t7

the above generates the figure below. The str_replace strategy suggested by @Julian achieves the hyphenation and wrapping and theme_zebra() in flextable preserved the row striping.

enter image description here

Upvotes: 1

Views: 1472

Answers (1)

Julian
Julian

Reputation: 9240

What you can do is to add linebreaks and add escape = FALSE to your kable function. Note that you need to escape #,_ etc. as well.

table7 <- data.frame(
  Column_1 = c('Very long string 1 that requires a wide column to accomodate and maintain readability' ,'Very long string 2... and more of the same down rows for this column...','Very long string 3','Very long string 4','Very long string 5','Very long string 6', 'Very long string 7'),
  Column_2 = c('"SampleText"',
               '"Sample Text"',
               '" SampleText"',
               '"SampleText "',
               '" SampleText "',
               '"SampleText 2"',
               '"Sample Text 2"'),
  Column_3 = c('Sample\nText',
               'Sample\n Text',
               ' Sample\nText',
               'Sample\nText ',
               ' Sample\nText ',
               'Sample\nText 2',
               'Sample \nText 2"'),
  Column_4 = c('Manu\nfacturer', 
               ' Manu\nfacturer', 
               'Manu\nfacturer ',
               ' Manu\nfacturer ',
               ' Long\nManufacturer\nName',
               'Long\nManufacturer\nName',
               "Long\n Manufacturer\n Name")
)

kable_example

Upvotes: 1

Related Questions