davidgohel / flextable

table farming
https://ardata-fr.github.io/flextable-book/
558 stars 80 forks source link

Define a Template without any previous dataframe #122

Closed kmezhoud closed 5 years ago

kmezhoud commented 5 years ago

Dear David, Thank you for flextable! I would like to define flextable as template for reporting. The report will be filled automatically or reactively after processing. Here an example of huxtable. I prefer using flextable to define Templates since I have a complex headers. Thanks

library(huxtable)
library(dplyr)
headr <- data.frame(Title = c("subTitle1", "subTitle2"), 
                     NULL = c("", "numeric2")) 
body <- data.frame( Description = c("Desc1", "Desc2", "Desc3"),
                    Value = c("vale1", "", "value3"))
merged_hux <- rbind(as_huxtable(headr) %>% add_colnames(),
               as_huxtable(body) %>% add_colnames())
huxtable::align(merged_hux)[1, 1]         <- "center"
merged_hux <- merge_cells(merged_hux,1, 1:2)
bottom_border(merged_hux[c(1,3,4), ])     <- 1
huxtable::bold(merged_hux)[c(1, 4), ]    <- TRUE
merged_hux
davidgohel commented 5 years ago

Hi,

I am not expert with huxtable but it seems there is a difference, flextable starts from a data.frame but huxtable can bind data into the table. I don't think I can translate that directly.

This would be one solution with flextable:

library(flextable)
body <- data.frame( Description = c("Desc1", "Desc2", "Desc3"),
                    Value = c("vale1", "", "value3"), stringsAsFactors = FALSE)
headr <- data.frame(col_keys = c("Description", "Value"),  
                    line1 = c("subTitle1", ""), 
                    line2 = c("subTitle2", "numeric2"), 
                    line3 = c("Description", "Value"),
                    stringsAsFactors = FALSE) 

your_theme <- function(ft, title){
  ft <- add_header_lines(ft, title, top = TRUE)
  ft <- flextable::align(ft, part = "all", align = "left")
  ft <- flextable::align(ft, i = 1, j = 1, part = "header", align = "center")
  ft <- flextable::bold(ft, i = c(1, 4), bold = TRUE, part = "header")
  ft <- fontsize(ft, size = 16, part = "all")
  ft <- padding(ft, padding = 10, part = "all")
  ft <- flextable::width(ft, width = 2)
  ft
}

ft <- flextable(data = body)
ft <- set_header_df(x = ft, mapping = headr, key = "col_keys")
ft <- your_theme(ft, title = "Title")
ft <- hline(ft, i = c(1, 3, 4), border = officer::fp_border(), part = "header")
ft
Capture d’écran 2019-05-12 à 16 03 04

I like set_header_df as it is easy to define a table and add the content in one single command. If you don't like set_header_df, another option is to use add_header_row:

library(flextable)
body <- data.frame( Description = c("Desc1", "Desc2", "Desc3"),
                    Value = c("vale1", "", "value3"), stringsAsFactors = FALSE)
base_ft <- flextable(data = body, theme_fun = NULL) %>% 
  add_header_row(values = c("subTitle2", "numeric2"), colwidths = c(1,1), top = TRUE) %>% 
  add_header_row(values = c("subTitle1"), colwidths = 2, top = TRUE) %>% 
  add_header_row(values = c("Title"), colwidths = 2, top = TRUE) %>% 
  fontsize(size = 16, part = "all") %>% padding(padding = 10, part = "all")

base_ft %>% 
  flextable::align( part = "all", align = "left") %>% 
  flextable::align( i = 1, j = 1, part = "header", align = "center") %>% 
  hline(i = c(1, 3, 4), border = officer::fp_border(), part = "header") %>% 
  flextable::bold(i = c(1, 4), bold = TRUE, part = "header") %>% 
  flextable::width(width = 2)
Capture d’écran 2019-05-12 à 16 03 11

You can also use theme functions (see theme_tron_legacy below) or copy and adapt from those theme function.

base_ft %>% flextable::theme_tron_legacy() %>% 
  flextable::width(width = 2) %>% 
  flextable::align( i = 1, j = 1, part = "header", align = "center")
Capture d’écran 2019-05-12 à 16 04 30

You can find some documentation here: https://davidgohel.github.io/flextable/articles/layout.html#manage-headers-and-footers

You can get lot of examples and code sample from https://davidgohel.github.io/flextable/articles/offcran/examples.html

kmezhoud commented 5 years ago

@davidgohel Thanks for the quick suggestions.

First point For the first one, the Description and value parameters are defined 3 times.

  1. as a col_keys for the headr despite that it could be in the body,
  2. The colnamesof the body, (which for me the right one),
  3. and in the line3 in separate rows.

I tried to understand to concept, and I add a column in the body.

Error in fix.by(by.y, y) : 'by' must specify a uniquely valid column

I commented some lines because the number of rows was changed...

library(flextable)
body <- data.frame( col_keys = c("Description", "Value", "Interpretation"),
                    col1 = c("Desc1", "Desc2", "Desc3"),
                    col2 = c("value1", "", "value3"), 
                    col3 = c("Inter1", "", "Inter3"),
                    stringsAsFactors = FALSE)

headr <- data.frame(col_keys = c("foo","too"),
                    line1 = c("subTitle1", ""), 
                    line2 = c("subTitle2", "numeric2"), 
                    #line3 = c("Description", "Value"),
                    stringsAsFactors = FALSE)

your_theme <- function(ft, title){
  ft <- add_header_lines(ft, title, top = TRUE)
  ft <- flextable::align(ft, part = "all", align = "center")
  ft <- flextable::align(ft, i = 1, j = 1, part = "header", align = "center")
  #ft <- flextable::bold(ft, i = c(1, 4), bold = TRUE, part = "header")
  ft <- fontsize(ft, size = 16, part = "all")
  ft <- padding(ft, padding = 10, part = "all")
  #ft <- flextable::width(ft, width = 2)
  ft
}

ft <- flextable(data = body)
ft <- set_header_df(x = ft, mapping = headr, key = "col_keys")
ft <- your_theme(ft, title = "Title")
#ft <- hline(ft, i = c(1, 3, 4), border = officer::fp_border(), part = "header")
ft
Screen Shot 2019-05-12 at 21 27 35

Second point With set_header_df we can not define the Title as an argument. We have to add it as a new line separately.

I thing the second suggestion is simplest.

flextable::bold(i = c(1, 4), bold = TRUE, part = "header") 

and

  hline(i = c(1, 3, 4), border = officer::fp_border(), part = "header") 

Thanks, km

davidgohel commented 5 years ago

I made documentation improvements.

https://davidgohel.github.io/flextable/articles/layout.html#manage-headers-and-footers

  1. What is the difference between add_header_row and add_header_lines ?

It's clearer in the doc

  1. theme_fun is not known for V0.5.2?

yes, it appeared with 0.5.3

  1. For the second suggestion Description and value are defined as colnames of the body. But during setting layout, they considered as a part of header with

I think the documentation is covering that

KR David

github-actions[bot] commented 2 years ago

This old thread has been automatically locked. If you think you have found something related to this, please open a new issue and link to this old issue if necessary.