Search code examples
rggplot2r-leaflet

Create icons from standard barplot (or ggplot2 geom_col) with single bar


I want to create png icons with single bar (from standard barplot or ggplot2 geom_col). Icons will be presented on leaflet map. There is data.frame: lat,lon,val. Parameter "val" is used to set height of bar (only one bar on one icon). Icons must have the same size, bars must have the same width, each bar with label above (val). Height of bar is restricted with maximum value (icon height).

Example image - map with icons to be reconstructed

Sample code is below. I used hints from here: R Barplot with one bar - how to plot correctly

Result with my code - all have the same height

lats = c(69.5, 70.0, 69.0) 
lons = c(33.0,33.5,34.3) 
vals = c(7,19,5) 
df = data.frame(lats, lons, vals)

for (i in 1:3) {
      png(file=paste0(i,".png"), width=100, height=200, res=72)
      bp <- barplot(df$vals[i], height =df$vals[i],
                    width=0.2, xlim=c(0,1.2), col="brown4", axes=FALSE);
      text(bp, 10*df$vals[i]+10, labels=df$vals[i]);
      dev.off()
}

Solution

  • I used advice from @Axeman and carried out a few experiments with png/barplot parameters. Problem is solved. The result is as following.

    library(shiny)
    library(leaflet)
    
    ui <- fluidPage(leafletOutput("map"))
    
    myicon=function(condition){
      makeIcon(
        iconUrl = paste0(condition,".png"),
        iconWidth = 30, iconHeight = 80
      )}
    
    server <- function(input, output, session) {
    
      lats = c(69.5, 70.0, 69.0) 
      lons = c(33.0,33.5,34.3) 
      vals = c(7,12,5) 
      df = data.frame(lats, lons, vals)
      for (i in 1:nrow(df)) {
        png(file=paste0(i,".png"), bg="transparent",width=3, height=10, units="in", res=72)
        bp <- barplot(df$vals[i], height =10*df$vals[i],
                      width=1, ylim=c(0,max(10*df$vals)+30),col="brown4", axes=FALSE);
        text(bp,10*df$vals[i]+20,labels=df$vals[i],cex=10,font=2);
        dev.off()
      }
    
      output$map <- renderLeaflet({
        top=70.4;
        bottom=66.05;
        right=42.05;
        left=27.5;
        leaflet(data = df,
                options = leafletOptions(minZoom = 3,maxZoom = 10))%>%
          fitBounds(right,bottom,left,top)%>%
          addTiles()%>%
          addProviderTiles("Esri.OceanBasemap") %>%
          addMarkers(
            icon = myicon(index(df)),
            lng = lons, lat = lats,
            options = markerOptions(draggable = TRUE))
      })
    }
    
    shinyApp(ui, server)