Alex Thomas
Alex Thomas

Reputation: 1232

plotGoogleMaps in shiny app

I thought it would be really cool to use plotGoogleMaps in a shiny app to dynamically analyze and display spatial data using R. I’ve never used either package before (they are relatively new) and do not have much programming experience, so I started with the tutorials and examples for each and then tried to mash them together.

I can get all of the individual elements of code to work, but running the app does not display the google map. I’m guessing it has to do with plotGoogleMaps trying to plot in a browser and shiny trying to render the plot in a browser, but I don’t know how to resolve this. I pulled most of the shiny code from the shiny tutorial Inputs & Outputs and followed the plotGoogleMaps Tutorial

test code:

#load packages and data
library(shiny)
library(plotGoogleMaps)
data(meuse)

#convert data frame to SpatialPointDataFrame and set 
coordinates(meuse)<-~x+y
proj4string(meuse) <- CRS('+init=epsg:28992')

#will need to select column name for app, maybe not best way to do this, 
#but seems to work
formulaText<-paste('zinc')

#plot data on Google map, opens browser and works
mpgPlot <- plotGoogleMaps(meuse, zcol=formulaText)

ui.R

library(shiny)

# Define UI for meuse test
shinyUI(pageWithSidebar(

    # Application title
    headerPanel("Meuse Test"),

    # Sidebar with controls to select the variable to plot on map
    sidebarPanel(
        selectInput("variable", "Variable:",
                                choices=list("Zinc" = "zinc", 
                                         "Lead" = "lead", 
                                         "Copper" = "copper"), 
                                selected="Zinc")

    ),

    # Show the caption and plot of the requested variable on map
    mainPanel(
        plotOutput("mapPlot")
    )
))

server.R

library(shiny)
library(plotGoogleMaps)

data(meuse)
coordinates(meuse)<-~x+y
proj4string(meuse) <- CRS('+init=epsg:28992')

# Define server logic required to plot various variables on map
shinyServer(function(input, output) {

    # Compute the forumla text in a reactive expression since it is 
    # shared by the output$mapPlot ?I think I still need to do this...
    formulaText <- reactive({
#paste the input name in so it follows argument format for plotGoogleMaps?
#tried without, don't think it is probelm, works with test code...
        paste(input$variable)
    })


    # Generate a plot of the requested variable against mpg and only 
    # include outliers if requested
    output$mapPlot <- renderPlot({
        plotGoogleMaps(meuse, zcol=formulaText)
#also tried to specify alternative arguments like add=TRUE, 
#filename='mapPlot.htm', openMap=FALSE
    })
})

I understand both shiny and plotGoogleMaps are pretty new and I've seen some suggestions to post questions to the shiny Google group, but I don't want to double post and StackOverflow is my go to for answers. I'd also finally like to make a small contribution to a community that has helped me so much so far! If this is just a lousy approach I'm open to alternatives, I'm checking out googleVis now...

Thanks, Alex

PS-

sessionInfo()
R version 3.0.1 (2013-05-16)
Platform: x86_64-w64-mingw32/x64 (64-bit)

locale:
[1] LC_COLLATE=English_United States.1252 
[2] LC_CTYPE=English_United States.1252   
[3] LC_MONETARY=English_United States.1252
[4] LC_NUMERIC=C                          
[5] LC_TIME=English_United States.1252    

attached base packages:
[1] grid      stats     graphics  grDevices utils     datasets  methods  
[8] base     

other attached packages:
[1] googleVis_0.4.3    plotGoogleMaps_2.0 maptools_0.8-25   
[4] lattice_0.20-15    foreign_0.8-54     rgdal_0.8-10      
[7] sp_1.0-11          shiny_0.6.0       

loaded via a namespace (and not attached):
[1] bitops_1.0-5   caTools_1.14   digest_0.6.3   httpuv_1.0.6.3
[5] Rcpp_0.10.4    RJSONIO_1.0-3  tools_3.0.1    xtable_1.7-1 

PPS- I read this post several times before posting, but now am suspicious my answer is there. Appologies if question is duplicate. I think it's something with htmlOutput()... ?htmlOutput is sparse... I'm feeling dense...

Upvotes: 7

Views: 10133

Answers (3)

chamaoskurumi
chamaoskurumi

Reputation: 2483

Thanks to ramnathv's code I managed to embed plotGoogleMaps in shiny without any .html programming knowledge:

library(plotGoogleMaps)
library(shiny)

runApp(list(
  ui = pageWithSidebar(
   headerPanel('Map'),
   sidebarPanel(""),
   mainPanel(uiOutput('mymap'))
   ),
   server = function(input, output){
    output$mymap <- renderUI({
      data(meuse)
      coordinates(meuse) = ~x+y
      proj4string(meuse) <- CRS("+init=epsg:28992")
      m <- plotGoogleMaps(meuse, filename = 'myMap1.html', openMap = F)
      tags$iframe(
        srcdoc = paste(readLines('myMap1.html'), collapse = '\n'),
        width = "100%",
        height = "600px"
      )
    })
   }
))

Note that the legend is not displayed. I have already posted a question about this issue elsewhere.

Upvotes: 4

Ciar&#225;n Tobin
Ciar&#225;n Tobin

Reputation: 7516

I don't know much about plotGoogleMaps, but as Jonathan said it seems to be generating a HTML rather than a plot that you can use for Shiny.

With a bit of effort you can bind Shiny to Google Maps yourself. You will probably want to ditch ui.R and use a custom HTML front-end with a Google Map (read up on the Google Map developer guide here). You page will start like this (straight from Google's "hello world" example):

<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
    <style type="text/css">
      html { height: 100% }
      body { height: 100%; margin: 0; padding: 0 }
      #map-canvas { height: 100% }
    </style>
    <script type="text/javascript"
      src="https://maps.googleapis.com/maps/api/js?key=API_KEY&sensor=SET_TO_TRUE_OR_FALSE">
    </script>
    <script type="text/javascript">
      function initialize() {
        var mapOptions = {
          center: new google.maps.LatLng(-34.397, 150.644),
          zoom: 8,
          mapTypeId: google.maps.MapTypeId.ROADMAP
        };
        var map = new google.maps.Map(document.getElementById("map-canvas"),
            mapOptions);
      }
      google.maps.event.addDomListener(window, 'load', initialize);
    </script>
  </head>
  <body>
    <div id="map-canvas"/>
  </body>
</html>

Don't forget to add in your API key above. Now you need to write the binding (see tutorial). Here's a sample to get you started:

var map_binding = new Shiny.OutputBinding();

$.extend(map_binding, {

  find: function(scope) {
    return $(scope).find('#map-canvas');
  },

  renderValue: function(el, data) {

    // Parse the data sent from R.
    var map_data = jQuery.parseJSON(data);

    // ... 
    // Render points or whatever on map.
    ///

  }
});

Shiny.outputBindings.register(map_binding, "map_binding");

Include this in a separate JavaScript file and load it in the head of the HTML page.

You'll need to edit renderValue() so that whatever data comes in from R is shown on the map. renderValue() will be called each time the map is updated. To see how to actually show points (or whatever you're displaying) on the map, again have a look at Google's documentation (e.g. here) which generally provides most of the code you will need.

Now on the R side, you will have something like this in server.R:

output$map <- renderText({
  RJSONIO::toJSON(some_data)
})

Where you will send whatever data to the map to be plotted (via the renderValue() function).

Upvotes: 1

Jonathan
Jonathan

Reputation: 8812

(disclaimer: not a Shiny expert)

renderPlot works with the R graphics device. In this case, plotGoogleMaps is generating a standalone HTML file, which is not output to the graphics device.

Since the .html files generated by plotGoogleVis are designed to stand alone (i.e. they're not document fragments that could be legally inserted into the Shiny app's document), I think you'll need to embed them in an iframe to get them to render properly (i.e. have plotGoogleVis output to a file, and then load the file in ui.R using tags$iframe).

If your overall goal is just to visualize data on a map, you may have better luck with Leaflet--there's already a package that supplies Shiny to Leaflet bindings.

Upvotes: 3

Related Questions