#r #shiny
#r #блестящий
Вопрос:
В функции сервера в shiny я должен повторить следующие шаги для разных входных данных (имен столбцов), например 'LGD-Class'
:
#Begin the server.R
function(input, output) {
.
.
.
if(dataRating() == "LGD-Class"){
data1<- data[,list('MW (%)'=sum(as.numeric(Marktwert))/mw.ganz),by='LGD-Class']
data2<- data[,list('EL (%)'=sum(as.numeric(`EL absolut`))/EL.ganz),by='LGD-Class']
data3<- data[,list('VaR (%)'=sum(`VaR Beitrag absolut`)/Var.ganz),by='LGD-Class']
# absolute values
data5<-data[,list(MW.Abs=sum(as.numeric(Marktwert))),by='LGD-Class']
data6<-data[,list(EL.Abs=sum(as.numeric(`EL absolut`))),by='LGD-Class']
data7<- data[,list(VaR.Abs=sum(`VaR Beitrag absolut`)),by='LGD-Class']
# relative values
data4<-merge(data1,data2,by='LGD-Class')
data.rel<-merge(data4,data3,by='LGD-Class')
# absolute values
data8<-merge(data5,data6,by='LGD-Class')
data.abs<-merge(data8,data7,by='LGD-Class')
data<-merge(data.rel,data.abs,by='LGD-Class')
}...
} #end of server.R
поэтому я написал функцию внутри серверной функции (сразу после начала server.R
), в которой переменная 'LGD-Class'
заменяется общей переменной x :
my.aggregate<-function(x,data){x.c<-as.character(x)
if(dataRating() ==x.c){
va=get(x)
data1<- data[,list('MW (%)'=sum(as.numeric(Marktwert))/mw.ganz),by=va]
data2<- data[,list('EL (%)'=sum(as.numeric(`EL absolut`))/EL.ganz),by=va]
data3<- data[,list('VaR (%)'=sum(`VaR Beitrag absolut`)/Var.ganz),by=va]
# absolute values
data5<-data[,list(MW.Abs=sum(as.numeric(Marktwert))),by=va]
data6<-data[,list(EL.Abs=sum(as.numeric(`EL absolut`))),by=va]
data7<- data[,list(VaR.Abs=sum(`VaR Beitrag absolut`)),by=va]
# relative values
data4<-merge(data1,data2,by=va)
data.rel<-merge(data4,data3,by=va)
# absolute values
data8<-merge(data5,data6,by=va)
data.abs<-merge(data8,data7,by=va)
data<-merge(data.rel,data.abs,by=va)
return(data)
}}
data
в качестве переменной функции ссылается на фрейм данных, который я прочитал перед вызовом my.aggregate
data<-fread(paste0('C:/Users/data/','31032019KRB.CSV'),header=TRUE, sep=";",stringsAsFactors = FALSE)
mw.ganz<-sum(as.numeric(data$MV))
Var.ganz<-sum(as.numeric(data$`VaR absolut`))
EL.ganz<-sum(as.numeric(data$`EL absolut`))
my.aggregate("LGD-Class",data)
Я получаю следующую ошибку:
Warning in is.na(data) :
is.na() applied to non-(list or vector) of type 'closure'
Warning: Error in get: object 'LGD-Class' not found
есть идеи, как я могу решить проблему? Проблема в том, что я использую character
(» «) и variable name
(‘ ‘) одновременно?
Я бы не хотел вводить / использовать глобальную переменную!
Комментарии:
1. На всякий случай, объявлена ли эта функция над
shinyServer
оболочкой? аLGD-Class
внутриshinyServer
?2. все происходит внутри серверной функции, как объявление функции, так и вызов функции my.aggregate(«LGD-Class»,данные)
3. Похоже, что «LGD-Class» недоступен в этой области действия функции. Попробуйте, может
get("LGD-Class", envir = .GlobalEnv)
быть. Заставьтеget
заглянуть в глобальную среду. Если это не сработает, попробуйте использовать другиеenvir
аргументы.4. Было бы полезно, если бы можно было избежать глобальных переменных и функций!
5. Я предлагаю вам найти, в какой области
get
просматривается и в какой областиLGD-Class
объявлено. Здесь есть отличная ссылка на среду: adv-r.had.co.nz/Environments.html .
Ответ №1:
Поскольку вы не предоставили воспроизводимый пример, я могу только догадываться, что вы пытаетесь сделать. Мне кажется, что вы используете пользовательскую функцию для объединения данных в реактивное выражение на основе пользовательского ввода (это предположение, оно не написано в предоставленном вами фрагменте кода).
Предположим, вы действительно хотите запустить пользовательскую функцию на основе data.table для агрегирования данных в вашей функции shiny server. Тогда кажется va = get(x)
, что это вызывает ошибку, поскольку вы вызываете свою пользовательскую функцию со строкой „LGD-Class“
, а не с именем объекта.
Вы можете легко исправить это, вызвав x непосредственно в вызове data.table, поскольку аргумент by может обрабатывать строки. Ниже я привожу минимальный пример (A), который показывает, как такая функция в операторе shiny server будет выглядеть с использованием пользовательского ввода для вызова пользовательской функции. Сама функция очень проста, но она должна быть легко адаптирована к вашей проблеме.
Хотя это может решить вашу проблему, мне интересно, действительно ли вам нужна пользовательская функция в первую очередь, поскольку вы можете использовать входную переменную непосредственно в реактивном выражении для генерации тех же агрегированных данных, которые будет генерировать пользовательская функция. Я также привожу пример (B) для такого рода агрегирования данных.
Пример A (блестящее приложение с пользовательской функцией data.table в разделе server)
library("shiny")
library("data.table")
# Generate data
testDT <- data.table(a1 = c(rep("group1",4),rep("group2",4),rep("group3",4)),
a2 = rep(c("red","blue","green"),4),
x1 = c(5,6,7,3,4,5,2,3,4,2,1,7),
x2 = c(1,2,3,2,3,2,1,4,6,7,3,4),
x3 = c(12,43,64,34,93,16,32,74,84,89,45,67)
)
shinyApp(
ui = fluidPage( # user interface
sidebarLayout( # layout with Sidebar
sidebarPanel( # input sidebarPanel
selectInput(inputId = "group", label = "Choose grouping variable",
choices = c("Variable a1" = "a1",
"Variable a2" = "a2"),
selected = "a1")
), # closes sidebarPanel
mainPanel( # Output in mainPabel
tableOutput("table")
) # closes mainPanel
) # closes sidebarLayout
), # closes fluidPage
server = function(input, output) {
create.DT <- function(DT, x) { # custom data.table function
data <- DT[,.(x1 = mean(x1)
),
by = c(x)]
return(data)
}
react_testDT <- reactive({
t <- create.DT(testDT, input$group) # function call with user input
})
output$table <- renderTable({
react_testDT()
})
}
) # closes shinyApp
Пример B (пользовательский ввод в реактивное выражение для агрегирования данных)
library("shiny")
library("data.table")
# Generate data
testDT <- data.table(a1 = c(rep("group1",4),rep("group2",4),rep("group3",4)),
a2 = rep(c("red","blue","green"),4),
x1 = c(5,6,7,3,4,5,2,3,4,2,1,7),
x2 = c(1,2,3,2,3,2,1,4,6,7,3,4),
x3 = c(12,43,64,34,93,16,32,74,84,89,45,67)
)
shinyApp(
ui = fluidPage( # user interface
sidebarLayout( # layout with Sidebar
sidebarPanel( # input sidebarPanel
selectInput(inputId = "group", label = "Choose grouping variable",
choices = c("Variable a1" = "a1",
"Variable a2" = "a2"),
selected = "a1")
), # closes sidebarPanel
mainPanel( # Output in mainPabel
tableOutput("table")
) # closes mainPanel
) # closes sidebarLayout
), # closes fluidPage
server = function(input, output) {
react_testDT <- reactive({
testDT[, .(x1_mean = mean(x1)), by = c(input$group)]
})
output$table <- renderTable({
react_testDT()
})
}
) # closes shinyApp
Комментарии:
1. не могли бы вы получить тот же результат, если вы создадите пользовательскую функцию в начале своего скрипта? то есть, имеет ли значение, где вы ее определяете?
2. Если вы вызываете приложение с помощью shinyApp(), как указано выше, в одном файле, то установка пользовательской функции в начале скрипта также работает. Смотрите Также здесь для получения дополнительной информации о области видимости.