Leaflet in R plotting icons unpredictably - r

My Shiny app takes a dataframe like this:
and subsets appropriately by allowing the user to select a person (P1_name) and a date (date).
When initally launched, it looks like this:
and already, it is clear that the app isn't working. There should be a letter 'N' at the location of the town of Apple Valley, but instead there is nothing. I can't figure out why, since the DF has been subsetted correctly:
and the layers should be plotted correctly:
m <- leaflet(DF) %>%
addTiles() %>% # Add default OpenStreetMap map tiles
setView(lat=setzoom[1], lng=setzoom[2], zoom=zoom_num) %>%
addMarkers(lat=subset(DF, P1_outcome=='W')$lat, lng=subset(DF, P1_outcome=='W')$lon, icon = icon_W) %>%
addMarkers(lat=subset(DF, P1_outcome=='L')$lat, lng=subset(DF, P1_outcome=='L')$lon, icon = icon_L) %>%
addMarkers(lat=subset(DF, P1_outcome=='D')$lat, lng=subset(DF, P1_outcome=='D')$lon, icon = icon_D) %>%
addMarkers(lat=subset(DF, P1_outcome=='N')$lat, lng=subset(DF, P1_outcome=='N')$lon, icon = icon_N)
Unfortunately, this is just one symptom of some sort of skitzophrenic behavior that my app is displaying. If that was the only problem, I'd be rejoicing. Instead, say I select John Doe, on his first row (which should be Crecent City)
and BOOM I get:
How in the world did Leaflet think I had given it two sets of coordinates to plot, and what made it think that John Doe was drowing somewhere in the Pacific Ocean.
Nothing here makes much sense. I can't see a pattern in the chaos it is outputting. It's barely 100 lines of simple code.
Some ideas:
the conditionalPanel is mixing up my dataframe? I don't think so, since I can View(DF) and see that this part isn't the problem.
the layering in the icons isn't working? Not sure how this would be a problem, as we know that this is the correct way to plot icons.
I am getting an xtable warning, Warning in run(timeoutMs) : data length exceeds size of matrix, but this is just for the tableOutput part, which I don't think is related to any of the issue I'm beseiged with.
I'm stumped. Been stuck on this all day. If anyone has any insight, ideas, incantations, etc, I'd love to hear them.
UI.R
library(shiny)
library(ggplot2)
library(dplyr)
library(leaflet)
library(data.table)
options(xtable.include.rownames=F)
library(ggmap)
library(lubridate)
DF <- data.frame(lon=c(-120.6596156, -87.27751, -119.7725868, -124.2026, -117.1858759),
lat=c(35.2827524, 33.83122, 36.7468422, 41.75575, 34.5008311),
date=c('2014-03-14', '2014-01-11', '2013-11-22', '2012-08-23', '2013-08-23'),
location=c('San Luis Obispo', 'Jasper', 'Fresno', 'Crescent City', 'Apple Valley'),
P1_name=c('John Doe', 'John Doe', 'John Doe', 'John Doe', 'Joe Blow'),
P1_outcome=c('W', 'L', 'D', 'W', 'N'))
DF$date <- as.Date(DF$date, format="%Y-%m-%d")
DF <- arrange(DF, P1_name, date)
DT <- data.table(DF)
DT[, .date := sequence(.N), by = "P1_name"]
DF$date <- paste(DF$date, ' (', DT$.date, ')', sep='')
DF <- arrange(DF, P1_name, desc(date))
DF$P1_name <- as.character(DF$P1_name)
DF$P1_outcome <- as.character(DF$P1_outcome)
DF$location <- as.character(DF$P1_location)
#str(DF$P1_outcome)
icon_W <- makeIcon(
iconUrl = "http://i58.tinypic.com/119m3r5_th.gif",
iconWidth = 10, iconHeight = 23,
iconAnchorX = 10, iconAnchorY =23
)
icon_L <- makeIcon(
iconUrl = "http://i62.tinypic.com/2dulcvq_th.jpg",
iconWidth = 10, iconHeight = 23,
iconAnchorX = 10, iconAnchorY = 23
)
icon_D <- makeIcon(
iconUrl = "http://i58.tinypic.com/2zox2yf_th.gif",
iconWidth = 10, iconHeight = 23,
iconAnchorX = 10, iconAnchorY = 23
)
icon_N <- makeIcon(
iconUrl = "http://i62.tinypic.com/339j7de_th.gif",
iconWidth = 10, iconHeight = 23,
iconAnchorX = 22, iconAnchorY = 94
)
server <- function(input, output, session) {
output$dates<-renderUI({
selectInput('dates', 'by date / number', choices=DF[which(DF$P1_name == input$person), ]$date, selectize = FALSE)
})
output$map<-renderLeaflet({
validate(
need(!is.null(input$dates),""),
need(!is.null(input$person),"")
)
if(input$radio=='by date'){
DF <- filter(DF, P1_name==input$person, date==input$dates)
View(DF)
zoom_num <- 5
setzoom <- c(DF$lat, DF$lon)
outcome <- data.frame(DF$P1_outcome, DF$location)
output$table <- renderTable(outcome)
}
else{
DF <- filter(DF, P1_name==input$person)
View(DF)
zoom_num <- 2
setzoom <- c(DF$lat[1], DF$lon[1])
outcome <- data.frame(DF$P1_outcome, DF$location)
output$table <- renderTable(outcome)
}
m <- leaflet(DF) %>%
addTiles() %>% # Add default OpenStreetMap map tiles
setView(lat=setzoom[1], lng=setzoom[2], zoom=zoom_num) %>%
addMarkers(lat=subset(DF, P1_outcome=='W')$lat, lng=subset(DF, P1_outcome=='W')$lon, icon = icon_W) %>%
addMarkers(lat=subset(DF, P1_outcome=='L')$lat, lng=subset(DF, P1_outcome=='L')$lon, icon = icon_L) %>%
addMarkers(lat=subset(DF, P1_outcome=='D')$lat, lng=subset(DF, P1_outcome=='D')$lon, icon = icon_D) %>%
addMarkers(lat=subset(DF, P1_outcome=='N')$lat, lng=subset(DF, P1_outcome=='N')$lon, icon = icon_N)
}) #<- end output$map
} #<- end server function
ui <- fluidPage(
titlePanel("Location Explorer"),
sidebarLayout (
sidebarPanel(
selectInput('person', 'Select person', choices=unique(DF$P1_name), selectize = FALSE),
radioButtons('radio', 'Select row(s)', choices=c('by date', 'all'), selected = NULL, inline = TRUE),
conditionalPanel(
condition = "input.radio == 'by date'",
uiOutput('dates')
),
conditionalPanel(
condition = "input.radio == 'all'"
)
),
mainPanel(
leafletOutput('map'),
fluidRow(column(4, tableOutput('table')))
))
) #<- end ui
shinyApp(ui = ui, server = server)

One of the issue could be that you are adding empty markers in your subsets and leaflet reacts strangely to that.
For example, when you select Joe Blow, all the subsets for P1_outcome == "W", "L" or "D" are empty.
As described here, you could use the iconList function to change the icons depending on P1_outcome and remove all the subset.
You could for example add:
icon_list <- iconList(W=icon_W,L=icon_L,D=icon_D,N=icon_N)
right after you define all the icons, and use:
m <- leaflet(DF) %>%
addTiles() %>% # Add default OpenStreetMap map tiles
setView(lat=setzoom[1], lng=setzoom[2], zoom=zoom_num) %>%
addMarkers(lat=DF$lat, lng=DF$lon,icon= ~icon_list[DF$P1_outcome])
to create your map.

Related

Reactive Sankey Diagram in R Shiny with multiple dataframes as input

It's my first time creating a dashboard and I'm running into a problem I can't seem to solve. I have created a sankey diagram and I want to be able to interactively change its contents through different dataframes (in this example: level_1, level_2, level_3). I've only ever practiced this with a regular plot, where the input would come from a variable within one dataframe which is my starting point in this piece of code (e.g. I have a df$country, so I use input$country in my plot --> Then I could choose from different countries in the dashboard sidebar, in order to change the contents of the plot). I have no idea how to do this when the input has to come from seperate dataframes.
My code: (in app.R)
level_1 <- as.data.frame(matrix(sample(seq(0,40), 15, replace=T ), 3, 5))
level_2 <- as.data.frame(matrix(sample(seq(0,40), 20, replace=T ), 4, 5))
level_3 <- as.data.frame(matrix(sample(seq(0,40), 25, replace=T ), 5, 5))
levels <- list(level_1, level_2, level_3)
ui <- dashboardPage(
dashboardHeader(title = "title"),
dashboardSidebar(
selectInput("in_levels", "Levels", choices = levels)
),
dashboardBody(
fluidRow(sankeyNetworkOutput("widget1"))
)
)
server <- function(input, output) {
links <- input$in_levels %>%
rownames_to_column(var="source") %>%
gather(key="target", value="value", -1) %>%
filter(value != 0)
nodes <- data.frame(
name=c(as.character(links$source), as.character(links$target)) %>%
unique()
)
links$IDsource <- match(links$source, nodes$name)-1
links$IDtarget <- match(links$target, nodes$name)-1
output$widget1 <- renderSankeyNetwork({
sankeyNetwork(Links = links, Nodes = nodes,
Source = "IDsource", Target = "IDtarget",
Value = "value", NodeID = "name", fontSize = 14, nodeWidth = 60,
fontFamily = "Arial", iterations = 0, sinksRight=TRUE)
})
}
shinyApp(ui, server)
I thought maybe it would help to create a list(), levels, of all the dataframes, but that does not work. I get this error:
Error : Can't access reactive value 'in_levels' outside of reactive consumer.
i Do you need to wrap inside reactive() or observer()?
I've googled reactive() and observer() to try to find out what my next step should be, but I haven't found the solution yet. It would be much appreciated if someone could give me advice on how to proceed, changes to make or something to read to increase my understanding.
Thanks in advance!
If you want to access any input values in the server you need to use a reactive context. shiny won't allow you to do otherwise, but even if it did, if an input value is updated, the server-side code won't update to reflect the change. Since you want both links and nodes to be dynamic and both depend on each other, a neat solution might be to store both objects in a list as follows:
server <- function(input, output) {
plot_data <- reactive({
# Perform all your computation inside this reactive!
links <- input$in_levels %>%
rownames_to_column(var="source") %>%
gather(key="target", value="value", -1) %>%
filter(value != 0)
nodes <- data.frame(
name = c(as.character(links$source), as.character(links$target)) %>%
unique()
)
links$IDsource <- match(links$source, nodes$name)-1
links$IDtarget <- match(links$target, nodes$name)-1
# Return the data in a list
list(links = links, nodes = nodes)
})
# Access the datasets by calling the reactive and then treating as a normal list
output$widget1 <- renderSankeyNetwork({
sankeyNetwork(Links = plot_data()$links, Nodes = plot_data()$nodes,
Source = "IDsource", Target = "IDtarget",
Value = "value", NodeID = "name", fontSize = 14, nodeWidth = 60,
fontFamily = "Arial", iterations = 0, sinksRight=TRUE)
})
}
This is untested as my current version of R doesn't support the network3d package.
The concept of reactivity is tricky, but chapter 3 of Mastering Shiny should be very illuminating if you're new to shiny.

wide data format as input to a Shiny mapview app - reactive wrapper(s) needed?

I'm having trouble using columns from data originating in wide format as dynamic inputs to a Shiny map app.
In the app I'm hoping to be able to:
select a parameter of point data (sample data below: 16 locations, 6 parameters) in a drop down type menu and adjust the symbol size to represent the selected parameter's absolute values with a slider (to help visualize positive and negative differences from zero)
with any parameter selected, retain ability to see all parameters (the columns) in mapview's popup feature (mapview turns the columns into rows for the popup). It seems a filtered long format data.frame would be missing data from the popup/viewing perspective
retain the (non absolute) original value on the mouseover hover label (eg the -7.3 in the image)
In addition to having those features, I don't know if/where I need to set reactive wrapper(s)? Or, maybe I could do everything more easily with another map-centric library (even though mapview is awesome for many things)?
My attempts are commented out below - the UI works as intended except without drop down selectability - the app is limited to only one working dropdown parameter with mapview(df["param1"] and cex = param1 * input$cex.
Here's the reproducible app.r:
library(tidyverse)
library(sf)
library(shiny)
library(shinydashboard)
library(leaflet)
library(mapview)
## sample earthquake data ##
set.seed(6)
lat <- rnorm(16,-34, 9)
lon <- rnorm(16,-67,.3)
param1 <- rnorm(16, 10, 40) %>% round(1)
param2 <- rnorm(16, 25, 3) %>% round(1)
param3 <- rnorm(16, -18, 10) %>% round(1)
param4 <- rnorm(16, -200, 93) %>% round(1)
param5 <- rnorm(16, 0.1, .09) %>% round(1)
param6 <- rnorm(16, 417, 33) %>% round(1)
df <- data.frame(lat, lon, param1, param2, param3, param4, param5,
param6)
df <- st_as_sf(df, coords = c("lon", "lat"), crs = 4326)
paramchoices <- colnames(df) %>% .[.!="geometry"]
colorpal = mapviewPalette("mapviewSpectralColors")
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(
sliderInput("cex", "Symbol Size",
min = 0.000001, max = 10, value = 1, step = 0.000001
),
selectizeInput(
"parameter", "Earthquake Parameter", choices = paramchoices,
selected = c("param1"),
multiple = FALSE)
),
dashboardBody(
tags$style(type = "text/css", "#mapplot {height: calc(100vh - 80px) !important;}"),
leafletOutput("mapplot")
)
)
server <- function(input, output) {
# df <- reactive ({
# df %>% mutate(selectedparameter = input$parameter,
# selectedparameter_abs = abs(selectedparameter))
# })
output$mapplot <- renderLeaflet({
m <- mapview(df["param1"], #mouseover column
#m <- mapview(df["selectedparameter"],
cex = param1 * input$cex, #marker size column
#cex = df$selectedparameter_abs * input$cex,
col.regions = colorpal(100),
alpha.regions = 0.3,
legend = TRUE,
popup = popupTable(df),
layer.name = "selectedparam[unit]")
m#map
}
)}
shinyApp(ui, server)
more info related to the absolute value part - Point color and symbol size based on different variables in mapview
thank you.

Shiny App: Error in filter_impl: Result must have length 4090, not 0

Trying to run a shiny app, but keep getting the error: Error in filter_impl: Result must have length 4090, not 0
I've tried:
debugging by removing individual filters to try isolate the issue.
using dplyr::filter to force dplr's filter
ensured all filters are in a reactive function
checked whether it was an issue of sharing inputs between ui.R and server.r
checked whether it is caused by a previous df transformation.
Spent about 3 hours trying to find the cause, with no success.
Can you please help?
Server.R
rm(list = ls())
library(shiny)
library(tidyverse)
library(shiny)
library(ggplot2)
library(singer)
library(ggvis)
library(dplyr)
# Set Up DataFrames
data(package = "singer")
data(singer_locations)
sdf <- singer_locations %>% filter(year != 0) # filter out songs with missing years for simplicity
sdf %>% skim() %>% kable() # Check to see missing and incomplete values
sdf <- sdf %>% filter(complete.cases(.)) # filter out songs with missing observations for simplicity
sdf %>% skim() %>% kable() # Check to see if missing and incomplete values have been ignored
sdf <- sdf %>% select(
track_id, title, song_id, release, artist_id, artist_name, year, duration,
artist_hotttnesss, artist_familiarity, name, city, longitude, latitude
)
# add new columns with rounded data (for nicer graphs later)
sdf$latitude_rounded <- round(sdf$latitude, 0)
sdf$longitude_rounded <- round(sdf$longitude, 0)
sdf$duration_rounded <- round(sdf$duration, 0)
# Add song_popularity & very_popular_song columns
pops <- sdf$artist_hotttnesss + sdf$artist_familiarity
sdf$artist_popularity <- round(pops, 0)
sdf$very_popular_song <- round(sdf$artist_popularity)
sdf$very_popular_song[sdf$very_popular_song < 1] <- "No"
sdf$very_popular_song[sdf$very_popular_song >= 1] <- "Yes"
# Select() relevant variables so they can be passed into server below (without having to use df[,"VAR"])
songs_list <- sdf %>% select(
track_id, title, song_id, release, artist_id, artist_name, year, duration_rounded, duration,
artist_hotttnesss, artist_familiarity, name, city, latitude_rounded, longitude_rounded, longitude,
latitude, artist_popularity, very_popular_song
)
#axis_variables <- reactive({
axis_variables <- c(
"Length of Song (Seconds)" = "duration_rounded",
"Rating" = "artist_hotttnesss",
"Rating" = "artist_familiarity",
"Year" = "year",
"Popularity Rating" = "artist_popularity"
)
################################### SHINY SERVER #########################################
function(input, output) {
songs <- reactive({ # Create Reactive Filtering Component
duration_s <- input$duration_s
artist_hotttnesss_s <- input$artist_hotttnesss_s
artist_familiarity_s <- input$artist_familiarity_s
latitude_s <- input$latitude_s
longitude_s <- input$longitude_s
year_s <- input$year_s
artist_popularity_s <- input$artist_popularity_s
# Apply filters
songs_df <- songs_list %>%
dplyr::filter(
duration_rounded >= duration_s,
artist_hotttnesss >= artist_hotttnesss_s,
artist_familiarity >= artist_familiarity_s,
latitude_rounded >= latitude_s,
longitude_rounded >= longitude_s,
year >= year_s,
artist_popularity >= artist_popularity_s
) %>%
arrange(duration_rounded)
# filter by city option
if (input$city_in != "All") {
city_in_temp <- paste0("%", input$city_in, "%")
songs_df <- songs_df %>% dplyr::filter(songs_df$city %like% city_in_temp)
}
# filter by artist_name option
if (input$artist_name_in != "" && !is.null(input$artist_name_in)) {
artist_name_temp <- paste0("%", input$artist_name_in, "%")
songs_df <- songs_df %>% dplyr::filter(songs_df$artist_name %like% artist_name_temp)
}
songs_df <- as.data.frame(songs_df)
songs_df # return df
})
# search fuction
song_search <- function(s) {
if (is.null(s)) return(NULL)
if (is.null(s$track_id)) return(NULL)
# Isolate the given ID
songs_df <- isolate(songs())
temp_song <- songs_df[songs_df$track_id == s$track_id, ]
paste0("<b>", temp_song$artist_name, "</b><br>",
temp_song$year, "<br>",
"popularity ", format(temp_song$artist_popularity, big.mark = ",", scientific = FALSE)
)
}
# A reactive expression with the ggvis plot
vis <- reactive({
# setting variablex & variabley (input names are type str)
variablex <- prop("x", as.symbol(input$variablex))
variabley <- prop("y", as.symbol(input$variabley))
# Lables for axes
xvar_name <- names(axis_variables)[axis_variables == input$variablex]
yvar_name <- names(axis_variables)[axis_variables == input$variabley]
songs %>%
ggvis(x = variablex, y = variabley) %>%
layer_points(size := 50, size.hover := 200,
fillOpacity := 0.2, fillOpacity.hover := 0.5,
stroke = ~artist_popularity, key := ~artist_name) %>%
add_tooltip(song_search, "hover") %>%
add_axis("x", title = xvar_name) %>%
add_axis("y", title = yvar_name) %>%
add_legend("stroke", title = "Very Popular", values = c("Yes", "No")) %>%
scale_nominal("stroke", domain = c("Yes", "No"),
range = c("orange", "#aaa")) %>%
set_options(width = 500, height = 500)
})
vis %>% bind_shiny("plot1")
output$songs_selected <- renderText({ nrow(songs()) })
}
Ui.R
rm(list = ls())
library(tidyverse)
library(shiny)
library(ggplot2)
library(singer)
library(ggvis)
library(dplyr)
#axis_variables <- reactive({
axis_variables <- c(
"Length of Song (Seconds)" = "duration_rounded",
"Hotness Rating" = "artist_hotttnesss",
"Familiarity Rating" = "artist_familiarity",
"Year" = "year",
"Popularity Rating" = "artist_popularity"
)
# Define UI for application that draws a histogram
shinyUI(fluidPage(
shinythemes::themeSelector(),
titlePanel("Artist & Song Data"),
fluidRow(
column(3,
wellPanel(
h4("Filter By"),
# Slider Options for Data Exploration
sliderInput("duration_s", "Minimum duration of song (seconds)", 10, 500, 100, step = 10),
sliderInput("year_s", "Year released", 1900, 2018, value = c(1980, 2018)),
sliderInput("artist_hotttnesss_s", "Ranking / 10 for popularity", 0, 2, 0, step = 0.1),
sliderInput("artist_familiarity_s", "Ranking / 10 for familiarity", 0, 2, 0, step = 0.1),
sliderInput("artist_popularity", "Ranking / 10 for familiarity", 0, 2, 0, step = 0.1),
# Filter by custom input condition
textInput("city_in", "Name of the city"),
textInput("artist_name_in", "Artist's name contains (e.g Pink f)")
),
wellPanel(
selectInput("variablex", "X-axis", axis_variables, selected = "year"),
selectInput("variabley", "Y-axis", axis_variables, selected = "duration_rounded")
)
),
column(9,
ggvisOutput("plot1"),
wellPanel(
span("Degrees of Freedom",
textOutput("songs_selected")
)
)
)
)
It looks like you are filtering using data created by input$XXX. Try to put req(input$XXX, req(input$YYY, ...) at the beginning of your reactive element(s).
Also read this tweet about starting with rm(list = ls()).

R shiny chorpleth map

I am new in R. now I am creating shiny app. R can read my dataset. with the comand myData <- read.csv("myData.csv"). however shinyServer file cannot read my data. and list no observation.
Could you guys help me what is the problem?
The Shinyapp provides interactive visulization for production of raw material in the world since 1900 to 2010 for every 10 years.
Also I keep getting this error:
"ERROR: 'breaks' are not unique"
The Code is here:
shinyUI(fluidPage(
checkboxInput("type", "Please Select production type:",
c("Aluminium", "Gold",
"Iron", "Silver", "Zinc")
),
sliderInput("year","Choose a Year",
min = 1910,
max = 2010,
value= 2010),
checkboxInput("Economy", "Please Select Economy Factor:",
c("Income Inequallity", "labourers Real Wage", "GDP", "Inflation")),
plotOutput("thisPlot"),
leafletOutput("myMap")
)
)
shinyServer:
myData <- read.csv("myData.csv")
shinyServer<- function(input,output){
output$myMap <- renderLeaflet({
temp <- which(myData$type == input$type &
myData$year == input$year)
myData <- myData[temp,]
pal <- colorQuantile("YlGn", myData$production, n = 9)
country_popup <- paste0("<strong>Estado: </strong>", myData$Country)
leaflet(data = myData) %>%
setView(46.227638, 2.213749, zoom = 2) %>%
addTiles() %>%
addPolygons( lng = ~myData$Long, lat = ~myData$Lat,
fillColor = ~pal(myData$production),
fillOpacity = 0.8,
color = "#BDBDC3",
weight = 1,
popup = country_popup)
})
}
the data is:
Names = c("id",
"Country", "type", "year", "production", "GDP", "Income", "Inflation",
"Laborer", "Lat", "Long"), class = "data.frame", row.names = c(NA,
-10670L))
head(myData)
id Country type year production GDP Income Inflation Laborer Lat
Long
1 1 Guyana Gold 1910 0.000000 0 42.43048 0 154.45527 4.860416
-58.9301
it seems that it does read the data but it does not show it. and i have a problem with creating the choropleth map. which it does not work now in my shiny.
Yeah, leaflet is finicky. I didn't have to make a lot of changes, you almost had it. One of the main problems was that your filter was usually yielding an empty dataframe which caused the markers not to show (of course).
This empty dataframe problem is also the cause for the "ERROR: 'breaks' are not unique" message since colorQuantile is getting a null input for its domain argument, which means it is doing an empty quantile, and all the breaks are zero and thus "not unique". This can also happen with highly skewed data. You should avoid calling it in that case - maybe fallback on colorBin, although detecting that can be a bit complicated.
The following changes were made.
Added some fake data.
Changed addPolygons to addCircleMarkers as addPolygons is for adding arbitray shapes that you specify.
Changed your checkBoxInput to checkBoxGroupInput as you didn't want a checkbox, you wanted a group of them.
Changed the filter clause to use myData$type %in% input$type instead of myData$type == input$type as you probably wanted membership.
truncated the input$year value as it might not give back an integer, but your year values are definitely integers.
Changed the border color to "black" so you could see it on the circle.
Note that the popup does not come on hover, you have to click on the circle.
removed the myData on the marker input as you have specified it on the leaflet call.
commented out the plotOutput as I don't know what you want to plot.
Here is the code - this should get you started:
library(shiny)
library(leaflet)
# fake-up some data
n <- 10000
countrylist <- c("Guyana","Venezuela","Columbia")
typelist <- c("Aluminium", "Gold","Iron", "Silver", "Zinc")
types <- sample(typelist,n,replace=T)
cntrs <- sample(countrylist,n,replace=T)
lat <- 2.2 + 50*runif(n)
long <- -46 + 50*runif(n)
year <- sample(1910:2010,n,replace=T)
prd <- 100*runif(n)
myData <- data.frame(Country=cntrs,type=types,year=year,production=prd,Long=long,Lat=lat)
u <- shinyUI(fluidPage(
checkboxGroupInput("type", "Please Select production type:",
c("Aluminium", "Gold","Iron", "Silver", "Zinc"),
selected=c("Gold","Silver")
),
sliderInput("year","Choose a Year",
min = 1910,
max = 2010,
value= 2010),
checkboxGroupInput("Economy", "Please Select Economy Factor:",
c("Income Inequallity", "labourers Real Wage", "GDP", "Inflation")),
# plotOutput("thisPlot"),
leafletOutput("myMap")
)
)
s <- function(input,output){
output$myMap <- renderLeaflet({
temp <- which(myData$type %in% input$type &
myData$year == trunc(input$year))
print(nrow(myData))
myData <- myData[temp,]
print(nrow(myData))
pal <- colorQuantile("YlGn", myData$production, n = 9)
country_popup <- paste0("<strong>Estado: </strong>", myData$Country)
leaflet(data = myData) %>%
setView(-46.227638, 2.213749, zoom = 2) %>%
addTiles() %>%
addCircleMarkers( lng = ~Long, lat = ~Lat,
fillColor = ~pal(myData$production),
radius = 6, # pixels
fillOpacity = 0.8,
color = "black",
weight = 1,
popup = country_popup)
})
}
shinyApp(u,s)
And this is the result:

R Shiny: How do I use nearPoints on a geom_area or stacked geom_bar?

I'm trying to use hover tooltips on a geom_area, but I can't get them to work with that geometry. It only displays lowest set of grouped variables (in the example below, it will show 'Lakers' hover values, but not 'Celtics'.
Interestingly, if you replace the geom_area with, for example, geom_point, the code below works fine. But for the real dashboard I'm making, an area chart is necessary.
library("shiny")
library("ggplot2")
d <- data.frame(date = as.Date(c("2017-01-01", "2017-01-02", "2017-01-03",
"2017-01-01", "2017-01-02", "2017-01-03")),
team = c("Celtics", "Celtics", "Celtics",
"Lakers", "Lakers", "Lakers"),
points_scored = c(108, 89, 95, 78, 93, 82))
ui <- fluidPage(
mainPanel(
plotOutput("graph",
hover = hoverOpts("plot_hover", delay = 100, delayType = "debounce")),
uiOutput("hover_info")
)
)
server <- function(input, output) {
output$graph <- renderPlot({
ggplot(d, aes(x = date, y = points_scored, fill = team)) +
geom_area()
})
output$hover_info <- renderUI({
hover <- input$plot_hover
point <- nearPoints(d, hover, threshold = 5, maxpoints = 1, addDist = TRUE)
if (nrow(point) == 0) return(NULL)
wellPanel(
paste0(point$team, " - ", point$date, ": ", point$points_scored)
)
})
}
runApp(list(ui = ui, server = server))
Thanks in advance!
--- Edit ---
It's actually displaying the hover in the incorrect location. See the attached picture. It treats the point (Celtics on Jan 1) as if it's still at y = 108. I want it to hover at the top of the visible red bar (108 + 78 = 186), but still display 108.
I've found a sketchy workaround, but it makes the app do what I want it to do. My edited app only edits the server function, and goes something like this:
Continue to use the main dataframe 'd' to generate the graph. Continue to use the hover in plotOutput off of that graph
Create a workaround dataframe 'd_workaround' that is identical, except it contains 1) the actual y position of the points in a column with the same name as the y column in 'd' and the graph (points_scored. I wanted to name this 'position', but the app only worked if it had the same name as the y column in 'd') and 2) the 'real' value that I want my tooltip to display (points_scored_real)
Direct my nearPoints() to use d_workaround, and my tooltips to display points_scored_real from that column
The app looks like this:
library(shiny)
library(ggplot2)
library(dplyr)
library(tidyr)
library(stringr)
d <- data.frame(date = as.Date(c("2017-01-01", "2017-01-02", "2017-01-03",
"2017-01-01", "2017-01-02", "2017-01-03")),
team = c("Celtics", "Celtics", "Celtics",
"Lakers", "Lakers", "Lakers"),
points_scored = c(108, 89, 95, 78, 93, 82))
ui <- fluidPage(
mainPanel(
plotOutput("graph",
hover = hoverOpts("plot_hover", delay = 100, delayType = "debounce")),
uiOutput("hover_info")
)
)
server <- function(input, output) {
output$graph <- renderPlot({
ggplot(d, aes(x = date, y = points_scored, fill = team)) +
geom_area()
})
output$hover_info <- renderUI({
d_workaround <- d %>%
spread(team, points_scored) %>%
mutate(Celtics = str_c(Celtics + Lakers, "-", Celtics),
Lakers = str_c(Lakers, "-", Lakers)) %>%
gather(team, points_scored, Celtics, Lakers) %>%
separate(points_scored, c("points_scored", "points_scored_real"), convert = TRUE)
hover <- input$plot_hover
point <- nearPoints(d_workaround, hover, threshold = 10, maxpoints = 1, addDist = TRUE)
if (nrow(point) == 0) return(NULL)
wellPanel(
paste0(point$team, " - ", point$date, ": ", point$points_scored_real)
)
})
}
runApp(list(ui = ui, server = server))

Resources