在 R 中,为什么我得到 "Error in [: (subscript) logical subscript too long"?
In R, why am I getting "Error in [: (subscript) logical subscript too long"?
下面的 MWE 代码 1 工作正常,在计算 2 列数字的和积时,sumproduct 输入矩阵水平扩展以适应额外的 sumproduct 场景。
下面的 MWE 代码 2 是对 MWE 代码 1 的修改,使输入矩阵也可以垂直扩展,因此用户可以在 sumproduct 计算中添加要求和的元素行。当我 运行 MWE 代码 2 时,代码崩溃给我“Error in [: (subscript) logical subscript too long”。
为什么会出现此错误?
下图说明了这个问题。
MWE 代码 1:
library(shiny)
library(shinyMatrix)
library(dplyr)
library(ggplot2)
sumProd <- function(a, b) { # a = periods, b = matrix inputs
c <- rep(NA, a)
c[] <- sum(b[,1]) %*% sum(b[,2])
return(c)
}
ui <- fluidPage(
sliderInput('periods', 'X-axis periods:', min=1, max=10, value=10),
matrixInput(
"myMatrixInput",
label = "Two columns to sumproduct are paired under each scenario heading:",
value = matrix(c(1, 5), 1, 2, dimnames = list(NULL, rep("Scenario 1", 2))),
cols = list(extend = TRUE, delta = 2, names = TRUE, delete = TRUE, multiheader = TRUE),
rows = list(extend = FALSE, delta = 1, names = FALSE, delete = FALSE),
class = "numeric"),
plotOutput("plot")
)
server <- function(input, output, session) {
observeEvent(input$myMatrixInput, {
tmpMatrix <- input$myMatrixInput
# Remove any empty matrix columns
empty_columns <- sapply(tmpMatrix, function(x) all(is.na(x) | x == ""))
tmpMatrix <- tmpMatrix[, !empty_columns, drop=FALSE]
# Assign column header names
colnames(tmpMatrix) <- paste("Scenario", rep(1:ncol(tmpMatrix), each = 2, length.out = ncol(tmpMatrix)))
isolate( # isolate update to prevent infinite loop
updateMatrixInput(session, inputId = "myMatrixInput", value = tmpMatrix)
)
})
plotData <- reactive({
tryCatch(
lapply(seq_len(ncol(input$myMatrixInput)/2),
function(i){
tibble(
Scenario = colnames(input$myMatrixInput)[i*2-1],
X = seq_len(input$periods),
Y = sumProd(input$periods,input$myMatrixInput[1,(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)
))
})
}
shinyApp(ui, server)
MWE 代码 2:
sumProd <- function(a, b) { # a = periods, b = matrix inputs
c <- rep(NA, a)
c[] <- sum(b[,1]) %*% sum(b[,2])
return(c)
}
ui <- fluidPage(
sliderInput('periods', 'X-axis periods:', min=1, max=10, value=10),
matrixInput(
"myMatrixInput",
label = "Two columns to sumproduct are paired under each scenario heading:",
value = matrix(c(1, 5), 1, 2, dimnames = list(NULL, rep("Scenario 1", 2))),
cols = list(extend = TRUE, delta = 2, names = TRUE, delete = TRUE, multiheader = TRUE),
rows = list(extend = TRUE, delta = 1, names = FALSE, delete = FALSE),
class = "numeric"),
plotOutput("plot")
)
server <- function(input, output, session) {
sanitizedMat <- reactiveVal() # < for vertical matrix expansion
observeEvent(input$myMatrixInput, {
if(any(colnames(input$myMatrixInput) == "")){
tmpMatrix <- input$myMatrixInput
# Remove any empty matrix columns
empty_columns <- sapply(tmpMatrix, function(x) all(is.na(x) | x == ""))
tmpMatrix <- tmpMatrix[, !empty_columns, drop=FALSE]
# Assign column header names
colnames(tmpMatrix) <- paste("Scenario", rep(1:ncol(tmpMatrix), each = 2, length.out = ncol(tmpMatrix)))
isolate( # isolate update to prevent infinite loop
updateMatrixInput(session, inputId = "myMatrixInput", value = tmpMatrix)
)
}
sanitizedMat(na.omit(input$myMatrixInput))
})
plotData <- reactive({
tryCatch(
lapply(seq_len(ncol(sanitizedMat())/2),
function(i){
tibble(
Scenario = colnames(sanitizedMat())[i*2-1],
X = seq_len(input$periods),
Y = sumProd(input$periods,sanitizedMat()[,(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)
))
})
}
shinyApp(ui, server)
解决方案是简单地消除单个 observeEvent()
下的自动矩阵空列删除并修改 UDF sumProd()
以忽略 NA(添加 na.rm = T
到 sum()
in sumProd()
).当 sub-columns(每种情况下 2 列的分组 header)长度不等时,NA 将出现在矩阵中,因此忽略 NA 可以解决问题。还删除了 MWE2 中的 UDF sanitizedMat()
和自动空列删除功能以简化。
修改后的代码:
library(shiny)
library(shinyMatrix)
library(dplyr)
library(ggplot2)
sumProd <- function(a, b) { # a = periods, b = matrix inputs
c <- rep(NA, a)
c[] <- sum(b[,1], na.rm = T) %*% sum(b[,2],na.rm = T) # Added na.rm = T
return(c)
}
ui <- fluidPage(
sliderInput('periods', 'X-axis periods:', min=1, max=10, value=10),
matrixInput(
"myMatrixInput",
label = "Two columns to sumproduct are paired under each scenario heading:",
value = matrix(c(1, 5), 1, 2, dimnames = list(NULL, rep("Scenario 1", 2))),
cols = list(extend = TRUE, delta = 2, names = TRUE, delete = TRUE, multiheader = TRUE),
rows = list(extend = TRUE, delta = 1, names = FALSE, delete = FALSE),
class = "numeric"),
plotOutput("plot")
)
server <- function(input, output, session) {
observeEvent(input$myMatrixInput, {
if(any(colnames(input$myMatrixInput) == "")){
tmpMatrix <- input$myMatrixInput
colnames(tmpMatrix) <- paste("Scenario",rep(1:ncol(tmpMatrix),each=2,length.out=ncol(tmpMatrix)))
isolate(updateMatrixInput(session, inputId = "myMatrixInput", value = tmpMatrix))
}
input$myMatrixInput
})
plotData <- reactive({
tryCatch(
lapply(seq_len(ncol(input$myMatrixInput)/2), # column counter to set matrix index as it expands
function(i){
tibble(
Scenario = colnames(input$myMatrixInput)[i*2-1],
X = seq_len(input$periods),
Y = sumProd(input$periods,input$myMatrixInput[,(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)
))
})
}
shinyApp(ui, server)
下面的 MWE 代码 1 工作正常,在计算 2 列数字的和积时,sumproduct 输入矩阵水平扩展以适应额外的 sumproduct 场景。
下面的 MWE 代码 2 是对 MWE 代码 1 的修改,使输入矩阵也可以垂直扩展,因此用户可以在 sumproduct 计算中添加要求和的元素行。当我 运行 MWE 代码 2 时,代码崩溃给我“Error in [: (subscript) logical subscript too long”。
为什么会出现此错误?
下图说明了这个问题。
MWE 代码 1:
library(shiny)
library(shinyMatrix)
library(dplyr)
library(ggplot2)
sumProd <- function(a, b) { # a = periods, b = matrix inputs
c <- rep(NA, a)
c[] <- sum(b[,1]) %*% sum(b[,2])
return(c)
}
ui <- fluidPage(
sliderInput('periods', 'X-axis periods:', min=1, max=10, value=10),
matrixInput(
"myMatrixInput",
label = "Two columns to sumproduct are paired under each scenario heading:",
value = matrix(c(1, 5), 1, 2, dimnames = list(NULL, rep("Scenario 1", 2))),
cols = list(extend = TRUE, delta = 2, names = TRUE, delete = TRUE, multiheader = TRUE),
rows = list(extend = FALSE, delta = 1, names = FALSE, delete = FALSE),
class = "numeric"),
plotOutput("plot")
)
server <- function(input, output, session) {
observeEvent(input$myMatrixInput, {
tmpMatrix <- input$myMatrixInput
# Remove any empty matrix columns
empty_columns <- sapply(tmpMatrix, function(x) all(is.na(x) | x == ""))
tmpMatrix <- tmpMatrix[, !empty_columns, drop=FALSE]
# Assign column header names
colnames(tmpMatrix) <- paste("Scenario", rep(1:ncol(tmpMatrix), each = 2, length.out = ncol(tmpMatrix)))
isolate( # isolate update to prevent infinite loop
updateMatrixInput(session, inputId = "myMatrixInput", value = tmpMatrix)
)
})
plotData <- reactive({
tryCatch(
lapply(seq_len(ncol(input$myMatrixInput)/2),
function(i){
tibble(
Scenario = colnames(input$myMatrixInput)[i*2-1],
X = seq_len(input$periods),
Y = sumProd(input$periods,input$myMatrixInput[1,(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)
))
})
}
shinyApp(ui, server)
MWE 代码 2:
sumProd <- function(a, b) { # a = periods, b = matrix inputs
c <- rep(NA, a)
c[] <- sum(b[,1]) %*% sum(b[,2])
return(c)
}
ui <- fluidPage(
sliderInput('periods', 'X-axis periods:', min=1, max=10, value=10),
matrixInput(
"myMatrixInput",
label = "Two columns to sumproduct are paired under each scenario heading:",
value = matrix(c(1, 5), 1, 2, dimnames = list(NULL, rep("Scenario 1", 2))),
cols = list(extend = TRUE, delta = 2, names = TRUE, delete = TRUE, multiheader = TRUE),
rows = list(extend = TRUE, delta = 1, names = FALSE, delete = FALSE),
class = "numeric"),
plotOutput("plot")
)
server <- function(input, output, session) {
sanitizedMat <- reactiveVal() # < for vertical matrix expansion
observeEvent(input$myMatrixInput, {
if(any(colnames(input$myMatrixInput) == "")){
tmpMatrix <- input$myMatrixInput
# Remove any empty matrix columns
empty_columns <- sapply(tmpMatrix, function(x) all(is.na(x) | x == ""))
tmpMatrix <- tmpMatrix[, !empty_columns, drop=FALSE]
# Assign column header names
colnames(tmpMatrix) <- paste("Scenario", rep(1:ncol(tmpMatrix), each = 2, length.out = ncol(tmpMatrix)))
isolate( # isolate update to prevent infinite loop
updateMatrixInput(session, inputId = "myMatrixInput", value = tmpMatrix)
)
}
sanitizedMat(na.omit(input$myMatrixInput))
})
plotData <- reactive({
tryCatch(
lapply(seq_len(ncol(sanitizedMat())/2),
function(i){
tibble(
Scenario = colnames(sanitizedMat())[i*2-1],
X = seq_len(input$periods),
Y = sumProd(input$periods,sanitizedMat()[,(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)
))
})
}
shinyApp(ui, server)
解决方案是简单地消除单个 observeEvent()
下的自动矩阵空列删除并修改 UDF sumProd()
以忽略 NA(添加 na.rm = T
到 sum()
in sumProd()
).当 sub-columns(每种情况下 2 列的分组 header)长度不等时,NA 将出现在矩阵中,因此忽略 NA 可以解决问题。还删除了 MWE2 中的 UDF sanitizedMat()
和自动空列删除功能以简化。
修改后的代码:
library(shiny)
library(shinyMatrix)
library(dplyr)
library(ggplot2)
sumProd <- function(a, b) { # a = periods, b = matrix inputs
c <- rep(NA, a)
c[] <- sum(b[,1], na.rm = T) %*% sum(b[,2],na.rm = T) # Added na.rm = T
return(c)
}
ui <- fluidPage(
sliderInput('periods', 'X-axis periods:', min=1, max=10, value=10),
matrixInput(
"myMatrixInput",
label = "Two columns to sumproduct are paired under each scenario heading:",
value = matrix(c(1, 5), 1, 2, dimnames = list(NULL, rep("Scenario 1", 2))),
cols = list(extend = TRUE, delta = 2, names = TRUE, delete = TRUE, multiheader = TRUE),
rows = list(extend = TRUE, delta = 1, names = FALSE, delete = FALSE),
class = "numeric"),
plotOutput("plot")
)
server <- function(input, output, session) {
observeEvent(input$myMatrixInput, {
if(any(colnames(input$myMatrixInput) == "")){
tmpMatrix <- input$myMatrixInput
colnames(tmpMatrix) <- paste("Scenario",rep(1:ncol(tmpMatrix),each=2,length.out=ncol(tmpMatrix)))
isolate(updateMatrixInput(session, inputId = "myMatrixInput", value = tmpMatrix))
}
input$myMatrixInput
})
plotData <- reactive({
tryCatch(
lapply(seq_len(ncol(input$myMatrixInput)/2), # column counter to set matrix index as it expands
function(i){
tibble(
Scenario = colnames(input$myMatrixInput)[i*2-1],
X = seq_len(input$periods),
Y = sumProd(input$periods,input$myMatrixInput[,(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)
))
})
}
shinyApp(ui, server)