rr-flextable

Using flextable functions (eg merge_at, hline) in functions


I'm trying to style my flextables programatically, but I ran into problems when using certain functions, for example merge_at() and hline(); they only style the very last entry of the column I'm referencing, no matter what row I try to use.

Here is a minimal example. iris_a turns out to look like I want it to, while iris_b is changed in a way I can't comprehend.

# setup
library(tidyverse)
library(officer)
library(flextable)
thin_border <- fp_border(color = "gray")

setosa <- iris %>% group_split(Species) %>% .[[1]] %>% slice(1:2)
versicolor <- iris %>% group_split(Species) %>% .[[2]] %>% slice(1:2)

iris_a <- bind_rows(setosa, versicolor) %>% mutate(spec = case_when(
    Species == "setosa" ~ "set",
    Species == "versicolor" ~ "versi"
)) %>% flextable()
iris_b <- iris_a

specs <- c("setosa", "versicolor")

# actual transformation

for (k in specs) {
    iris_a<- iris_a%>% hline(., i = ~ Species == k, j = 1:5, border = thin_border)
}
for(k in specs){
    iris_a <- iris_a %>% merge_at(., i = ~ Species == k, j = ~spec)
}
iris_a %>% fix_border_issues()

# success, a nice table; now I wrap the loops into functions

merge_cells <- function(flex, location){
    for(k in location){
    flex <- flex %>% merge_at(., i = ~ Species == k, j = ~spec)    
    }
flex
}

add_vlines <- function(flex, location){
    for (k in location) {
        flex <- flex %>% hline(., i = ~ Species == k, j = 1:5, border = thin_border)
    }
flex
}

iris_b <- iris_b %>%
    add_vlines(., "set") %>%
    merge_cells(., "set")
iris_b %>% fix_border_issues()

It doesn't matter to what location is set, the outcome is the same (eg location = specs).

I also tried to tackle this issue with mk_par() but to no avail.

Where did I go wrong?

addendum: forgot to add, location can be set to anything, the outcome is still the same (iris_b %>% merge_cells(., "something")).


Solution

  • I think this will help you fix your issue. Your formula is the issue. I reduced the example to a simpler case.

    library(flextable)
    
    dat <- structure(list(Sepal.Length = c(5.1, 4.9, 7, 6.4), Sepal.Width = c(3.5, 
    3, 3.2, 3.2), Petal.Length = c(1.4, 1.4, 4.7, 4.5), Petal.Width = c(0.2, 
    0.2, 1.4, 1.5), Species = structure(c(1L, 1L, 2L, 2L), levels = c("setosa", 
    "versicolor", "virginica"), class = "factor"), spec = c("set", 
    "set", "versi", "versi")), row.names = c(NA, -4L), class = c("tbl_df", 
    "tbl", "data.frame"))
    
    merge_cells <- function(flex, location){
      for(k in location){
        form <- as.formula(paste0("~ spec %in% '", k, "'"))
        flex <- merge_at(flex, i = form, j = ~spec) 
      }
      flex
    }
    
    flextable(dat) |> merge_cells(location = "set")
    

    enter image description here