我正在使用Shiny,我对Leaflet有一个问题。
我想做什么: 我的项目的最终目标是选择特定的法国县。 当选择这些县时,我会在移动中(通过合并)创建形状文件(这是在Leaflet上绘制地图所必需的)和包含所有类型的公共数据的数据库(例如人口数等等)。 ..)仅对应于那些特定的县。
我的问题:我知道"合并"在Shiny App里面做得很好。但是,我的Outputmap并不想工作。
详情:实际上,我推出了合并和策划"在另一个.R脚本上,它运行得非常好(我只定义了#34;手动"在启动脚本之前我想绘制的县)。在我的ShinyApp上,这个选择由input$choix_depa
变量进行。
现在有点代码。我有三个同时作出反应的脚本:global.R ui.R和server.R(这就是Shiny的工作方式,如你所知)。 对于global.R(我只在这里显示" interessant"部分)我加载包含所有县的数据的数据库文件(不是形状文件!仅数据)
setwd('path')
data_BP = read_delim(
"database-allFrance.csv",
",",
na = "empty",
quote = "\"",
locale = locale(encoding = 'windows-1252')
)
在ui.R(用户界面)上,我有我的"选择"县:
shinydashboard::tabItem(tabName= "Departements", class = 'active',
shiny::fluidPage(
shiny::absolutePanel(
draggable = FALSE,
fixed = TRUE,
top = 60, left = "auto", right = 20, bottom = "auto",
width = 330, height = "auto",
wellPanel(
shiny::h4("Départements"),
selectizeInput(inputId = "choix_depa", label = "",multiple=TRUE,
choices = seq(1,95))
)
), textOutput("answ")
),
selectizeInput
是允许用户在seq(1,95)
中选择一个或多个县的按钮。
在服务器上.R(最重要的)我有:
ObserveEvent(input$choix_depa, {
output$answ<- renderText({
paste("You choose", input$choix_depa)
})
choice=input$choix_depa
print(choice)
for (i in input$choix_depa){
setwd(sprintf("path/county%s",i))
assign(paste("contouriris",i,sep=""), readOGR(
dsn = "contours_IRIS_BP.shp",
layer = "contours_IRIS_BP",
verbose = FALSE,
encoding = 'UTF-8'
))
print("modification en cours...")
assign(paste("data_BP",i,sep=""),subset(data_BP,as.numeric(as.character(data_BP$IRIS))>=as.numeric(i)*10000000&as.numeric(as.character(data_BP$IRIS))<(as.numeric(i)+1)*10000000))
}
if (length(input$choix_depa)>=1){
contours_IRIS <- get(paste("contouriris",input$choix_depa[1],sep=""))
data_BPC <- get(paste("data_BP",input$choix_depa[1],sep=""))
}
if (length(input$choix_depa)>1){
for (i in input$choix_depa[-1]){
contours_IRIS <- rbind(contours_IRIS,get(paste("contouriris",i,sep="")))
data_BPC <- rbind(data_BPC,get(paste("data_BP",i,sep="")))
}
}
map_WGS84 = spTransform(
merge(contours_IRIS, data_BPC, by.x = 'CODE_IRIS', by.y = 'IRIS'),
CRS("+init=epsg:4326")
)
# Correction of names :
names(map_WGS84)[names(map_WGS84) == "TYP_IRIS.x"] <- "TYP_IRIS"
})
您不必了解所有这些代码。
您可以在input$choix_depa
变量中选择县。
如果用户在应用程序中选择了县4和87(例如),那么这种变量就像[&#34; 4&#39;,&#34; 87&#34;]。
我的计算机上有95个文件夹(每个县一个)。我使用setwd转到正确的路径,然后在contouririsK
中加载&#34;形状文件&#34; ,其中K为县的编号。在上一个示例中,我们将contouriris4
和countouriris87
。
这些形状文件合并在contours_IRIS
中。
我对数据文件做了同样的事情,我获取了与这些县相关联的数据,我合并了data_BPC
中的所有文件。 (如果我采用前面的示例,我们会在data_BPC4
合并data_BPC87
和data_BPC
。
在此之后,我使用两个变量(contours_IRIS
和data_BPC
)来创建map_WGS84
变量(我将需要LeafletOutput的这个变量)。
好的,在我想要在Leaflet地图上绘制这些县的选择后,我必须选择我感兴趣的变量。 这是另一个菜单,我不在这里写所有代码(不是必需的)
observeEvent(input$choix_var_pop, {XXXXXXXXX})
用户想要在地图上绘制的变量的选择位于input$choix_var_pop
。
在此之后,我创建了我在LeafletMap上需要的特定变量:
label_reac_pop = reactive({as.character(input$choix_var_pop)})
var_reac_pop = reactive({dico$Variable[dico$Label == label_reac_pop()]})
col_reac_pop = reactive({as.character(dico$Couleur[dico$Label == label_reac_pop()])})
type_reac_pop = reactive({as.character(dico$Type[dico$Label == label_reac_pop()])})
unite_reac_pop = reactive({ifelse(as.character(type_reac_pop()) == "Pct", " %", "")})
最后,我绘制了LeafletMap :(为了清晰起见,我已大大减少了以下代码)
output$Carte_Pop <- renderLeaflet({
label = label_reac_pop()
var = var_reac_pop()
col = col_reac_pop()
type = type_reac_pop()
unite = unite_reac_pop()
values_var = map_WGS84@data[,var]
leaflet(map_WGS84) %>%
addProviderTiles("CartoDB.PositronNoLabels") %>%
addProviderTiles("CartoDB.PositronOnlyLabels") %>%
setView(lng = 2.468738900000062, lat = 49.19316, zoom = 7) %>%
clearShapes() %>%
clearPopups() %>%
})
当然,我在ui.R文件中调用此输出$ Carte_Pop,以便绘制它。
好的,所有这一切的结果是什么?
正如我之前提到的,当脚本单独使用时,此脚本工作,并且当没有input$choix_depa
时(我手动输入要在数组中合并的县,并且它们合并得很好) ,并绘制好地图)。
但当我使用我的3个脚本(global.R,ui.R和server.R)在ShinyApp上时,&#34; new&#34; &#34;地图的价值&#34;没有&#34;保存&#34; 。
例如:如果我选择(在我的单独脚本上)合并并绘制4号和87号县,它可以正常工作(合并部分和绘图部分工作正常)!
但是当我启动ShinyApp时,当我选择我想要的县时(例如13和91),即使contours_IRIS
和data_BPC
很好与对应于13和91的数据合并,因此我认为在map_WGS84
内创建的observeEvent(input$choix_depa....)
对应为13和91,当我要求绘图时一个特定的变量(在observeEvent(input$choix_var_pop)
之后绘制的地图不是之前创建的地图,而是旧的MAP&#34; 4和87 (地图是在启动ShinyApp之前在&#34; alone-script&#34; ...上创建。)但我确信100%在observeEvent(input$choix_depa .... )
内部创建的MAP是好的。但是,此MAP的&#34;值&#34;不是&#34;由ShinyApp保存&#34; (他们使用MAP的旧值...)。
所以我的问题是:我应该怎么做才能绘制好的新地图(在APP内部创建)而不是OLD BAD ONE(在应用程序之前和之外创建......) ?
这个问题有点复杂&#34;,如果您有任何疑问,请随时提出!
谢谢! :)
答案 0 :(得分:3)
摘要:如果要使某些输出依赖于其他表达式,则应使用eventReactive,或将该对象存储在reactiveValues中并从observeEvent更新该对象。
好的,我已经阅读了你的问题,这是我的想法:
ObserveEvent(input$choix_depa, {
output$answ<- renderText({
paste("You choose", input$choix_depa)
})
这是不好的做法。观察者只应用于副作用,而不是用于创建输出。这应该成为:
output$answ<- renderText({
paste("You choose", input$choix_depa)
})
ObserveEvent(input$choix_depa, {
....
每当输入$ choix_depa发生变化时, renderText也会触发,因为它对此有反应。所以不需要把它放在观察者身上。
map_WGS84 = spTransform(
merge(contours_IRIS, data_BPC, by.x = 'CODE_IRIS', by.y = 'IRIS'),
CRS("+init=epsg:4326")
)
map_WGS84是什么类型的对象? 只有当它是reactiveValue时才会起作用。否则你不会覆盖全局变量,而只是覆盖函数observeEvent中的本地变量。一旦observeEvent完成,全局map_WGS84就没有改变。我想这就是问题所在。
最好的选择可能是将其设为eventReactive ,而不是observeEvent,因为您希望它生成可在其他地方使用的输出。另一个选项是将map_WGS84存储在reactiveValues表达式中,并从observeEvent中覆盖它。
答案 1 :(得分:0)
感谢Florian的帮助,我将准确描述我的成功:
output$answ<- renderText({
paste("Choix départements:", input$choix_depa)
})
observeEvent(input$choix_depa, {
choice=input$choix_depa
})
map_reactive <- eventReactive(input$choix_depa,{
... merging and creating contours_IRIS (shape file)
and data_BPC given input$choix_depa ...
map_WGS84 = spTransform(
merge(contours_IRIS, data_BPC, by.x = 'CODE_IRIS', by.y = 'IRIS'),
CRS("+init=epsg:4326")
)
list(map = map_WGS84)
})
observeEvent(input$choix_var_pop, {XXXXXXXXX})
... defining variables...
output$Carte_Pop <- renderLeaflet({
compulsive = map_reactive()$map
label = label_reac_pop()
var = var_reac_pop()
col = col_reac_pop()
type = type_reac_pop()
unite = unite_reac_pop()
values_var = compulsive@data[,var]
leaflet(compulsive) %>%
})
这里“重要”的是在eventReactive末尾添加“list”,以便稍后调用“map_reactive $ map”。 问题解决了 !