I am about to create plots in a dynamic way using R shiny and the ggplot2 library. The function I use for the plot creation is ggplot() and I need to display the plot on a tab inside of a tabset.
The position of the plot is fixed but the plot type, the columns for x and y, even the number of data columns and the astethic parameters of aes mapping such as colour, fill, etc. are stored and mapped in the variable “aes_mapping”. The plot type is provided as a character “plot_type”. The data is given as a data frame “data”.
In the end the plot has to be shown in the object “output[[plot_id]]” using the renderPlot function.
I tried to create the functions for aes mapping danamically by using do.call:
output[[plot_id]] <- renderPlot({
# convert ot data frame
data_df <- as.data.frame(data)
# create plot
p <- ggplot(data_df) + do.call(get(plot_type), list(mapping = aes_mapping))
})
This leads to an error:
Error in as.vector(x, "character") :
cannot coerce type 'environment' to vector of type 'character'
I tried to define an environment function but the error persists.
output[[plot_id]] <- renderPlot({
data_df <- as.data.frame(data)
plot_function <- get(plot_type, mode = "function", envir = asNamespace("ggplot2"))
p <- ggplot(data_df) + do.call(get(plot_type), list(mapping = aes_mapping))
})
When I use browser() to stop just before the output[[plot_id]]… block and try the lines in the console then I can create the plot without any error and display it with print(p).
Then, I tried to find out more about the variables:
Browse[1]> class(data_df)
[1] "data.frame"
Browse[1]> class(plot_type)
[1] "character"
Browse[1]> class(aes_mapping)
[1] "uneval"
Browse[1]> print(aes_mapping)
Aesthetic mapping:
* `alpha` -> NULL
* `colour` -> NULL
* `fill` -> NULL
* `group` -> NULL
* `shape` -> NULL
* `size` -> NULL
* `x` -> `msglvl_times_readable`
* `y` -> `msglvl_seqNumber`
I tried only to use the mandatory requested parameters x and y:
Browse[1]> m <- list(aes_mapping$x, aes_mapping$y)
Browse[1]> class(m)
[1] "list"
Browse[1]> print(m)
[[1]]
<quosure>
expr: ^msglvl_times_readable
env: 0x0000019d7aa09328
[[2]]
<quosure>
expr: ^msglvl_seqNumber
env: 0x0000019d7aa09328
And I tried to find out more about the classes fo the aes string:
Browse[1]> plot_function <- get(plot_type, mode = "function", envir = asNamespace("ggplot2"))
Browse[1]> c <- plot_function(mapping = aes_mapping)
Browse[1]> class(c)
[1] "LayerInstance" "Layer" "ggproto" "gg"
The error persists when I let the script run and it is valid and the plot is created when I do it by console command.
Does someone see what I am doing wrong? Is it possible to create a plot that dynamically when using a shiny app?
This should be a running code which is producing the error. But it isn’t. I can’t reproduce it in a smaller way than the original which is quite large. But the variables are created correctly:
library(shiny)
library(ggplot2)
library(data.table)
# define ui object
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
actionButton(inputId = "action", label = "Action")
),
mainPanel(
tabsetPanel(
id = "tabset1",
tabPanel("plot_1",
plotOutput(outputId = "plot_1"))
)
)
)
)
server <- function(input, output, session) {
observeEvent(input$action,{
browser()
data <- data.table(
msglvl_times_readable= 1:10,
msglvl_seqNumber= rnorm(10),
z_var = runif(10)
)
settings <- list(
plot_1 = list(
"geom_point",
list("msglvl_times_readable",
"msglvl_seqNumber"),
list(NA, NA, NA, NA, NA, NA)
)
)
mapping_param <- list(
"geom_point",
c("x", "y"),
c("alpha", "colour", "fill", "group", "shape", "size")
)
plot_id <- "plot_1"
#create plot
# get plot type
plot_type <- settings[[plot_id]][[1]]
# get mpp
mpp <- mapping_param[[2]]
# get mppv
mppv <- settings[[plot_id]][[2]]
# get opp
opp <- mapping_param[[3]]
# get oppv
oppv <- settings[[plot_id]][[3]]
# create aes mapping
aes_mapping_list <- setNames(c(mppv, oppv), c(mpp, opp))
# create aes dynamically
aes_mapping <- do.call(aes_string, aes_mapping_list)
output[[plot_id]] <- renderPlot({
data_df <- as.data.frame(data)
plot_function <- get(plot_type, mode = "function", envir = asNamespace("ggplot2"))
p <- ggplot(data_df) + do.call(get(plot_type), list(mapping = aes_mapping))
})
})
}
# start ui
shinyApp(ui, server)
Bastian is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.