0

The goal is to create an interactive (single) plot in Shiny in which the user can select any of the wanted variables of the dataframe. For now the variable freq_prov_tot is plotted. The plot itself is working, but I do not know how to include other variables to "choose" from in an interactive manner. Also a tooltip is included. I'm using ggiraph due to the posibility of integrating this interactive polygon map into Shiny quite easily.

If you have any idea how this can be fixed, help is very much appreciated.

The dataframe I'm using is as follows. For protection of the used data all provinces are given a value of 1 for the variable freq_prov_tot.

counties_e<- fortify(Iran3, region = "NAME_1")
counties_e$freq_prov_tot<- ifelse(counties_e$id == "Alborz",1,
                       ifelse(counties_e$id == "Ardebil",1,  
                       ifelse(counties_e$id == "Bushehr",1,
                       ifelse(counties_e$id == "Chahar Mahall and Bakhtiari",1,
                       ifelse(counties_e$id == "East Azarbaijan",1,
                       ifelse(counties_e$id == "Esfahan",1,
                       ifelse(counties_e$id == "Fars",1,
                       ifelse(counties_e$id == "Gilan",1,
                       ifelse(counties_e$id == "Golestan",1,
                       ifelse(counties_e$id == "Hamadan",1,
                       ifelse(counties_e$id == "Hormozgan",1,
                       ifelse(counties_e$id == "Ilam",1,
                       ifelse(counties_e$id == "Kerman",1,
                       ifelse(counties_e$id == "Kermanshah",1,
                       ifelse(counties_e$id == "Khuzestan",1,
                       ifelse(counties_e$id == "Kohgiluyeh and Buyer Ahmad",1,
                       ifelse(counties_e$id == "Kordestan",1,
                       ifelse(counties_e$id == "Lorestan",1,
                       ifelse(counties_e$id == "Markazi",1,
                       ifelse(counties_e$id == "Mazandaran",1,
                       ifelse(counties_e$id == "North Khorasan",1,
                       ifelse(counties_e$id == "Qazvin",1,
                       ifelse(counties_e$id == "Qom",1,
                       ifelse(counties_e$id == "Razavi Khorasan",1,
                       ifelse(counties_e$id == "Semnan",1,
                       ifelse(counties_e$id == "Sistan and Baluchestan",1,
                       ifelse(counties_e$id == "South Khorasan",1,
                       ifelse(counties_e$id == "Tehran",1,
                       ifelse(counties_e$id == "West Azerbaijan",1,
                       ifelse(counties_e$id == "Yazd",1,
                       ifelse(counties_e$id == "Zanjan",1, 0)))))))))))))))))))))))))))))))

The code for the tooltip

provinces_e <- sprintf("<p>%s</p>",
                       as.character(counties_e$id) )
table_e <- paste0(
  "<table><tr><td>Total Number of Environmental Issues:</td>",
  sprintf("<td>%.0f</td>", counties_e$freq_prov_tot),
  "</tr></table>"
)

counties_e$labs <- paste0(provinces_e, table_e)

the code for the ui and server

ui_e <- fluidPage(

  # Application title
  titlePanel("Spatial Distribution of Environmental Issues in Iran during 1930 - 2018"),
  fluidRow(column(12,
                  ggiraph::ggiraphOutput("county_map")))
)

server_e <- function(input, output) {

  output$county_map<- renderggiraph({
    p<- ggplot(counties_e, aes(x=long, y=lat, group = group, fill = freq_prov_tot)) +
      xlab("Longitude") + ylab("Lattitude") + labs(fill = "Number of Environmental Issues") +
      coord_map("polyconic" ) +
      geom_polygon_interactive(aes(tooltip = labs))

    ggiraph(code = print(p))
  })

}

shinyApp(ui = ui_e, server = server_e)

Counties_e can be downloaded with the following link:

https://drive.google.com/file/d/1TOyZIADTCnRFyWLehxS7Td9v-BOZXARS/view?usp=sharing

2 Answers2

0

The following code could be a solution. Labels annotations are added and are used as a basic menu. It's not really pretty, some work need to be done to make it nicer...

counties_e <- read.csv("~/Downloads/counties_e.csv", row.names=1, stringsAsFactors=FALSE)
library(ggiraph)
library(shiny)
library(ggplot2)
library(rlang)

ui_e <- fluidPage(

  # Application title
  titlePanel("Spatial Distribution of Environmental Issues in Iran during 1930 - 2018"),
  fluidRow(column(
    12,
    ggiraph::ggiraphOutput("county_map")
  ))
)

min_ann_y <- min(counties_e$lat, na.rm = TRUE)
max_ann_y <- max(counties_e$lat, na.rm = TRUE)
y_pos <- seq(from = min_ann_y, to = max_ann_y, along.with = colnames(counties_e))

server_e <- function(input, output) {
  rv <- reactiveValues(column = tail(colnames(counties_e), n = 1))
  observeEvent(input$county_map_selected, {
    rv$column <- input$county_map_selected
  })
  output$county_map <- renderggiraph({
    tooltip_col <- sym(rv$column)

    p <- ggplot(counties_e, aes(x = long, y = lat, group = group, fill = freq_prov_tot)) +
      xlab("Longitude") + ylab("Lattitude") + labs(fill = "Number of Environmental Issues") +
      coord_map("polyconic") +
      scale_x_continuous(limits = c(40, NA)) + 
      geom_polygon_interactive(aes(tooltip = format(!!tooltip_col, trim = TRUE))) +
      annotate_interactive(
        "label", hjust = 0,
        x = 40,
        y = y_pos, fill = "#FF000009",
        data_id = colnames(counties_e),
        label = colnames(counties_e)
      )

    girafe_options(
      girafe(ggobj = p),
      opts_selection(
        type = "single", selected = rv$column,
        css = girafe_css(
          css = "fill:purple;stroke:black;",
          text = "stroke:none;fill:red;"
        )
      ),
      opts_hover(css = "stroke:none;fill:red;")
    )
  })
}

print(shinyApp(ui = ui_e, server = server_e))

enter image description here

David Gohel
  • 9,180
  • 2
  • 16
  • 34
  • Thank you for your comment. However I was questioning if there is a way to let users of the map for themselves select which variable to show [instead of freq_prov in this case] using for instance sidebarPanel. I'm sorry if this was not clear. An example ui: `ui_try <- fluidPage( headerPanel("header"), titlePanel("title"), sidebarPanel( selectInput("id", "Select Plot", counties_e, selected = "freq_prov_tot", multiple = TRUE) ), mainPanel( tabsetPanel( tabPanel("plot", plotOutput("plot") ) ) ) )` – SofieCroonenberg Oct 05 '19 at 15:09
  • I have updated the answer - sorry I misunderstood your question – David Gohel Oct 05 '19 at 15:57
  • Hi David. Thank you a lot! However, your script does not seem to work since it does not identify "label" as a geom function, giving the following warning: "Warning: Error in : Can't find interactive geom function called "label"" Is there maybe a package you installed before that made you be able to use label as a geom function here? – SofieCroonenberg Oct 05 '19 at 16:16
  • it needs dev/github version – David Gohel Oct 05 '19 at 17:39
  • I added another answer to my question which uses ObserveEvent. If you have any information on how to include variables in this manner in my interactive graph, that would be very helpful. – SofieCroonenberg Oct 06 '19 at 12:24
  • you can look at `tooltip = format(!!tooltip_col, trim = TRUE)` in my answer and adapt to your need – David Gohel Oct 06 '19 at 18:04
0

I decided to use a different format using the function observeEvent(). This includes the different columns as an input for the final map in a nicer way.

This however does not work since it refuses to respond to the selectInput function.

This is the changed ui and server code I used for this

ui <- fluidPage(

  # Application title
  titlePanel("Spatial Distribution of Protest Events in Iran during 2005 - 2017"),

  sidebarPanel(
    selectInput(
      inputId = "counties",
      label   = "counties",
      choices = c("freq_prov_tot", "freq_prov_air")
    )
  ), 
  fluidRow(column(12,
                  ggiraph::ggiraphOutput("county_map")))
)


server <- function(input, output) {

  data2 <- observeEvent(input$choices, {counties}) 

  output$county_map<- renderggiraph({
    p<- ggplot(data2, aes(x=long, y=lat, group = group, fill = data2)) +
      xlab("Longitude") + ylab("Lattitude") + labs(fill = "Number of Protest Events\n regarding Air Quality") +
      coord_map("polyconic" ) +
      geom_polygon_interactive(aes(tooltip = labs))

    ggiraph(code = print(p)) 

})} 

shinyApp(ui = ui, server = server)

It gives the following error: "data must be a data frame, or other object coercible by fortify(), not an S3 object with class Observer/R6"

Does anybody have an idea to fix this?