Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Leaflet map legend in R Shiny app has doesn't show colors

Tags:

r

leaflet

shiny

When I try to add a legend to a leaflet map for a leaflet map (using the Leaflet for R package) incorporated into a Shiny app, the legend does not show the colors of the color palette. Instead it only shows the colors specified for the NA values, in this case, white.

legend without colors

The app does the following:

  • First, it filters a set of data based on user inputs
  • Then it generates a choropleth map from the filtered data

This is the code I used to make the legend:

addLegend(position = "bottomleft",
   pal = pal, values = shp.data()$stat.selected,
   title = "Legend",
   opacity = .5)

Where pal is a quantile color palette as follows

pal <-colorQuantile(c("#B2FF66","#66CC00","#4C9900","#336600","#193300"),
                    NULL, n = 5, na.color="#FFFFFF")

shp.data() is a reactive expression that is a shapefile filtered based on user inputs and stat_selected is the specific statistic that the user selects for mapping onto colors.

I get the following warnings:

Warning in is.na(x) :
  is.na() applied to non-(list or vector) of type 'NULL'
Warning in is.na(values) :
  is.na() applied to non-(list or vector) of type 'NULL'

I initially tried to make the legend following the example on the leaflet for R page and used the argument values = ~stat.selected for the addLegend function, but I got this error:

Error in UseMethod("doResolveFormula") : 
  no applicable method for 'doResolveFormula' applied to an object of class "NULL"
like image 906
chokn Avatar asked Jun 04 '15 21:06

chokn


People also ask

How do you add a legend to a leaflet map?

Use the addLegend function to add a legend. The easiest way to use addLegend is to provide pal (a palette function, as generated from colorNumeric et al.) and values , and let it calculate the colors and labels for you.

What does the addTiles() function allow a user to do?

In the code above, addTiles() is used to add the default OpenStreetMap(OSM) tile to the leaflet map. Map tiles weave multiple map images together. The map tiles presented adjust when a user zooms or pans the map enabling the interactive features. The leaflet package comes with more than 100 map tiles that you can use.


3 Answers

Earlier I had just a simple snippet that showed how to add legends. I did not use the ~ before the legend values as is the norm. I did the traditional dataframe$column and it works nicely.

This is now updated to see how it all fits together. Here is a full-fledged mapping run after creating all of the variable cuts, etc. The final cleansed data frame was called zipData

# create a full popup
# add some HTML for editing the styles

zipData$popUp <- paste('<strong>',zipData$Street, '</strong><br>',
                       'TIV = $',prettyNum(zipData$tiv, big.mark = ',',preserve.width = 'none'), '<br>',
                       'City: ', zipData$city, '<br>',
                       'YrBuilt = ', zipData$YearBuilt, '<br>',
                       'Construction = ', zipData$ConstructionCode, '<br>',
                       'Occupancy = ', zipData$OccupancyCode, '<br>',
                       'Premium = $' , prettyNum(zipData$Premium, big.mark = ',',preserve.width = 'none') , '<br>',
                       'GrossArea = ', prettyNum(zipData$GrossArea, big.mark = ',', preserve.width = 'none'), '<br>', 
                       'RoofYr = ', zipData$RoofYearBuilt, '<br>')

# set color scale for key factor
colorsConst <- colorFactor(rainbow(4), zipData$ConstructionCode)

# color scales for numerical bins
colorstivValue <- colorFactor(palette = 'Accent', zipData$tivValueLvl)
colorsYrBuilt <- colorFactor(palette = 'Spectral', zipData$yrBuiltLvl)
colorsRoofYrBuilt <- colorFactor(palette = "YlOrRd", zipData$roofYrBuiltLvl)


# begin the leaflet map construction
# create the map opbject

m <- leaflet() %>%
    addTiles() %>%

# add different tiles for different color schemes

    addProviderTiles(providers$OpenStreetMap, group = 'Open SM')  %>%
    addProviderTiles(providers$Stamen.Toner, group = 'Toner')  %>%
    addProviderTiles(providers$CartoDB.Positron, group = 'CartoDB')  %>%
    addProviderTiles(providers$Esri.NatGeoWorldMap, group = 'NG World') %>%
    setView(lng = -90, lat = 30, zoom = 10) %>%

##############################

    # this section is for plotting the variables
    # each variable below is a layer in the map

    # construction
    addCircleMarkers(data = zipData, lat = ~Lat, lng = ~Lon,
                     color = ~colorsConst(ConstructionCode), popup = zipData$popUp,
                     radius = 5, group = 'Construction') %>%
    # tiv
    addCircleMarkers(data = zipData, lat = ~Lat, lng = ~Lon, 
                     color = ~colorstivValue(tivLvl), popup = zipData$popUp,
                     radius = ~tiv/20000, group = 'Bldg Value') %>%

    # year built  
    addCircleMarkers(data = zipData, lat = ~Lat, lng = ~Lon, 
                     color = ~colorsYrBuilt(yrBuiltLvl), popup = zipData$popUp,
                     radius = ~YearBuilt/250, group = 'Yr Built') %>%


######################################

    # layer control

    addLayersControl(
        baseGroups = c('Open SM', 'Toner', 'Carto DB', 'NG World'),

        overlayGroups = c('Construction',
                          'TIV',
                          'Yr Built'
        ),
        options = layersControlOptions(collapsed = F)
    ) %>%


#################################################       
add the legends for each of the variables


    # construction        
    addLegend('bottomright', pal = colorsConst, values = zipData$ConstructionCode,
              title = 'Construction Code',
              opacity = 1) %>%

     # tiv 
    addLegend('bottomleft', pal = colorstivValue, values = zipData$tivLvl,
              title = 'TIV',
              opacity = 1) %>%

    # year built
    addLegend('topleft', pal = colorsYrBuilt, values = zipData$yrBuiltLvl,
              title = 'Yr Built',
              opacity = 1)


m  # Print the map

A portion of the map is shown below.

This shows the layer control and the construction legend

like image 106
Bryan Butler Avatar answered Sep 23 '22 22:09

Bryan Butler


I was able to make the colors showing up by changing the way I was referencing the values column in the arguments of the AddLegend function. I put the stat.selected variable in double brackets, which seemed to fix the problem:

addLegend(position = "bottomleft",
          pal = pal, values = shp.data()[[stat.selected]],
          title = "Legend",
          opacity = 1
          )

For clarification, the stat.selected variable comes from the following switch statement:

 stat.selected <- isolate(switch(input$var.stat,
                                "Total employment" = "tot_emp",
                                "Mean annual wage" = "a_mean",
                                "Mean hourly wage" = "h_mean",
                                "Location quotient" = "loc_quotient"
)

where "tot_emp", "a_mean", "h_mean", and "loc_quotient" are column names in the shp.data spatial polygons data frame.

I guess the problem was that I was trying to pass in the column name by variable using a $.

I'm still a fairly novice R user, so if anyone can explain why the example in the Leaflet for R documentation does not work in this case I would appreciate it.

like image 26
chokn Avatar answered Sep 23 '22 22:09

chokn


I had the same message

Error in UseMethod("doResolveFormula") : no applicable method for 'doResolveFormula' applied to an object of class "NULL" 

with

    data <- data.frame(lng1 = c(1, 2, 3), 
                   lng2 = c(2, 3, 4), 
                   lat1 = c(1, 2, 3), 
                   lat2 = c(2, 3, 4), 
                   values = c(1, 2, 3))

    pal_grid <- colorNumeric(palette = "YlGn", domain = data$values)

    leaflet() %>% 
      addRectangles(lng1 = data$lng1, lat1 = data$lat1, 
                lng2 = data$lng2, lat2 = data$lat2, 
                fillColor = ~pal_grid(data$values),
                fillOpacity = 0.2,
                weight = 2, opacity = 0.5)

The solution is to provide to leaflet the data that you are using to create the element in the main call to leaflet() or in the call to any element that you add after that.

  1. In the main call to leaflet():

    data <- data.frame(lng1 = c(1, 2, 3), 
                   lng2 = c(2, 3, 4), 
                   lat1 = c(1, 2, 3), 
                   lat2 = c(2, 3, 4), 
                   values = c(1, 2, 3))
    
    pal_grid <- colorNumeric(palette = "YlGn", domain = data$values)
    
    leaflet(data = data) %>% 
      addRectangles(lng1 = data$lng1, lat1 = data$lat1, 
                lng2 = data$lng2, lat2 = data$lat2, 
                fillColor = ~pal_grid(data$values),
                fillOpacity = 0.2,
                weight = 2, opacity = 0.5)
    
  2. At the moment of add elements:

    data <- data.frame(lng1 = c(1, 2, 3), 
                   lng2 = c(2, 3, 4), 
                   lat1 = c(1, 2, 3), 
                   lat2 = c(2, 3, 4), 
                   values = c(1, 2, 3))
    
    pal_grid <- colorNumeric(palette = "YlGn", domain = data$values)
    
    leaflet() %>% 
      addRectangles(data = data,
                lng1 = data$lng1, lat1 = data$lat1, 
                lng2 = data$lng2, lat2 = data$lat2, 
                fillColor = ~pal_grid(data$values),
                fillOpacity = 0.2,
                weight = 2, opacity = 0.5)`
    
like image 28
avidalvi Avatar answered Sep 23 '22 22:09

avidalvi