Is it possible to use crosstalk with kableextra table? - r

I've formatted my table nicely using kableextra and I want to apply a crosstalk filter_slider to one of the columns so that the user can adjust it. However, I am getting the following error:
Error in if (nrow(df) > 0) as.character(1:nrow(df)) else character() : argument is of length zero
The code works fine if the table is not formatted using kableextra. How can I fix this? Here is some basic reproducible code I put together to demonstrate:
Name <- c("Dwyer, Andy","Ludgate, April", "Knope, Leslie")
Rank <- c(1,2,3)
Hours <- c(1000,2000,5000)
Title <- c("Shoe Shine","Intern","Deputy Director")
df <- data.frame(Name,Rank,Title, Hours)
library(crosstalk)
df2 <- SharedData$new(df)
filter_slider("Rank","Top",df2,column=~Rank)
library(kableExtra)
df3 <- kable(df,row.names=FALSE) %>%
kable_styling(bootstrap_options = c("striped","hover",full_width=T),fixed_thead = T)%>%row_spec(seq(1,nrow(df),2),background = "aliceblue")
df3
df4 <- SharedData$new(df3)
filter_slider("Rank","Top",df4,column=~Rank)
I expect the filter_slider to work on both tables without error. I need an interactive filter to work on the kable formatted table and cannot use shiny.

Related

How to take borders off table in R markdown

Below is my code that I am using to manually create a table. When I knit in R markdown, there is a border about it and ## in front of each row. Is there a way to remove these items? Or would I be best creating data frames using these data points and then using gt?
library(dplyr)
comparison <- matrix(c(-2267,-345916,-185344,-44.4,-24.0,-57.1,"+1224","+191534","+80,347","51.4","55.4","43.4"),ncol=3,byrow=TRUE)
colnames(comparison) <- c("Daycare Services","Total, All Industries","Accommodation and Food Services")
rownames(comparison) <- c("Decline","% Decline","Recovery","% Recovery")
comparison <- as.table(comparison)
comparison
Here is how I create it. Create a new R markdown file. Next, I put the code chunk in the first chunk (look below) and then enter the word, "comparison" in the place of summary(cars) below in the section that appears as such
knitr::opts_chunk$set(echo = TRUE)
comparison <- matrix(c(-2267,-345916,-185344,-44.4,-24.0,-57.1,"+1224","+191534","+80,347","51.4","55.4","43.4"),ncol=3,byrow=TRUE)
colnames(comparison) <- c("Daycare Services","Total, All Industries","Accommodation and Food Services")
rownames(comparison) <- c("Decline","% Decline","Recovery","% Recovery")
comparison <- as.table(comparison)
comparison
summary(cars)
If we are using gt, then we do
```{r}
library(gt)
library(dplyr)
comparison <- matrix(c(-2267,-345916,-185344,-44.4,-24.0,-57.1,"+1224","+191534","+80,347","51.4","55.4","43.4"),ncol=3,byrow=TRUE)
colnames(comparison) <- c("Daycare Services","Total, All Industries","Accommodation and Food Services")
rownames(comparison) <- c("Decline","% Decline","Recovery","% Recovery")
out <- as.data.frame(comparison)
gt(out, rownames_to_stub = TRUE)
```
-output

How to create a string that can be used as LHS and assigned a value to?

I feel stupid for asking such a simple question, but I am hitting my head in the wall.
Why does the paste0() create a string that cannot be not interpreted as name for an empty object ? Is there a different way of create the LHS that would be better?
As input I have a dataframe. As an output I want to have a new filtered dataframe. This works fine as long as I manually type all the code. However, I am trying to reduce repetition, and therefore I want to create a function that does the same thing, but then it is not working anymore.
library(magrittr)
df <- data.frame(
var_a = round(runif(20), digits = 1),
var_b = sample(letters, 20)
)
### Find duplicates
df$duplicate_num <- duplicated(df$var_a)
df$duplicate_txt <- duplicated(df$var_b)
df # a check
### Create two lists of duplicates
list_of_duplicate_num <-
df %>%
filter(duplicate_num)
list_of_duplicate_num # a check
list_of_duplicate_txt <-
df %>%
filter(duplicate_txt)
list_of_duplicate_txt # a check '
So far everything works as expected.
I would like to simplify the code and make this to a function that takes the arguments "num" or "txt". But I am having problems with creating the LHS.
The below should, in my mind, do the same as the code above.
paste0("list_of_duplicate_", "num") <-
df %>%
filter(duplicate_num)
I do get an error message:
Error in paste0("list_of_duplicate_", "num") <- df %>%
filter(duplicate_num) :
target of assignment expands to non-language object
My goal is to create a function with something like this:
make_list_of_duplicates <- function(criteria = "num") {
paste0("list_of_duplicate_", criteria) <-
df %>%
filter(paste0("duplicate_", criteria))
paste0("list_of_duplicate_", criteria) # a check
}
### Create two lists of duplicates
make_list_of_duplicates("num")
make_list_of_duplicates("txt")
and then continue with some joins etc.
I have been looking to tidy evaluation, assignments, rlang::enexpr(), base::substitute(), get(), mget() and many other things, but after two day of reading and trial and error, I am convinced that there must be a an other direction to look at that I am not seeing.
I am running MS Open R 4.0.2.
I am grateful for any suggestions.
Sincerely,
Eero
I found the solution to my question, when I understood that it was a case of indirection. Because I was on a wrong track, I created lots of complications and made it more difficult than necessary. Thanks to #r2evans who pointed me in the right direction. I have in the mean time decided that I will use loops, instead of functions, but here is the working function:
## Example of using paste inside a function to refer to an object.
library(magrittr)
library(dplyr)
df <- data.frame(
var_a = round(runif(20), digits = 1),
var_b = sample(letters, 20)
)
# Find duplicates
df$duplicate_num <- duplicated(df$var_a)
df$duplicate_txt <- duplicated(df$var_b)
# SEE https://dplyr.tidyverse.org/articles/programming.html#indirection-2
make_list_of_duplicates_f2 <- function(criteria = "num") {
df %>%
filter(.data[[paste0("duplicate_", {{criteria}})]])
}
# Create two lists of duplicates
list_of_duplicates_f2_num <-
make_list_of_duplicates_f2("num")
list_of_duplicates_f2_txt <-
make_list_of_duplicates_f2("txt")

flextable package assigns changes without <-

I'm not sure if this is the correct forum to post this, but I have noticed some strange behavior with the flextable package in R, and was wondering if anyone can shed any light.
In the documentation for flextable it shows objects being modified when they are re-assigned to themselves, eg:
ft <- regulartable(head(iris))
ft <- color(ft, color = "orange", part = "body" )
However, my code is modifying the actual table even without re-assigning it, just using piping %>%:
myft <- regulartable(head(iris))
myft %>% align(j = 1, align = "left")
myft # changed
I don't think piping is the issue as it doesn't have the same effect with other packages, eg:
library(plyr)
df <- head(iris)
df %>% mutate(Sum=Sepal.Width*2)
df # unchanged
Is this a bug in flextable? Or is this by design?
It's true that you can mutate formats without assigning the object. But that's not a behavior you can rely on. This is an unwanted design ;) and should be corrected in the next versions so it is safer to assign the result if you want your code to work with future versions.

How to name a column " " in officer was able to do it previously in ReporteRs

this is a big problem for me as I need to have un-named column names inside my flextable in officer. This previously worked with the ReporteRs version.
But so far haven't been able to do this, tried using the following code:
rename(` ` = col0)
When I run try and create a flextable using this column name I get the following error message:
Error in flextable(a) :
invalid col_keys, flextable support only syntactic names
data <- head(iris) %>%
rename(` ` = Sepal.Length)
myft <- regulartable(data)
myft1<- flextable(data)
Note: the regulartable(data) works and the column name is blank.
When trying to do this with a flextable however it doesn't work and errors
Is there anyway that I am able to do this with a flextable?
Many thanks in advance
You don't need to modify your data.frame to customize the display. Having names like is risky IHMO. Read https://davidgohel.github.io/flextable/articles/layout.html#manage-headers-and-footers
library(flextable)
library(magrittr)
library(dplyr)
data <- head(iris)
myft <- regulartable(data) %>%
set_header_labels(Sepal.Length = " ")
myft1 <- flextable(data) %>%
set_header_labels(Sepal.Length = " ")
myft1

Column alignment with kableExtra using group_rows

I'm using Rmarkdown to produce a PDF of frequency tables. Producing a complex frequency table after running freq from questionr and adding row groupings with group_rows leads to an alignment problem on the last line of the first group. Reproducible example here:
---
output:
pdf_document:
latex_engine: xelatex
fig_caption: true
---
```{r}
library(haven)
library(questionr)
library(dplyr)
library(magrittr)
library(knitr)
library(kableExtra)
# Build some data
x <- rep(c(1,0),times=50)
y <- c(rep(1,times=25),rep(0,times=75))
z <- c(rep(1,times=75),rep(0,times=25))
# Function to run frequencies on several variables at a time
MassFreq <- function(...){
step1 <- list(...) # Wrap items into a list
step2 <- lapply(step1,freq,total=TRUE) # run frequencies on all items
step3 <- bind_rows(step2) # collapse list results into single df
Response <- unlist(lapply(step2,row.names),recursive=FALSE) # Get row names from frequencies
step4 <- cbind(Response,step3) #Stick row names at front of the dataframe
}
# Run function - returns a data frame object
test <- MassFreq(x,y,z)
# Build table
test %>%
kable(format="latex", booktabs = TRUE, row.names=FALSE) %>%
group_rows("Group 1",1,3) %>%
group_rows("Group 2",4,6) %>%
group_rows("Group 3",7,9)
```
Gives me this upon knitting:
The first "Total" text is right-aligned, but everything else is fine. Adding align=('lrrr') in the kable line does nothing, and align=('crrr') is kind of a mess. Using the index method for group_rows produces the same results. When leaving out the group_rows commands, everything in the first column is left-aligned and looks fine. My hunch is that kableExtra isn't playing well with questionr because the "Total" rows are created when running questionr::freq.
This is a bug in current CRAN version of kableExtra, 0.5.2. It has been fixed in the dev version. I will make a CRAN release next week.

Resources