我将使用 Rshiny 和 ggplot2 库以动态方式创建绘图。我用于创建绘图的函数是 ggplot(),我需要在选项卡集内的选项卡上显示绘图。
绘图的位置是固定的,但绘图类型、x 和 y 的列、甚至数据列的数量以及 aes 映射的美学参数(例如颜色、填充等)都存储并映射在变量“aes_mapping”中”。绘图类型作为字符“plot_type”提供。数据以数据框“数据”形式给出。
最后必须使用 renderPlot 函数在对象“output[[plot_id]]”中显示绘图。
我尝试使用 do.call 创建 aes 映射动态函数:
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))
})
这会导致错误:
Error in as.vector(x, "character") :
cannot coerce type 'environment' to vector of type 'character'
我尝试定义一个环境函数,但错误仍然存在。
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))
})
当我使用 browser() 在输出[[plot_id]]...块之前停止并尝试控制台中的行时,我可以创建没有任何错误的绘图并使用 print(p) 显示它。
然后,我尝试了解有关变量的更多信息:
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`
我只尝试使用强制请求的参数 x 和 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
我尝试了解有关 aes 字符串的类的更多信息:
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"
当我让脚本运行并且它是有效的并且当我通过控制台命令执行该操作时创建绘图时,错误仍然存在。
有人看到我做错了什么吗?是否可以在使用闪亮的应用程序时动态创建一个绘图?
这应该是产生错误的运行代码。但事实并非如此。我无法以比原来相当大的更小的方式复制它。但变量创建正确:
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)
将 opp 保留为 NA 将意味着剧情中不会出现任何内容 不适用
但如果把这些放在一边,下面的内容我认为你的意图是这样的:
aes_mapping_list <- setNames(c(mppv, oppv), c(mpp, opp))
aes_mapping_list <- aes_mapping_list[!is.na(aes_mapping_list)]
# create aes dynamically
aes_mapping <- do.call(aes_string, aes_mapping_list)
output[[plot_id]] <- renderPlot({
data_df <- as.data.frame(data)
p <- ggplot(data_df) + do.call(plot_type, list(mapping = aes_mapping))
p
})