Function magic_mirror and updated READ.ME
diff --git a/R/footnote.R b/R/footnote.R
index 8724141..e35a9f1 100644
--- a/R/footnote.R
+++ b/R/footnote.R
@@ -14,11 +14,13 @@
#' "number", "alphabet" and "symbol".
#'
#' @export
-add_footnote <- function(input, label = NULL, notation = "alphabet", threeparttable = F) {
+add_footnote <- function(input, label = NULL, notation = "alphabet",
+ threeparttable = F) {
if (is.null(label)){return(input)}
# Define available id list
if (!notation %in% c("number", "alphabet", "symbol")){
- warning('Please select your notation within "number", "alphabet" and "symbol". Now add_footnote is using "alphabet" as default.')
+ warning('Please select your notation within "number", "alphabet" and ',
+ '"symbol". Now add_footnote is using "alphabet" as default.')
}
if (notation == "symbol") {notation = paste0(notation, ".", attr(input, "format"))}
ids.ops <- data.frame(
@@ -27,14 +29,18 @@
symbol.latex = c(
"*", "\\\\dag", "\\\\ddag", "\\\\S", "\\\\P",
"**", "\\\\dag\\\\dag", "\\\\ddag\\\\ddag", "\\\\S\\\\S", "\\\\P\\\\P",
- "***", "\\\\dag\\\\dag\\\\dag", "\\\\ddag\\\\ddag\\\\ddag", "\\\\S\\\\S\\\\S", "\\\\P\\\\P\\\\P",
- "****", "\\\\dag\\\\dag\\\\dag\\\\dag", "\\\\ddag\\\\ddag\\\\ddag\\\\ddag", "\\\\S\\\\S\\\\S\\\\S", "\\\\P\\\\P\\\\P\\\\P"
+ "***", "\\\\dag\\\\dag\\\\dag", "\\\\ddag\\\\ddag\\\\ddag",
+ "\\\\S\\\\S\\\\S", "\\\\P\\\\P\\\\P",
+ "****", "\\\\dag\\\\dag\\\\dag\\\\dag", "\\\\ddag\\\\ddag\\\\ddag\\\\ddag",
+ "\\\\S\\\\S\\\\S\\\\S", "\\\\P\\\\P\\\\P\\\\P"
),
symbol.html = c(
"*", "†", "‡", "§", "¶",
"**", "††", "‡‡", "§§", "¶¶",
- "*", "†††", "‡‡‡", "§§§", "¶¶¶",
- "**", "††††", "‡‡‡‡", "§§§§", "¶¶¶¶"
+ "*", "†††", "‡‡‡",
+ "§§§", "¶¶¶",
+ "**", "††††", "‡‡‡‡",
+ "§§§§", "¶¶¶¶"
),
symbol.markdown = c(
"\\*", "†", "‡", "§", "¶",
@@ -50,6 +56,7 @@
)
)
ids <- ids.ops[,notation]
+ # pandoc cannot recognize ^*^ as * is a special character. We have to use ^\*^
ids.intable <- gsub("\\*", "\\\\*", ids)
#count the number of items in label and intable notation
@@ -60,8 +67,14 @@
count.intablenoot, "[note] in your table."))
}
+ export <- input
+
+ # Footnote solution for markdown and pandoc. It is not perfect as
+ # markdown doesn't support complex table formats but this solution
+ # should be able to satisfy people who don't want to spend extra
+ # time to define their `kable` output.
if(!attr(input, "format") %in% c("html", "latex")){
- export <- input
+ # In table notation
if(count.intablenoot != 0){
for(i in 1:count.intablenoot){
export[which(str_detect(export, "\\[note\\]"))[1]] <-
@@ -70,6 +83,20 @@
collapse = "")), export[which(str_detect(export, "\\[note\\]"))[1]])
}
}
+ # Fix extra in table notation
+ extra.notation <- as.numeric(
+ str_extract(
+ str_extract_all(
+ paste0(export, collapse = ""), "\\[note[0-9]{1,2}\\]"
+ )[[1]],
+ "[0-9]{1,2}"))
+ for(i in extra.notation){
+ export <- gsub(paste0("\\[note", i, "\\]"),
+ paste0("^", ids.intable[i], "^",
+ paste0(rep(" ", 4 - nchar(as.character(ids[i]))),
+ collapse = "")),
+ export)
+ }
export[length(export)+1] <- ""
export[length(export)+1] <- "__Note:__"
@@ -80,13 +107,17 @@
# Generate latex table footnote --------------------------------
if(attr(input, "format")=="latex"){
+ kable_info <- magic_mirror(input)
+ if(threeparttable == F | latex.tabular == "longtable"){
+
+ }
# If longtable is used, then use page footnote instead of threeparttable
# as it makes more sense to see the footnote at the bottom of page if
# table is longer than one page.
if(grepl("\\\\begin\\{longtable\\}", input)){
-
for(i in 1:count.intablenoot){
- input <- sub("\\[note\\]", paste0("\\\\footnote[", ids[i], "]{", label[i], "}"), input)
+ export <- sub("\\[note\\]",
+ paste0("\\\\footnote[", ids[i], "]{", label[i], "}"), export)
}
}else{
# Regular cases other than longtable
@@ -98,13 +129,14 @@
# Replace in-table notation with appropriate symbol
for(i in 1:count.intablenoot){
- input <- sub("\\[note\\]", paste0("\\\\textsuperscript{", ids[i], "}"), input)
+ export <- sub("\\[note\\]", paste0("\\\\textsuperscript{", ids[i], "}"), export)
}
- if(grepl("\\\\caption\\{.*?\\}", input)){
- export <- sub("\\\\caption\\{", "\\\\begin{threeparttable}\n\\\\caption{", input)
+ if(grepl("\\\\caption\\{.*?\\}", export)){
+ export <- sub("\\\\caption\\{", "\\\\begin{threeparttable}\n\\\\caption{", export)
}else{
- export <- sub("\\\\begin\\{tabular\\}", "\\\\begin{threeparttable}\n\\\\begin{tabular}", input)
+ export <- sub("\\\\begin\\{tabular\\}",
+ "\\\\begin{threeparttable}\n\\\\begin{tabular}", export)
}
export <- gsub(
"\\\\end\\{tabular\\}",
@@ -116,7 +148,6 @@
}
}
if(attr(input, "format")=="html"){
- export <- input
}
return(export)
}
diff --git a/R/magic_mirror.R b/R/magic_mirror.R
index 0fa726c..af77b50 100644
--- a/R/magic_mirror.R
+++ b/R/magic_mirror.R
@@ -5,24 +5,46 @@
#' @export
magic_mirror <- function(input){
- if(!"knitr_kable" %in% attr(input, "format")){
+ if(!"knitr_kable" %in% attr(input, "class")){
warning("magic_mirror may not be able to produce correct result if the",
" input table is not rendered by knitr::kable. ")
}
kable_format <- attr(input, "format")
if (kable_format == "latex"){
- magic_mirror_latex(input)
+ kable_info <- magic_mirror_latex(input)
}
if (kable_format == "html"){
- magic_mirror_html(input)
+ kable_info <- magic_mirror_html(input)
}
+ return(kable_info)
}
#' Magic mirror for latex tables
magic_mirror_latex <- function(input){
- # kable will put a begin{table} shell if caption is not NULL
- caption <- ifelse(
- str_detect(input, "\\\\caption\\{.*?\\}"),
- str_match(input, "caption\\{(.*?)\\}")[2], NULL
+ kable_info <- list(tabular = NULL, booktabs = NULL, align = NULL,
+ ncol=NULL, nrow=NULL, colnames = NULL, rownames = NULL,
+ caption = NULL, contents = NULL)
+ # Tabular
+ kable_info$tabular <- ifelse(
+ grepl("\\\\begin\\{tabular\\}", input),
+ "tabular", "longtable"
)
+ # Booktabs
+ kable_info$booktabs <- ifelse(grepl("\\\\toprule", input), TRUE, FALSE)
+ # Align
+ kable_info$align <- gsub("\\|", "", str_match(
+ input, paste0("\\\\begin\\{", kable_info$tabular,"\\}\\{(.*?)\\}"))[2])
+ # N of columns
+ kable_info$ncol <- nchar(kable_info$align)
+ # N of rows
+ kable_info$nrow <- str_count(input, "\\\\\n")
+ # Caption
+ kable_info$caption <- str_match(input, "caption\\{(.*?)\\}")[2]
+ # Contents
+ kable_info$contents <- str_match_all(input, "\n(.*)\\\\\\\\")[[1]][,2]
+ # Column names
+ kable_info$colnames <- str_split(kable_info$contents[1], " \\& ")[[1]]
+ # Row names
+ kable_info$rownames <- str_extract(kable_info$contents, "^[^ &]*")
+ return(kable_info)
}
diff --git a/README.Rmd b/README.Rmd
index 9851a02..792b5b3 100644
--- a/README.Rmd
+++ b/README.Rmd
@@ -7,8 +7,40 @@
This package is still in an "as-is" state. You can save a lot of finger-typing time by using it but you still need to understand what is really going on behind the hood, which is still far behind my goal. Also, since the default output format of `kable` is `markdown`, which doesn't support high-level table customization, it may not work well in many cases. I would recommend you to set the `format` option in each `kable` function or to define `options(knitr.table.format = 'html')` or `latex` somewhere in your document.
-#Introduction
-`knitr::kable` wins the favor of a lot of people, including me, by its ultimate simplicity.
+#Introduction to kableExtra
+When we are talking about table generators in `R`, `knitr::kable` wins the favor of a lot of people by its ultimate simplicity. Unlike those powerful table rendering engine such as `xtable`, `tables` or even `gridExtra`, the philosophy behind `kable` is to make it easy for programmers to use. Just as it claimed in its function description,
+> This is a very simple table generator. It is simple by design. It is not intended to replace any other R packages for making tables. - Yihui
+However, we also see a lot of people getting frustrated online for the lack of functionality of `kable`. It is kind of unfair to `kable` as it is supposed to be "simple" by design. However, it is also understandable as people cry because they love to use this function instead of those complicated alternatives.
-Even though there are some other available packages in `R` to build beautiful tables, `kable` is still my go-to function whenever I want to build a table in `rmarkdown` or `Shiny`. After using `kable` for a long time, I can see the only reason that prevents people from using `kable` is its simplicityThis package is designed to enhance `kable`'s functionality without destorying its beauty of simplicity by using our favorite `pipe` syntax.
+In `kableExtra`, we are not intended to build another table generator engine as there have been a lot (actually too many in my personal opinion) in `R`. This package is an attempt to extend `knitr::kable`'s functionality without destroying the beauty of its simplicity by using the pipe syntax from `magrittr`. We will follow the literal programming practice and try to make the progress of building a table in `R` go together with the flow of logic in your mind. We will also borrow the idea of *"grammar of graphics"* from `ggplot2` and `ggvis` and implement it in the progress of table generating tasks.
+
+##Vocabulary & Grammar
+Here is a list of features that we would love to see in this package. I bolded these that have been done.
+
+- **add_footnote()**
+- add_indent()
+- col_markup()
+- row_markup()
+- add_stripe()
+- add_hover()
+- add_textcolor()
+- add_bgcolor()
+- **magic_mirror()**
+- reverse_kable()
+
+The syntax of this package is just like what you are doing in `dplyr` or `ggvis`. Here is an example of adding footnote to a `kable` object.
+```r
+library(knitr)
+library(kableExtra)
+
+cars %>%
+ head() %>%
+ rename("speed[note]" = speed) %>%
+ kable(caption = "Head of cars [note]") %>%
+ add_footnote(
+ label = c("Footnote in caption",
+ "Footnote in table"),
+ notation = "number" # Or "alphabet"/"symbol"
+ )
+```
diff --git a/README.md b/README.md
index f6c7668..0444f5c 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,44 @@
<!-- README.md is generated from README.Rmd. Please edit that file -->
-This package is still in an "as-is" state. You can save a lot of finger-typing time by using it but you still need to understand what is really going on behind the hood. Also, since the default output format of `kable` is `markdown`, which doesn't support high-level table customization, it may not work well in many cases. I would recommend you to set the `format` option in `kable` or to define `options(knitr.table.format = 'html')` or `latex` somewhere in your document. \#Introduction My previous package `ezsummary` was trying to fulfill
+This package is still in an "as-is" state. You can save a lot of finger-typing time by using it but you still need to understand what is really going on behind the hood, which is still far behind my goal. Also, since the default output format of `kable` is `markdown`, which doesn't support high-level table customization, it may not work well in many cases. I would recommend you to set the `format` option in each `kable` function or to define `options(knitr.table.format = 'html')` or `latex` somewhere in your document.
-Everyone loves `kable`, so do I. It is the most straight forward, convenient table generating function in R (in my opinion). At the same time, it won't through you some useless messages that you need to think of a way to get rid of. Also, if you are planning to "knit" a document, you probably have already have `knitr` loaded. Why would you want to load another "table generator" package if the original one can fulfill your need.
+Introduction to kableExtra
+==========================
-Even though there are some other available packages in `R` to build beautiful tables, `kable` is still my go-to function whenever I want to build a table in `rmarkdown` or `Shiny`. After using `kable` for a long time, I can see the only reason that prevents people from using `kable` is its simplicityThis package is designed to enhance `kable`'s functionality without destorying its beauty of simplicity by using our favorite `pipe` syntax.
+When we are talking about table generators in `R`, `knitr::kable` wins the favor of a lot of people by its ultimate simplicity. Unlike those powerful table rendering engine such as `xtable`, `tables` or even `gridExtra`, the philosophy behind `kable` is to make it easy for programmers to use. Just as it claimed in its function description, > This is a very simple table generator. It is simple by design. It is not intended to replace any other R packages for making tables. - Yihui
+
+However, we also see a lot of people getting frustrated online for the lack of functionality of `kable`. It is kind of unfair to `kable` as it is supposed to be "simple" by design. However, it is also understandable as people cry because they love to use this function instead of those complicated alternatives.
+
+In `kableExtra`, we are not intended to build another table generator engine as there have been a lot (actually too many in my personal opinion) in `R`. This package is an attempt to extend `knitr::kable`'s functionality without destroying the beauty of its simplicity by using the pipe syntax from `magrittr`. We will follow the literal programming practice and try to make the progress of building a table in `R` go together with the flow of logic in your mind. We will also borrow the idea of *"grammar of graphics"* from `ggplot2` and `ggvis` and implement it in the progress of table generating tasks.
+
+Vocabulary & Grammar
+--------------------
+
+Here is a list of features that we would love to see in this package. I bolded these that have been done.
+
+- **add\_footnote()**
+- add\_indent()
+- col\_markup()
+- row\_markup()
+- add\_stripe()
+- add\_hover()
+- add\_textcolor()
+- add\_bgcolor()
+- **magic\_mirror()**
+- reverse\_kable()
+
+The syntax of this package is just like what you are doing in `dplyr` or `ggvis`. Here is an example of adding footnote to a `kable` object.
+
+``` r
+library(knitr)
+library(kableExtra)
+
+cars %>%
+ head() %>%
+ rename("speed[note]" = speed) %>%
+ kable(caption = "Head of cars [note]") %>%
+ add_footnote(
+ label = c("Footnote in caption",
+ "Footnote in table"),
+ notation = "number" # Or "alphabet"/"symbol"
+ )
+```