Save local ggplot graphics and use in reactable table - r

I'd like to generate small ggplot graphics and use them inline in a reactable. I can generate the plots needed (1 per row), but when inserting them into the table, they come up as broken images. I imagine it has something to do with the file paths?
Note: This will ultimately be used in a shiny app where the graphics are generated dynamically. I am doing this in reactable because I plan to combine this with the expandable rows feature.
Here is some reproducible code
library(tidyverse)
library(palmerpenguins)
library(reactable)
#get list of species names
species <- penguins %>% select(species ) %>%
distinct() %>% pull()
# make a simple df
plot_data <- penguins %>%
group_by(species) %>%
summarize(mean = mean(bill_length_mm, na.rm=T))
# for loop to generate and save plots
for(i in species){
tmp_plot <-
plot_data %>%
filter(species == i) %>%
ggplot(aes(y=species, x=mean))+
geom_col()+
theme_void()
file_name <- i %>% janitor::make_clean_names()
ggsave(plot = tmp_plot,
filename = paste0("plots/",file_name,".png"),
width=4,
height=.5)
}
#make a table
species %>%
as.data.frame() %>%
rename("species" = 1) %>%
mutate(plot = paste0("<img src='plots/", janitor::make_clean_names(species),".png' />")) %>%
reactable(
columns = list(
plot = colDef(html = TRUE,
resizable = TRUE,
show=T)
))
Here is what I get:
Just as a check, doing this loads the graphic: magick::image_read("plots/adelie.png") so I am not sure what I am missing.

Related

Automate naming of table and export as image?

I have this automated script that produces a table with frequencies of "thetarget" tokens by year:
library(quanteda)
vec <- c("Apple", "Google")
out <- map(vec, ~
df %>%
filter(str_detect(collectionName, .x)) %>%
filter(str_detect(Year, paste(years, collapse = "|"))) %>%
corpus(text_field = "text") %>%
tokens() %>%
tokens_select(thetarget) %>%
dfm() %>%
dfm_group(groups = "Year") %>%
convert(to = "data.frame")
)
names(out) <- sub("^(...).*\\s+(\\S)$", "\\1\\2", vec)
Using
View(out$Apple)
Produces the corresponding table.
I am trying to automate the export of these tables as a pdf or jpeg with the name of the file being "Apple" for example.
Is there a way to do this?
TIA
I can't execute your code chunk (problem with function convert, from which library is it?) - but it isn't a problem.
Exist a lot of solutions, but, f.e., you can use packages gt or flextable for this task (pile of output types).
First of all, install the webshot and PhantomJS.
And after you can install other packages (gt and flextable). See examples:
(gt)
tab_1 <-
gtcars %>%
dplyr::select(model, year, hp, trq) %>%
dplyr::slice(1:5) %>%
gt(rowname_col = "model") %>%
tab_stubhead(label = "car") %>%
gtsave("tab_1.png", expand = 10, path = "********")
(flextable)
ft <- flextable(head(mtcars))
save_as_image(x = ft, path = "********\\image_name.png")

What is a good approach to add sparkline chart to an R gt table

I am trying to use R sparkline with gt. My question is very similar to this one Is it possible to use sparkline with gt?, but on top of simply using sparkline with gt as in the referenced question, I am trying to use it as part of the summary row. Below is the picture of what I have achieved so far. Here are my two questions:
How can I remove the two grey lines that are printed as part of the sparkline chart in the summary row?
Is there a better way to add sparkline to the summary row of a gt table?
library(tidyverse)
library(sparkline)
library(gt)
# toy data
df <- tibble(
name = rep(c("A", "B"), each = 20),
value = runif(40, min = -10, max = 10) %>% cumsum()
) %>%
group_by(name) %>%
mutate(
index = row_number()
) %>% ungroup()
# preparing the data for the standard sparkline
regular_sparkline_df <- df %>%
group_by(name) %>%
summarise(
chart = spk_chr(
value,
type="line"
)
)
# here I try to prepare the data for the summary row by getting the whole gt table and then removing the header
summary_row_sparkline_df <- df %>%
group_by(index) %>%
summarise(value = sum(value)) %>% ungroup() %>%
summarise(
chart = spk_chr(
value,
type="line"
)
) %>%
gt() %>%
fmt_markdown(columns = vars(chart)) %>%
gt:::as.tags.gt_tbl() %>%
htmltools::attachDependencies(htmlwidgets::getDependency("sparkline")) %>%
as.character() %>%
gsub('<thead.+</thead>', "", .) # removing the header of the table
# building the html and adding dependencies
p_html <- regular_sparkline_df %>%
gt() %>%
fmt_markdown(columns = vars(chart)) %>%
grand_summary_rows(
columns = "chart",
fns = list(Total = ~as.character(summary_row_sparkline_df)),
formatter = fmt_markdown
) %>%
gt:::as.tags.gt_tbl() %>%
htmltools::attachDependencies(htmlwidgets::getDependency("sparkline"))
# seeing the table in the RStudio
print(p_html, browse = interactive())

ggplot plots within a table

Problem
I would like to produce a good looking table which has ggplots within the cells of one column. One key element is that I would like to create a pdf output of this table eventually.
What I have tried so far
Hopefully the example below is understandable. Essentially I found that I can achieve what I want using the gt package. The problem is this creates a html widget which you then have to use phantomJS and webshot to export as a pdf.
library(dplyr)
library(purrr)
library(gt)
library(ggplot2)
dat = tibble(
RowLabel = letters[1:5],
Numeric = seq(100,500,100)
) %>%
mutate(
plotData = RowLabel %>% map(function(pos){
tibble(y=runif(10)*100) %>%
arrange(desc(y)) %>%
mutate(x=row_number())
}),
plot_obj = plotData %>% map(function(df){
df %>%
ggplot(aes(x=x,y=y))+
geom_col()
}),
plot_grob = plot_obj %>% map(cowplot::as_grob)
)
tab = dat %>%
select(RowLabel, Numeric) %>%
mutate(
ggplot = NA
) %>%
gt() %>%
text_transform(
locations = cells_body(vars(ggplot)),
fn = function(x) {
dat$plot_obj %>%
map(ggplot_image, height = px(50))
}
)
tab
What do I want
I would like an output which is similar to the above example. However, I would like a solution which does not require me to use html widgets and can be saved directly as a pdf without the use of other programs. Is this possible to do using ggplot? I have started to learn more about grids/grobs/gtables etc but have not made any meaningful progress.
Thanks in advance!
Perhaps you could tweak the gtsave() function to suit? E.g.
library(dplyr)
library(purrr)
library(gt)
library(ggplot2)
dat = tibble(
RowLabel = letters[1:5],
Numeric = seq(100,500,100)
) %>%
mutate(
plotData = RowLabel %>% map(function(pos){
tibble(y=runif(10)*100) %>%
arrange(desc(y)) %>%
mutate(x=row_number())
}),
plot_obj = plotData %>% map(function(df){
df %>%
ggplot(aes(x=x,y=y))+
geom_col()
}),
plot_grob = plot_obj %>% map(cowplot::as_grob)
)
tab = dat %>%
select(RowLabel, Numeric) %>%
mutate(
ggplot = NA
) %>%
gt() %>%
text_transform(
locations = cells_body(vars(ggplot)),
fn = function(x) {
dat$plot_obj %>%
map(ggplot_image, height = px(50))
}
)
tab %>%
gt::gtsave(filename = "test.pdf", vwidth = 180, vheight = 250)
(R v4.0.3 / gt v0.2.2)

Multiple line graphs in ggvis using for loop

I am trying to create multiple line graphs using ggvis. I am able to plot multiple lines but I am unable to add tooltip for these lines. I need to show the x and y value when I hover the mouse on the lines. I also am unable to add points to the lines in the for loop.
Below is a simplified example I am working with. column "c1" is the x values and columns "c2", "c3" and "c4" are to be plotted(lines with points and tooltip)
Screenshot of the plot
mydf <- data.frame(c(1:10),c(11:20), c(21:30), c(31:40))
v <- c("c1","c2","c3", "c4")
names(mydf) <- v
myggv <- mydf %>% ggvis(x = ~c1, y = ~c2) %>% layer_lines() %>% layer_points() %>% add_tooltip( function(mydf){paste0("x:",mydf$c1,"<br>","y:",mydf$c2)}, "hover")
for(r in v[2:length(v)]){
myggv <- (myggv %>% layer_paths(x = ~c1, y = as.name(r)) %>% layer_points()
%>% add_tooltip( function(mydf){paste0("x:",mydf$c1,"<br>","y:",mydf[,r] )}, "hover"))
}
Thanks
The best approach here is to not use a for loop. I mean, you can, but it's not the way ggvis approaches things. Also I can't get the tooltip to work in the loop (it gives the only the correct result for the last added line. But here is how I would do it anway:
mydf <- data.frame(c1 = c(1:10),
c2 = c(11:20),
c3 = c(21:30),
c4 = c(31:40))
myggv <- ggvis(mydf)
for (r in names(mydf)[-1]) {
myggv <- (myggv %>%
layer_paths(x = ~c1, y = as.name(r)) %>%
layer_points(x = ~c1, y = as.name(r)) %>%
add_tooltip(function(mydf) {
paste0("x:", mydf[[1]], "<br>", "y:", mydf[[r]])}, "hover"))
}
The nicer way is to restructure your data, and then use group_by to create seperate lines. As an added benefit, this is perhaps nicer to read. This way your tooltips also work:
mydf2 <- tidyr::gather(mydf, 'var', 'val', -c1)
myggv2 <- mydf2 %>%
ggvis(x = ~c1, y = ~val) %>%
layer_points() %>%
add_tooltip(function(d) { paste0("x:", d$c1, "<br>", "y:", d$val) }, "hover") %>%
group_by(var) %>%
layer_paths()
You might want to use layer_lines() instead of layer_paths().

Multiple plots from multiple data frames using ggvis in shiny in R

How do I plot multiple series from different data frames, with different numbers of rows on one ggvis plot?
shinyServer(function(input, output, session) {
vis1 <- reactive({
df2 <-data.frame(csv1)
df3 <- data.frame(csv2)
long2 <- array()
matrix2<-data.frame(Col1,Col2,Col3,Col4)
matrix2$long2 = as.character(paste0("Col3: ",Col3,", Col4: ",Col4))
matrix2 # What does this line do?
})
vis1 %>%
ggvis(x = ~Col1, y = ~Col2,fill = ~Col4, key:= ~long2) %>%
layer_points() %>%
add_axis("x", title = "Col1") %>%
scale_numeric("x", domain = c(0, 130), nice = FALSE, clamp = TRUE)%>%
add_axis("y", title = "Col2") %>%
scale_numeric("y", domain = c(0, 8000), nice = FALSE, clamp = TRUE)%>%
add_tooltip(function(matrix2){
paste0("Col2: ", matrix2$Col2, "<br>", "Col1: ", matrix2$Col1, "<br>", " ", as.character(matrix2$long2))
}, "hover") %>%
layer_paths(data = df2, x = ~Col1,y = ~Col2,fill:="green") %>%
bind_shiny("plot_col2")#,"plot_ui_col2")
output$matrix2_table <- renderTable({
vis1()[,c("Col1","Col2","Col3","Col4")]
})
This is most of the server.R code, with ui.R code that works fine with one series plotted on these axes.
But trying to put the data from two data frames on these axes just returns
"Error in add_data(vis, data, data_name) : object 'df2' not found"
Doesn't even get to df3.
How do I get it to recognise df2, then use that data to plot the second series?
I get that plotting two series from the same data frame is done like this:
df %>% ggvis(~x,~y) layer_points() %>%
df %>% layer_points(~x,~y1)
There abouts, but how is it done with different numbers of points and from different data frames?
Thank you.
I put everything in the same data frame, in the same columns, just added more rows, also added a colours column, so they would be plotted in different colours.
The first thing to do was to make a much larger data frame in the unnamed function section at the top (only executes once).

Resources