Home > Net >  How to deal with factor values in a data frame when building a reactive map widget on shiny?
How to deal with factor values in a data frame when building a reactive map widget on shiny?

Time:12-31

I am currently developing a reactive map on Shiny. This map is basically a US map where a selectors enables the user to display different quality variables. The data frame used (called data)looks as follows (data here is randomised) :

head(data)
       state year color leaf mike_value strength length color_leaf_grade staple
1    Alabama 2020    41    1      40.24   300.12  37.00             31-4     34
2   Arkansas 2020    31    1      45.57   300.12  37.80             31-4     34
3    Arizona 2020    11    2      45.51   300.12  37.11             11-2     34
4 California 2020    11    2      45.94   300.12  39.40           others     34
5    Florida 2020    21    3      45.83   300.12  37.18             31-1     37
6    Georgia 2020    41    3      45.06   300.12  36.58           others     37

I am encountering an issue with the color_leaf_grade variable. Indeed, unlike the other variables such as color or leaf which are numeric, color_leaf_grade is a factor. I would like to color the map according to the different factor levels (in total 4 different levels). However, when I do so, I obtain some weird things. As can be seen on the screenshot below, it colours the different states according to the level to which they belong (which is what I want) but instead of displaying the names of the levels in both the legend and the pop-up that appears when hovering the map with the mouse, it displays values 1, 2, 3, 4. I already tried to assign new names to the factor levels, yet it doesn't work.

Screenshot of the widget that displays the current issue that I have

Here is what I have in the ui part of my Shiny app for my map widget:

 tabItem(tabName = "dashboard_map",
                                fluidRow(
                                  box(selectInput("variable_selected",
                                                  label = "Select variable",
                                                  choices = c(
                                                    "Color" = "color",
                                                    "Leaf" = "leaf",
                                                    "Mike" = "mike_value",
                                                    "Strength" = "strength",
                                                    "Length" = "length",
                                                    "Color leaf grade" = "color_leaf_grade",
                                                    "Staple" ="staple"
                                                    )),
                                      width = 9)
                                  ),
                                fluidRow(
                                  box(leafletOutput(outputId = "map"), width = 9),
                                  box(selectInput("myear_selected", 
                                                  label = "Marketing year:", 
                                                  choices=c(year_range),
                                                  selected = year_range[length(year_range)]),
                                      width = 3)),

Here is what I have in the server part of my Shiny app for my map widget:

# MAP
  output$map <- renderLeaflet({
    # Add data to map
    datafiltered <- data[which(data$year == input$myear_selected),]
    orderstates <- match(map@data$STATE_NAME, datafiltered$state)
    map@data <- datafiltered[orderstates,]
    
    # Create variableplot
    # ADD this to create variableplot
    map$variableplot <- as.numeric(map@data[, input$variable_selected])
    
    # Create leaflet
    pal <- colorBin("YlOrRd",
                    domain = map$variableplot,
                    bins = 5)
    
    labels <- sprintf("%s: %g",map$state, map$variableplot) %>%
      lapply(htmltools::HTML)
    
    l <-
      leaflet(map, options = leafletOptions(zoomSnap = 0.25, zoomDelta = 0.25,zoomControl = FALSE)) %>%
      addTiles() %>%
      setView(lng = -98,
              lat = 36,
              zoom = 3.75) %>%
      addPolygons(
        fillColor = ~ pal(variableplot),
        color = "white",
        dashArray = "3",
        fillOpacity = 0.7,
        label = labels
      ) %>%
      leaflet::addLegend(
        "bottomright",
        pal = pal,
        values = ~ variableplot,
        opacity = 0.7,
        title = NULL
      )
  })

Does anyone here have an idea about whether it is possible when building such a reactive map to account for other numeric and categorical types of value?

Thank you very much in advance for your help and happy new year.

CodePudding user response:

In sprintf("%s: %g",map$state, map$variableplot), the values of the factor variable map$variableplot are used (which are just numbers), but you want the levels. (Factor variables are just numbers, where each number is assigned a level. You can check it with str(map$variableplot).) Try the below that extracts the levels when a factor is present:

variableplot_clean <- ifelse(is.factor(map$variableplot),
                             levels(map$variableplot), map$variableplot)

labels <- sprintf("%s: %s",map$state, variableplot_clean) %>%
  lapply(htmltools::HTML)

CodePudding user response:

Since color_leaf_grade is a factor variable, you could use the colorFactor function to generate the palette. You can specify the color for each level in the factor set, like this:

pal <- colorFactor(palette = c("red","yellow","orange","green"),
                levels = c("31-1","11-2","others","factor4..."))

And then your addPolygons would look like this:

addPolygons(
    fillColor = ~pal(color_leaf_grade),
    color = "white",
    dashArray = "3",
    fillOpacity = 0.7,
    label = labels
  )
  • Related