shiny - 在 Shiny 中保持运行值
问题描述
我是一名环境科学家,试图为牡蛎创建一个收获模拟。我希望模拟显示两张地图,一张用于显示当前的牡蛎种群,另一张用于显示禁捕区(保护区)。单击地图上的一个图(每个图都有一个不可见的标记)应该根据显示的地图执行不同的操作。单击牡蛎种群地图应导致种群随着单击图中发生的牡蛎收获而更新。点击保护区地图应该会导致点击的地块改变为打开或关闭的指定。
据我所知,问题是每次单击输入时所有这些值都会重置。例如,之前显示的地图无关紧要,“showSanctuary”变量,应该显示 F 是人口地图上升,T 如果保护区地图上升,总是设置为 False,它的起始值,每当单击新输入时。牡蛎种群向量和保护区向量似乎做同样的事情。如何防止这些变量重置为初始值?
另外,我对这个论坛很陌生,我不确定礼仪。我将在下面发布我的所有代码,而不是存储我的函数的两个脚本(我确定它们不是问题),但这是一个相当冗长的程序。这个问题与第 70 行和第 152 行之间的代码有关。我将首先发布这些行,下面是完整的脚本。如果这不是典型的礼仪,再次抱歉。
发生问题的行(这是在 Server 函数内部):
#Make Reactive Values
offLim <- reactiveValues()
offLim = 0
showSanctuary <- reactiveValues()
showSanctuary = F
myOutputs <- reactiveValues()
myOutputs$outHarvTime = 0
myOutputs$outSacksTaken = 0
myOutputs$outAvgSize = 0
#React to click event
observeEvent(input$map_marker_click, {
click<-input$map_marker_click
if(is.null(click))
return()
xClk=trunc(click$lng*1000)/1000
yClk=trunc(click$lat*1000)/1000
xCor = which(coord$x == xClk)
yCor = which(coord$y == yClk)
myPlot = intersect(xCor, yCor)
if(showSanctuary == T){
if(offLim[myPlot]==1){
offLim[myPlot]=0
}else if(offLim[myPlot]==0){
offLim[myPlot]=1
}
myMap <- makeSanctuaryMap(offLim)
myOutputs$finalMap = myMap
}
else{
myHarvLim = input$amount
myMaxTime = input$effort
myMinSize = input$size
returnShells = input$shell
param = c(myHarvLim, myMaxTime, myMinSize, myPlot, returnShells)
newOysters = oysters
newDens = myDens
newShell = myShell
outVar<-localUpdate(param, newOysters, myMaxDens, newDens, newShell, nplts)
oysters = outVar$oysters
myDens = outVar$myDens
myShell = outVar$myShell
myOutputs$outAvgSize = outVar$avgSize
myOutputs$outHarvTime = outVar$harvTime
myOutputs$outSacksTaken = outVar$sacksTaken
myOutputs$finalMap = outVar$myMap
}
})
observeEvent(input$update,{
#Make sanctuary variables. Needs to be reactive to be global
showSanctuary = F #Whether the Map Currently Displays Sanctuary Areas
offLim = vector(length=nplts) #1 if plot is a Sanctuary or 0 if not
offLim[] = 0
offLim[!cond]<-NA
myOutputs$outAvgSize = NA
myOutputs$outHarvTime = NA
myOutputs$outSacksTaken = NA
myOutputs$finalMap = myMap
})
observeEvent(input$sanctuaryMap,{
print(showSanctuary)
showSanctuary = T
myMap <- makeSanctuaryMap(offLim)
myOutputs$finalMap = myMap
})
observeEvent(input$harvestMap,{
print(showSanctuary)
showSanctuary = F
myMap <- updateMap(heatVec)
myOutputs$finalMap = myMap
})
完整脚本:
library(shiny)
library('leaflet')
library(raster)
library('sf')
library(rgdal)
source('updateFunctions.R')
effortLbl = "What is the maximum number of hours that you are willing to spend harvesting each day?"
amountLbl = "What is the maximum number of sacks of oysters you would harvest in one day?"
sizeLbl = "Select a minimum size for legal harvest (inches)"
shellLbl="Check to require culling on site"
ui<-fluidPage(
numericInput(inputId="effort", label=effortLbl, value=8, min=1, max=16, step=1),
numericInput(inputId="amount", label=amountLbl, value=4, min=1, max=40, step=1),
numericInput(inputId="size", label=sizeLbl, value=3, min=1, max=6, step=1),
checkboxInput(inputId="shell", label=shellLbl, value = FALSE),
actionButton(inputId="update", label="Begin"),
actionButton(inputId="sanctuaryMap", label="Set Sanctuaries"),
actionButton(inputId="harvestMap", label="Choose Harvest Area"),
leafletOutput("map"),
textOutput("time"),
textOutput("sacks"),
textOutput("size")
)
server<-function(input, output, session){
#Generate list of clickable coordinates
cedKey <- readOGR(dsn=path.expand("shapefile"), layer="LC_10_Area") #Imports Cedar Key shape file
ckCrd <- spTransform(cedKey, CRSobj = CRS("+init=epsg:4326")) #Converts shape file coordinate to longitude/latitude
matCrd=expand.grid(x=seq(from=-83.1164,to=-83.06251,length.out=moveRow), #Generates a series of coordinates within range
y=seq(from=29.2169,to=29.26528,length.out=moveRow))
df = data.frame(x = matCrd$x, y = matCrd$y)
s = SpatialPixelsDataFrame(df[,c('x', 'y')], data = df, proj4string = crs(ckCrd))
clp <- over(s[,c("x", "y")], ckCrd)
cond <- !is.na(clp$Id)
spNew<-s[cond,]
spDf = as.data.frame(spNew)
coord = data.frame(x=(trunc(df$x*1000)/1000), y=(trunc(df$y*1000)/1000))
#Initialize oyster population variables
nplts = 1600 #Total number of plots
nsize = 7 #Number of size classes (including larva)
oysters = matrix(0, nplts,nsize)
myDens = vector(length=nplts) #Total number of oysters weighted by size
myShell = vector(length=nplts) #The amount of dead shell (or other non-living hard substrate)
myMaxDens = 1000 #The maximum capacity of every plot
moveRow = sqrt(nplts) #The number of plots in a row
#Initialize oyster population with randomization
for(i in 1:nplts){
initMin = c(20,20,5,5,0,0) #Minimum number of oysters of each size at game start
initMax = c(60,40,30,20,10,5) #Maximum number of oysters of each size at game start
oysters[i,1:6]=runif(6, initMin, initMax)
oysters[i,7]=sum(oysters[i,1:6]*4)
}
oysters[!cond,]<-NA
for(i in 1:nplts){
myDens[i]=sum(oysters[i,1:6]*c(1:6))
myShell[i]=0.2*myDens[i]
}
#Set values of outputs before initial update
heatVec = vector(length=nplts)
for(i in 1:nplts){
heatVec[i] = (100*myDens[i])/myMaxDens
}
myMap = updateMap(heatVec)
#Make Reactive Values
offLim <- reactiveValues()
offLim = 0
showSanctuary <- reactiveValues()
showSanctuary = F
myOutputs <- reactiveValues()
myOutputs$outHarvTime = 0
myOutputs$outSacksTaken = 0
myOutputs$outAvgSize = 0
#React to click event
observeEvent(input$map_marker_click, {
click<-input$map_marker_click
if(is.null(click))
return()
xClk=trunc(click$lng*1000)/1000
yClk=trunc(click$lat*1000)/1000
xCor = which(coord$x == xClk)
yCor = which(coord$y == yClk)
myPlot = intersect(xCor, yCor)
if(showSanctuary == T){
if(offLim[myPlot]==1){
offLim[myPlot]=0
}else if(offLim[myPlot]==0){
offLim[myPlot]=1
}
myMap <- makeSanctuaryMap(offLim)
myOutputs$finalMap = myMap
}
else{
myHarvLim = input$amount
myMaxTime = input$effort
myMinSize = input$size
returnShells = input$shell
param = c(myHarvLim, myMaxTime, myMinSize, myPlot, returnShells)
newOysters = oysters
newDens = myDens
newShell = myShell
outVar<-localUpdate(param, newOysters, myMaxDens, newDens, newShell, nplts)
oysters = outVar$oysters
myDens = outVar$myDens
myShell = outVar$myShell
myOutputs$outAvgSize = outVar$avgSize
myOutputs$outHarvTime = outVar$harvTime
myOutputs$outSacksTaken = outVar$sacksTaken
myOutputs$finalMap = outVar$myMap
}
})
observeEvent(input$update,{
#Make sanctuary variables. Needs to be reactive to be global
showSanctuary = F #Whether the Map Currently Displays Sanctuary Areas
offLim = vector(length=nplts) #1 if plot is a Sanctuary or 0 if not
offLim[] = 0
offLim[!cond]<-NA
myOutputs$outAvgSize = NA
myOutputs$outHarvTime = NA
myOutputs$outSacksTaken = NA
myOutputs$finalMap = myMap
})
observeEvent(input$sanctuaryMap,{
print(showSanctuary)
showSanctuary = T
myMap <- makeSanctuaryMap(offLim)
myOutputs$finalMap = myMap
})
observeEvent(input$harvestMap,{
print(showSanctuary)
showSanctuary = F
myMap <- updateMap(heatVec)
myOutputs$finalMap = myMap
})
localUpdate <- function(param, locOyster, myMaxDens, locDens, locShell, nplts){
myUpdate<-updateFunction(locOyster, myMaxDens, locDens, locShell, param, nplts) #All updates done in separate script
#Set oyster pop, dens, and dead shell according to updates
oysters = myUpdate$oysters
for(i in 1:nplts){
myDens[i] = sum(oysters[i,1:6]*c(1:6))
}
myShell = myUpdate$shell
#Calculate heatmap values based on density (biomass)
for(i in 1:nplts){
heatVec[i] = (100*myDens[i])/myMaxDens
}
myMap <- updateMap(heatVec) #Create Map
return(list(avgSize = myUpdate$avgSize, harvTime = myUpdate$harvTime, sacksTaken = myUpdate$sacksTaken,
myMap = myMap, myShell = myShell, myDens = myDens, oysters = oysters))
}
#Assemble and Display Outputs
output$map <- renderLeaflet({
input$map_marker_click #Makes output dependent on map or button click (via isolate)
input$sanctuaryMap
input$harvestMap
input$update
isolate(myOutputs$finalMap)})
output$time <- renderText({
input$map_marker_click
input$update
timeString <- isolate(c("Time Spent Harvesting Each Day: ",
toString(trunc(myOutputs$outHarvTime*100)/100), " hours"))
timeString})
output$sacks <- renderText({
input$map_marker_click
input$update
sacksString<-isolate(c("Average Number of Sacks Harvested per Day: ",
toString(trunc(myOutputs$outSacksTaken*100)/100), " sacks"))
sacksString})
output$size <- renderText({
input$map_marker_click
input$update
sizeString<-isolate(c("Average Size of Harvested Oysters this Year: ",
toString(trunc(myOutputs$outAvgSize*100)/100), " inches"))
sizeString})
}
shinyApp(ui = ui, server = server)
解决方案
对于初学者,您没有reactiveValues
正确使用。它会是这样的:
my_reactives <- reactiveValues()
my_reactives$offLim <- 0
my_reactives$showSanctuary <- F
推荐阅读
- python - 将两列相互添加
- c# - 日期时间包括时间的“t”在插入时在 c# 中给出错误
- html - 如何在英文网站上显示外语单词?
- c# - PostSharp中的父属性设置拦截
- tfs - 我有现有的团队项目(TFS 2018)我想知道使用了哪个流程模板
- php - 使用 array_column 将两列连接为一列
- python - 如何使用 QProcess 运行 jar 文件
- java - 查看冗余依赖项
- asp.net - 错误:仅允许直接在包含内容控件的内容页面中使用内容控件。在页面布局 SharePoint 2016
- spring - 为什么项目 pom.xml 显示此 Non-Resolvable 错误