当使用for循环渲染一些图时,我得到的结果我并不理解。所有的情节都等于(预期的)最后一个。我希望在下面的例子中更清楚地说明这一点。注意,plot1显示了' 6' (最后一个),而不是' 5' (如预期)。 任何人都可以解释这个和/或给出一个避免这种行为的解决方案 闪亮的ui:
shinyUI (fluidPage(
fluidRow (
column (6, plotOutput ('plot1', height = "180px")),
column (6, plotOutput ('plot2', height = "180px"))
),
fluidRow (
column (6, plotOutput ('plot3', height = "180px")),
column (6, plotOutput ('plot4', height = "180px"))
)
))
闪亮的服务器:
shinyServer (function (input, output, session) {
require (ggplot2)
plotId <- c('plot1', 'plot2', 'plot3', 'plot4')
pw <- initPlotWindows ()
output[['plot1']] <- renderPlot ({pw[[1]]})
output[['plot2']] <- renderPlot ({pw[[2]]})
output[['plot3']] <- renderPlot ({pw[[3]]})
output[['plot4']] <- renderPlot ({pw[[4]]})
id <- 'plot1'
i <- 5
output[[id]] <- renderPlot ({pw[[i]]})
id <- 'plot3'
i <- 6
# output[[id]] <- renderPlot ({pw[[i]]})
})
initPlotWindows <- function () {
pw <- vector (mode = 'list', length = 6) # plot window data
for (i in 1:6) pw[[i]] <- p_empty (plotN = i)
pw
}
p_empty <- function (plotN) {
p <- ggplot()
p <- p + annotate("text", label = plotN, x = .5, y = .5, size = 20, colour = "grey")
p <- p + theme(axis.ticks.x = element_blank(), axis.text.x = element_blank(), axis.title.x=element_blank())
p <- p + theme(axis.ticks.y = element_blank(), axis.text.y = element_blank(), axis.title.y=element_blank())
p
}
答案 0 :(得分:2)
发生这种情况的原因是因为闪亮不会逐行执行服务器端代码。 Shiny在开始时执行一次所有非反应性代码。但是renderPlot()
和其他反应代码只会在必要时运行。 (当他们被召唤时)
所以发生的事情是,它分配5,然后6分配给i
,之后只渲染了图。
output[[id]] <- renderPlot ({
print("section D")
pw[[i]]})
您可以使用print()
功能在R控制台中轻松查看:
shinyServer (function (input, output, session) {
print("section A")
require (ggplot2)
plotId <- c('plot1', 'plot2', 'plot3', 'plot4')
pw <- initPlotWindows ()
output[['plot1']] <- renderPlot ({
print("section B1")
pw[[1]]})
output[['plot2']] <- renderPlot ({
print("section B2")
pw[[2]]})
output[['plot3']] <- renderPlot ({
print("section B3")
pw[[3]]})
output[['plot4']] <- renderPlot ({
print("section B4")
pw[[4]]})
print("section C")
id <- 'plot1'
i <- 5
output[[id]] <- renderPlot ({
print("section D")
pw[[i]]})
print("section E")
id <- 'plot3'
i <- 6
# output[[id]] <- renderPlot ({pw[[i]]})
})
控制台输出:
[1] "section A"
[1] "section C"
[1] "section E"
[1] "section B1"
[1] "section B2"
[1] "section B3"
[1] "section B4"
[1] "section D"
至于output[[id]]
,id
会在开始时进行评估,因此output[[id]]
变为output[[plot1]]
。但pw[[i]]
仅在闪亮要求渲染图时进行评估,即在将值设置为5然后再设置为6之后。
如果您希望plot1显示5,那么您可以在id
之外指定renderPlot()
,并在i
内指定renderPlot()
:
id <- 'plot1'
output[[id]] <- renderPlot ({
i <- 5
pw[[i]]})
答案 1 :(得分:0)
谢谢GyD,
根据你的回答,我得出结论,正常的for循环是不可能的。运行变量&#39; i&#39;将在外部定义,而不是在renderPlot()内定义。
所以我似乎必须至少使用eval(parse())来实现renderPlot()。
像for循环一样:
for ( i in 1:4) {
pltId <- paste ('plot', i, sep='')
output[[pltId]] <- renderPlot ({pw[i]})
}
然后将成为(使用eval(parse())进行整个分配):
for ( i in 1:4) {
eval (parse (text = paste ("output[['plot", i, "']] <- renderPlot ({pw[", i, "]})", sep='')))
}
答案 2 :(得分:0)
您的答案应该有效,但您可以使用循环生成UI元素和服务器端。 (不知道你是否感兴趣)
我不是R中for
循环的忠实粉丝,所以我使用的是lapply
。
library(shiny)
library(ggplot2)
# I want to plot these elements
vec <- c(5, 2, 3, 4)
# Defining some functions
initPlotWindows <- function () {
pw <- vector (mode = 'list', length = 6) # plot window data
for (i in vec) pw[[i]] <- p_empty (plotN = i)
pw
}
p_empty <- function (plotN) {
p <- ggplot()
p <- p + annotate("text", label = plotN, x = .5, y = .5, size = 20, colour = "grey")
p <- p + theme(axis.ticks.x = element_blank(), axis.text.x = element_blank(), axis.title.x=element_blank())
p <- p + theme(axis.ticks.y = element_blank(), axis.text.y = element_blank(), axis.title.y=element_blank())
p
}
# Creating pw list
pw <- initPlotWindows()
ui <- fluidPage(
# Creating UI from loop
lapply(vec, function(i) {
column(6, plotOutput(paste0('plot', i), height = "180px"))
})
)
server <- function(input, output, session){
# Generating UI output from loop
lapply(vec, function(i) {
output[[paste0('plot', i)]] <- renderPlot({
pw[[i]]
})
})
}
shinyApp(ui, server)