Search code examples
rr-leaflet

Image in R Leaflet marker popups


I'm trying to make my leaflet map generated by R include images in the popups for markers in a dynamic way - e.g.,

library(leaflet)


pts <- data.frame(Latitude = 30, Longitude = 30, file = "thing")

leaflet() %>%
  addTiles %>%
  addCircleMarkers(data = pts, lng =~Longitude, lat = ~Latitude,
                   popup =~ paste0("<img src = './", file, ".jpg'>"))

The above generates an bad image (ye olde ? in an image), however. Viewing source makes it look like it should work....not sure what's wrong here.

{"lineCap":null,"lineJoin":null,"clickable":true,"pointerEvents":null,
"className":"","stroke":true,"color":"#03F","weight":5,"opacity":0.5,"fill":true,"
fillColor":"#03F","fillOpacity":0.2,"dashArray":null},null,null,
"<img src = './thing.jpg'>"]}],"limits":{"lat":[30,30],"lng":[30,30]}},"evals":[]}

Solution

  • If you can use svg instead of jpg it should work. See my answer here.

    EDIT/UPDATE:
    It is possible to embed image files that are not local. Consider the following, where we add the R logo from Wikipedia.

    library(leaflet)
    
    pts <- data.frame(Latitude = 30, Longitude = 30, file = "thing")
    
    file <- 'https://upload.wikimedia.org/wikipedia/commons/thumb/c/c1/Rlogo.png/274px-Rlogo.png'
    
    leaflet() %>%
      addTiles %>%
      addCircleMarkers(data = pts, lng =~Longitude, lat = ~Latitude,
                       popup = paste0("<img src = ", file, ">"))
    

    This works just fine.

    For local files it is a bit more tricky as leaflet, or better the underlying htmltools, is expecting relative paths to the specified image file from the location of the index.html which is being stored in a temporary folder that is being created on widget creation. Hence we cannot know in advance where to save our images beforehand. @Spacedman provided some functions for storing leaflet maps in a user specified folder, so we can use those to create our working map like this

    library (leaflet)
    
    saveas <- function(map, file){
      class(map) <- c("saveas",class(map))
      attr(map,"filesave")=file
      map
    }
    
    print.saveas <- function(x, ...){
      class(x) = class(x)[class(x)!="saveas"]
      htmltools::save_html(x, file=attr(x,"filesave"))
    }
    
    file <- '/path/to/folder/image.png'
    
    pts <- data.frame(Latitude = 30, Longitude = 30, file = "thing")
    
    m <- leaflet() %>%
      addTiles %>%
      addCircleMarkers(data = pts, lng =~Longitude, lat = ~Latitude,
                       popup = paste0("<img src = ", file, ">"))
    
    saveas(m, "/path/to/folder/index.html")
    

    We save the index.html in the same folder as the png so now if we open the index.html in a browser the popup should render the png just fine. This should also work with jpg files.

    Note that this will still not show the desired popup behaviour in the RStudio viewer. There may be a possible workaround for this also by encoding the images to base64. I will dig deeper into this when I find the time.

    UPDATE 2: The development version of mapview now has dedicated functions for this:

    • popupImage() for embedding local or remote images
    • popupGraph() for embedding lattice, ggplot2 or htmlwidgets based plots

    The development version of mapview can be installed with:

    devtools::install_github("environmentalinformatics-marburg/mapview", ref = "develop"