I have made a shiny app which brings static maps back using ggmap. However when I want to overlay postcode boundaries I am encountering an error where ggplot cannot find the data set.
The dataset poa is a dataframe of postcode boundaries i.e. lats and lons with a polygon ID.
I have already tried adding environment = environment()
but that doesn't solve my problem.
I know that the data exists as I call print(str(poa))
which prints to the R console.
Can anyone suggest a work around for me so that ggplot can access the poa dataframe? I apologise that this is not a very reproducible example.
Update: ggplot is able to access the poa dataframe when I use this code:
print(ggmap(map)) + geom_polygon(data = poa, aes(x = LON, y = LAT, group = order), alpha = .5, colour = "black", fill = NA))
But I need to make a nested call to ggplot for the base layer of the map, when I do that ggplot is unable to find the data
Here is my server.R code
I am using isolate as I have an action button in my ui.R and I only want the plot to update when it has been clicked.
library(shiny)
library(ggmap)
library(RODBC)
# Define server logic required to summarize and view the selected dataset
shinyServer(function(input, output) {
output$searchString <- renderText({
if (input$searchButton == 0)
return()
isolate({input$searchString})
})
mapSourceInput <- reactive({
switch(input$mapSource
, "google" = "google"
, "stamen" = "stamen")
})
mapTypeInput <- reactive({
switch(input$mapType
, "terrain" = "terrain"
, "satellite" = "satellite"
, "roadmap" = "roadmap"
, "hybrid" = "hybrid"
, "toner" = "toner"
, "watercolor" = "watercolor")
})
overlayInput <- reactive({
switch(input$overlay
, "postcodes" = "postcodes"
, "states" = "states"
, "nothing" = "nothing")
})
output$map <- renderPlot({
if (input$searchButton == 0)
return()
isolate({
if (overlayInput() == "nothing"){
map <- get_map(location = input$searchString, zoom = input$zoom, source = mapSourceInput(), maptype = mapTypeInput())
mapPlot <- ggmap(map)
print(mapPlot)
#return()
} else {
if (overlayInput() == "postcodes"){
#postcode boundaries
map <- get_map(location = input$searchString, zoom = input$zoom, source = mapSourceInput(), maptype = mapTypeInput())
poa <- structure(list(POAOBS = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L)
, COORD_REF = 1:10
, COORD_POL = 1:10
, POLYGON = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L)
, LON = c(144.951431274414, 144.956451416016, 144.95539855957, 144.955993652344, 144.958465576172, 144.956634521484, 144.956817626953, 144.954727172852, 144.957550048828, 144.958831787109)
, LAT = c(-37.8131675720215, -37.8117561340332, -37.8094863891602, -37.8058776855469, -37.8061485290527, -37.8021659851074, -37.8010902404785, -37.7994079589844, -37.7997169494629, -37.799861907959)
, POA = c("3000", "3000", "3000", "3000", "3000", "3000", "3000", "3000", "3000", "3000"))
, .Names = c("POAOBS", "COORD_REF", "COORD_POL", "POLYGON", "LON", "LAT", "POA")
, row.names = c(NA, 10L)
, class = "data.frame")
print(str(poa))
print(ggmap(map, base_layer = ggplot(data = poa, aes(x = LON, y = LAT), environment = environment()), extent = "normal", maprange = FALSE, environment = .GlobalEnv) +
geom_polygon(data = poa, aes(x = LON, y = LAT, group = order), alpha = .5, colour = "black", fill = NA) +
coord_map(projection = "mercator",
xlim = c(attr(map, "bb")$ll.lon, attr(map, "bb")$ur.lon),
ylim = c(attr(map, "bb")$ll.lat, attr(map, "bb")$ur.lat)))
} else {
if(overlayInput() == "states"){
return()
}}}
})
})
})
edit: added ui.R
library(shiny)
# Define UI for dataset viewer application
shinyUI(pageWithSidebar(
# Application title.
headerPanel("The New Map App"),
# Sidebar with controls
sidebarPanel(
textInput("searchString", "Get Map Of", value = "melbourne, australia")
, selectInput("mapSource", "Choose a Map Source", choices = c("google", "stamen"))
, numericInput("zoom", "Zoom Level", 10)
, helpText("Note: An integer from 3 (continent) to 21 (building), default value 10 (city)")
, selectInput("mapType", "Choose a Map Type", choices = c("terrain", "satellite", "roadmap", "hybrid", "toner", "watercolor"))
, helpText("Note: Options available are 'terrain', 'satellite', 'roadmap', and 'hybrid' (google maps), 'watercolor', and 'toner' (stamen maps)")
, radioButtons("overlay", "Overlay Polygon",
list("Postcodes" = "postcodes"
, "States" = "states"
, "Nothing" = "nothing"))
, actionButton("searchButton", "Get Map")
, tags$style(type='text/css', "button#searchButton { margin-bottom: 9px; }")
),
#output panel
mainPanel(
h3(textOutput("searchString"))
, plotOutput("map")
)
))
output of sessionInfo:
R version 3.0.1 (2013-05-16)
Platform: x86_64-pc-linux-gnu (64-bit)
locale:
[1] LC_CTYPE=en_AU.UTF-8 LC_NUMERIC=C LC_TIME=en_AU.UTF-8 LC_COLLATE=en_AU.UTF-8 LC_MONETARY=en_AU.UTF-8
[6] LC_MESSAGES=en_AU.UTF-8 LC_PAPER=C LC_NAME=C LC_ADDRESS=C LC_TELEPHONE=C
[11] LC_MEASUREMENT=en_AU.UTF-8 LC_IDENTIFICATION=C
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] RODBC_1.3-7 ggmap_2.3 ggplot2_0.9.3.1 shiny_0.6.0
loaded via a namespace (and not attached):
[1] bitops_1.0-5 caTools_1.14 colorspace_1.2-2 dichromat_2.0-0 digest_0.6.3 grid_3.0.1
[7] gtable_0.1.2 httpuv_1.0.6.3 labeling_0.1 mapproj_1.2-1 maps_2.3-2 MASS_7.3-26
[13] munsell_0.4 plyr_1.8 png_0.1-5 proto_0.3-10 RColorBrewer_1.0-5 Rcpp_0.10.4
[19] reshape2_1.2.2 RgoogleMaps_1.2.0.3 rjson_0.2.12 RJSONIO_1.0-3 scales_0.2.3 stringr_0.6.2
[25] tools_3.0.1 xtable_1.7-1
So I have finally figured this one out.
To have ggplot be able to find the data set in the nested ggplot query, the data set in question needs to be assigned using <<-
For example the data set poa cannot be found in this nested query when being called inside a function.
print(ggmap(map)) + geom_polygon(data = poa, aes(x = LON, y = LAT, group = order), alpha = .5, colour = "black", fill = NA))
So before you need to use poa in the function use this line
poa <<- poa
From the help: "The operators <<- and ->> are normally only used in functions, and cause a search to made through parent environments for an existing definition of the variable being assigned."
This is a tricky one. I might edit this answer as I get a little better acquainted with ggplot's environment nesting. But here's the modified chunk that seems to make it work for me:
env <- environment()
print(ggmap(map, base_layer = ggplot(data = poa, aes(x = LON, y = LAT), environment=env), extent = "normal", maprange = FALSE, environment=environment()) +
geom_polygon(data = poa, aes(x = LON, y = LAT), alpha = .5, colour = "black", fill = NA, environment=env) +
coord_map(projection = "mercator",
xlim = c(attr(map, "bb")$ll.lon, attr(map, "bb")$ur.lon),
ylim = c(attr(map, "bb")$ll.lat, attr(map, "bb")$ur.lat)))
A few things to note here.
group = order
directive, as that causes a "differing number of rows" error. Not sure what you're after there, but it doesn't look right.poa
exists in a variable named env
. This is the environment you want to use in any function which references poa
.geom_polygon
and ggplot
to use the environment I've just created by specifying a environment=env
parameter.ggmap
call to be executed in the calling environment using environment=environment()
as the last parameter in that command. Without this, it won't be able to find the env
variable we created.With those changes, things seem to work properly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With