Search code examples
rdataframeformattingflextableofficer

Categorize and highlight table sections with flextable


I have below dataframe which is categorized by the column Category

> dput(mydata)
structure(list(Category = c("Executive", "Management", "Management", 
"Management", "Professional", "Professional", "Professional", 
"Para-Professional", "Para-Professional", "Para-Professional"
), Rank = c("Rank 1", "Rank 1", "Rank 2", "Rank 3", "Rank 1", 
"Rank 2", "Rank 3", "Rank 1", "Rank 2", "Rank 3"), Jobs = c(" SMP - Sales, Marketing & Product Management", 
" SMP - Sales, Marketing & Product Management", " ENS - Engineering & Science", 
" FIN - Finance", " SMP - Sales, Marketing & Product Management", 
" ENS - Engineering & Science", " FIN - Finance", " PSK - Production & Skilled Trades", 
" ENS - Engineering & Science", " EGS - Energy Generation & Supply"
), N = c(3, 10, 3, 2, 54, 25, 5, 7, 2, 1)), row.names = c(NA, 
-10L), class = "data.frame")

I wanted to merge cells of same category for category column which did with below code using flex table

mydata%>% flextable()%>% merge_v(j=~Category)

Now i want to highlight entire section border of data corresponding to each category, for example the data corresponding to Executive category should be highlighted with broader border similarly for other. I tried and could highlight only the category cells as below:

cl<-fp_border(color = "#00A8C8",width = 3)
mydata%>% flextable()%>% merge_v(j=~Category)%>%hline(j=~Category,border = cl)

I want similar border around all the sub-table corresponding to each category to differentiate better between categories in the table. How can do it with flextable only?


Solution

  • I think this should help.

    The key here is to find a way to create a logical vector representing where lines should appear - this is what function break_position is doing.

    library(flextable)
    library(officer)
    library(magrittr)
    mydata <- structure(list(Category = c(
      "Executive", "Management", "Management",
      "Management", "Professional", "Professional", "Professional",
      "Para-Professional", "Para-Professional", "Para-Professional"
    ), Rank = c(
      "Rank 1", "Rank 1", "Rank 2", "Rank 3", "Rank 1",
      "Rank 2", "Rank 3", "Rank 1", "Rank 2", "Rank 3"
    ), Jobs = c(
      " SMP - Sales, Marketing & Product Management",
      " SMP - Sales, Marketing & Product Management", " ENS - Engineering & Science",
      " FIN - Finance", " SMP - Sales, Marketing & Product Management",
      " ENS - Engineering & Science", " FIN - Finance", " PSK - Production & Skilled Trades",
      " ENS - Engineering & Science", " EGS - Energy Generation & Supply"
    ), N = c(3, 10, 3, 2, 54, 25, 5, 7, 2, 1)), row.names = c(
      NA,
      -10L
    ), class = "data.frame")
    
    
    cl <- fp_border(color = "#00A8C8", width = 3)
    
    break_position <- function(x) {
      z <- data.table::rleidv(x)
      c(z[-length(z)] != z[-1], FALSE)
    }
    
    mydata %>%
      flextable() %>%
      merge_v(j = ~Category) %>%
      hline(i = ~ break_position(Category), border = cl) %>% 
      fix_border_issues()
    

    enter image description here