在 R Shiny 中,isTruthy() 函数没有按照我认为应该的方式工作
In R Shiny, isTruthy() function is not working the way I think it should
我相信我对 isTruthy()
函数的工作原理存在根本性的误解。
在下面的 MWE 中,对第一个矩阵的输入求和并在 10 个周期内绘制直线。但是,只有在矩阵 2 创建函数像此 MWE 中一样被注释掉时,这才有效。当矩阵 2 的创建未被注释时(矩阵 2 与矩阵 1 做同样的事情:输入被求和并绘制,但绘制为单独的线),矩阵 1 输入不再被求和和绘制。
问题似乎出在 server
部分的 plotData <- reactive({...}
函数下的 if(isTruthy(input$matrix2)){...
中。我认为 if(isTruthy(...)
在这种情况下意味着如果手动输入矩阵 2,则绘制矩阵 2,否则跳到 else{...}
并仅绘制矩阵 1。(请注意,在较大的应用程序中,此代码派生自,矩阵 2 在模态对话框中呈现,因此绘图被这样分解的原因)。
我该如何更改此代码,以便仅在手动输入矩阵 2 时才绘制矩阵 2;否则绘制矩阵 1?为了解决我遇到的一个更大的问题,即使存在矩阵 2,我也希望矩阵 1 能够正确绘制。
library(dplyr)
library(ggplot2)
library(shiny)
library(shinyMatrix)
sumMat <- function(x){return(rep(sum(x,na.rm = TRUE), 10))}
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
matrixInput("matrix1",
value = matrix(c(60,5), ncol = 2, dimnames = list(NULL,c("X","Y"))),
rows = list(extend = TRUE, delete = TRUE), class = "numeric"),
# matrixInput("matrix2",
# label = "Matrix 2 (Value Y applied in Period X):",
# value = matrix(c(60,5),ncol=2,dimnames=list(NULL,rep("Scenario 1",2))),
# rows = list(extend = TRUE, delete = TRUE),
# cols = list(extend = TRUE, delta = 2, delete = TRUE, multiheader = TRUE),
# class = "numeric"),
),
mainPanel(plotOutput("plot"))
)
)
server <- function(input, output, session){
observeEvent(input$matrix1, {
tmpMat1 <- input$matrix1
if(any(rownames(input$matrix1) == "")){rownames(tmpMat1) <- paste("Row", seq_len(nrow(input$matrix1)))}
updateMatrixInput(session, inputId = "matrix1", value = tmpMat1)
})
plotData <- reactive({
tryCatch(
if(isTruthy(input$matrix2)){
lapply(seq_len(ncol(input$matrix2)/2),
function(i){
tibble(Scenario = colnames(input$matrix2)[i*2-1],
X = seq_len(10),Y = sumMat(input$matrix2[,(i*2-1):(i*2), drop = FALSE]))
}) %>% bind_rows()
} else
{tibble(Scenario = "Scenario 1", X = seq_len(10),Y = sumMat(input$matrix1))},
error = function(e) NULL)
})
output$plot <- renderPlot({
req(plotData())
plotData() %>% ggplot() + geom_line(aes(x = X, y = Y, colour = as.factor(Scenario)))
})
}
shinyApp(ui, server)
请参阅 CuriousJorge 对 Limey 评论的回复中的错误解释(isTruthy()
的错误使用,plotData()
函数中有缺陷的 if/then/else 逻辑。
注意矩阵 1 如何将“下游”输入矩阵 2 作为场景 1。
下面是解析后的代码:
library(dplyr)
library(ggplot2)
library(shiny)
library(shinyMatrix)
sumMat <- function(x){return(rep(sum(x,na.rm = TRUE), 10))}
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
matrixInput("matrix1",
label ="Matrix 1 (scenario 1):",
value = matrix(c(60,5), nrow = 1, ncol = 2, dimnames = list(NULL,c("X","Y"))),
rows = list(extend = TRUE, delete = TRUE),
class = "numeric"),
matrixInput("matrix2",
label = "Matrix 2:",
value = matrix(c(60,5), ncol = 2, dimnames = list(NULL, rep("Scenario 1", 2))),
rows = list(extend = TRUE, delete = TRUE),
cols = list(extend = TRUE, delta = 2, delete = TRUE, multiheader = TRUE),
class = "numeric")
),
mainPanel(plotOutput("plot"))
)
)
server <- function(input, output, session){
observeEvent(input$matrix1, {
a <- apply(input$matrix2,2,'length<-',max(nrow(input$matrix2),nrow(input$matrix1)))
b <- apply(input$matrix1,2,'length<-',max(nrow(input$matrix2),nrow(input$matrix1)))
c <- if(length(a) == 2){c(b)} else {c(b,a[,-1:-2])}
d <- ncol(input$matrix2)
tmpMat2 <- matrix(c(c), ncol = d)
colnames(tmpMat2) <- paste("Scenario",rep(1:ncol(tmpMat2),each=2,length.out=ncol(tmpMat2)))
if(any(rownames(input$matrix1) == "")){
tmpMat1 <- input$matrix1
rownames(tmpMat1) <- paste("Row", seq_len(nrow(input$matrix1)))
updateMatrixInput(session, inputId = "matrix1", value = tmpMat1)
}
updateMatrixInput(session, inputId = "matrix2", value = tmpMat2)
})
observeEvent(input$matrix2, {
if(any(colnames(input$matrix2) == "")){
tmpMat2 <- input$matrix2
colnames(tmpMat2) <- paste("Scenario",rep(1:ncol(tmpMat2),each=2,length.out=ncol(tmpMat2)))
updateMatrixInput(session, inputId = "matrix2", value = tmpMat2)
}
if(any(rownames(input$matrix2) == "")){
tmpMat2 <- input$matrix2
rownames(tmpMat2) <- paste("Row", seq_len(nrow(input$matrix2)))
updateMatrixInput(session, inputId = "matrix2", value = tmpMat2)
}
input$matrix2
})
plotData <- reactive({
tryCatch(
lapply(seq_len(ncol(input$matrix2)/2),
function(i){
tibble(
Scenario = colnames(input$matrix2)[i*2-1],
X = seq_len(10),
Y = sumMat(input$matrix2[,(i*2-1):(i*2), drop = FALSE])
)
}) %>% bind_rows(),
error = function(e) NULL
)
})
output$plot <- renderPlot({
req(plotData())
plotData() %>% ggplot() +
geom_line(aes(x = X, y = Y, colour = as.factor(Scenario))) +
theme(legend.title=element_blank())
})
}
shinyApp(ui, server)
我相信我对 isTruthy()
函数的工作原理存在根本性的误解。
在下面的 MWE 中,对第一个矩阵的输入求和并在 10 个周期内绘制直线。但是,只有在矩阵 2 创建函数像此 MWE 中一样被注释掉时,这才有效。当矩阵 2 的创建未被注释时(矩阵 2 与矩阵 1 做同样的事情:输入被求和并绘制,但绘制为单独的线),矩阵 1 输入不再被求和和绘制。
问题似乎出在 server
部分的 plotData <- reactive({...}
函数下的 if(isTruthy(input$matrix2)){...
中。我认为 if(isTruthy(...)
在这种情况下意味着如果手动输入矩阵 2,则绘制矩阵 2,否则跳到 else{...}
并仅绘制矩阵 1。(请注意,在较大的应用程序中,此代码派生自,矩阵 2 在模态对话框中呈现,因此绘图被这样分解的原因)。
我该如何更改此代码,以便仅在手动输入矩阵 2 时才绘制矩阵 2;否则绘制矩阵 1?为了解决我遇到的一个更大的问题,即使存在矩阵 2,我也希望矩阵 1 能够正确绘制。
library(dplyr)
library(ggplot2)
library(shiny)
library(shinyMatrix)
sumMat <- function(x){return(rep(sum(x,na.rm = TRUE), 10))}
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
matrixInput("matrix1",
value = matrix(c(60,5), ncol = 2, dimnames = list(NULL,c("X","Y"))),
rows = list(extend = TRUE, delete = TRUE), class = "numeric"),
# matrixInput("matrix2",
# label = "Matrix 2 (Value Y applied in Period X):",
# value = matrix(c(60,5),ncol=2,dimnames=list(NULL,rep("Scenario 1",2))),
# rows = list(extend = TRUE, delete = TRUE),
# cols = list(extend = TRUE, delta = 2, delete = TRUE, multiheader = TRUE),
# class = "numeric"),
),
mainPanel(plotOutput("plot"))
)
)
server <- function(input, output, session){
observeEvent(input$matrix1, {
tmpMat1 <- input$matrix1
if(any(rownames(input$matrix1) == "")){rownames(tmpMat1) <- paste("Row", seq_len(nrow(input$matrix1)))}
updateMatrixInput(session, inputId = "matrix1", value = tmpMat1)
})
plotData <- reactive({
tryCatch(
if(isTruthy(input$matrix2)){
lapply(seq_len(ncol(input$matrix2)/2),
function(i){
tibble(Scenario = colnames(input$matrix2)[i*2-1],
X = seq_len(10),Y = sumMat(input$matrix2[,(i*2-1):(i*2), drop = FALSE]))
}) %>% bind_rows()
} else
{tibble(Scenario = "Scenario 1", X = seq_len(10),Y = sumMat(input$matrix1))},
error = function(e) NULL)
})
output$plot <- renderPlot({
req(plotData())
plotData() %>% ggplot() + geom_line(aes(x = X, y = Y, colour = as.factor(Scenario)))
})
}
shinyApp(ui, server)
请参阅 CuriousJorge 对 Limey 评论的回复中的错误解释(isTruthy()
的错误使用,plotData()
函数中有缺陷的 if/then/else 逻辑。
注意矩阵 1 如何将“下游”输入矩阵 2 作为场景 1。
下面是解析后的代码:
library(dplyr)
library(ggplot2)
library(shiny)
library(shinyMatrix)
sumMat <- function(x){return(rep(sum(x,na.rm = TRUE), 10))}
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
matrixInput("matrix1",
label ="Matrix 1 (scenario 1):",
value = matrix(c(60,5), nrow = 1, ncol = 2, dimnames = list(NULL,c("X","Y"))),
rows = list(extend = TRUE, delete = TRUE),
class = "numeric"),
matrixInput("matrix2",
label = "Matrix 2:",
value = matrix(c(60,5), ncol = 2, dimnames = list(NULL, rep("Scenario 1", 2))),
rows = list(extend = TRUE, delete = TRUE),
cols = list(extend = TRUE, delta = 2, delete = TRUE, multiheader = TRUE),
class = "numeric")
),
mainPanel(plotOutput("plot"))
)
)
server <- function(input, output, session){
observeEvent(input$matrix1, {
a <- apply(input$matrix2,2,'length<-',max(nrow(input$matrix2),nrow(input$matrix1)))
b <- apply(input$matrix1,2,'length<-',max(nrow(input$matrix2),nrow(input$matrix1)))
c <- if(length(a) == 2){c(b)} else {c(b,a[,-1:-2])}
d <- ncol(input$matrix2)
tmpMat2 <- matrix(c(c), ncol = d)
colnames(tmpMat2) <- paste("Scenario",rep(1:ncol(tmpMat2),each=2,length.out=ncol(tmpMat2)))
if(any(rownames(input$matrix1) == "")){
tmpMat1 <- input$matrix1
rownames(tmpMat1) <- paste("Row", seq_len(nrow(input$matrix1)))
updateMatrixInput(session, inputId = "matrix1", value = tmpMat1)
}
updateMatrixInput(session, inputId = "matrix2", value = tmpMat2)
})
observeEvent(input$matrix2, {
if(any(colnames(input$matrix2) == "")){
tmpMat2 <- input$matrix2
colnames(tmpMat2) <- paste("Scenario",rep(1:ncol(tmpMat2),each=2,length.out=ncol(tmpMat2)))
updateMatrixInput(session, inputId = "matrix2", value = tmpMat2)
}
if(any(rownames(input$matrix2) == "")){
tmpMat2 <- input$matrix2
rownames(tmpMat2) <- paste("Row", seq_len(nrow(input$matrix2)))
updateMatrixInput(session, inputId = "matrix2", value = tmpMat2)
}
input$matrix2
})
plotData <- reactive({
tryCatch(
lapply(seq_len(ncol(input$matrix2)/2),
function(i){
tibble(
Scenario = colnames(input$matrix2)[i*2-1],
X = seq_len(10),
Y = sumMat(input$matrix2[,(i*2-1):(i*2), drop = FALSE])
)
}) %>% bind_rows(),
error = function(e) NULL
)
})
output$plot <- renderPlot({
req(plotData())
plotData() %>% ggplot() +
geom_line(aes(x = X, y = Y, colour = as.factor(Scenario))) +
theme(legend.title=element_blank())
})
}
shinyApp(ui, server)