ggvis Map & Tooltips - r

I am trying to layer on tooltips to a map of the US, but wherever I hover... it displays the same data. In addition, the data is wrong. I'm thinking that it is passing through the factor values and not the character value. I tried taking tips from the movie explorer example - http://shiny.rstudio.com/gallery/movie-explorer.html - but, it's not working as I hoped. Any hints or clues I should look into?
Update: I've determined that you can only pass through arguments that are being called into the ggvis function. So, if my tooltip function included region, long, & lat, all of them would appear in the tooltip. Since Population and Income do not appear anywhere in the function, it is not passing them through. I'm still lost on how to proceed, but any ideas would be awesome! :)
library(ggplot2)
library(shiny)
library(ggvis)
library(dplyr)
shinyApp(
ui = fluidPage(
#numericInput("n", "n", 1),
ggvisOutput("map")
),
server = function(input, output) {
statesData <- reactive({
states <- data.frame(state.x77)
states$region <- row.names(state.x77) %>% tolower
row.names(states) <- NULL
all_states <- map_data("state") %>%
mutate(region = tolower(region)) %>%
left_join(states)
all_states_unique <- all_states %>%
select(region, Population, Income, Illiteracy, Life.Exp, Murder, HS.Grad, Frost, Area) %>%
unique
states_tooltip <- function(x) {
if (is.null(x)) return(NULL)
if (is.null(x$region)) return(NULL)
# Pick out the movie with this ID
allStates <- isolate(all_states_unique)
state <- allStates[allStates$region == x$region, ]
paste0("<b>", state$region, "</b><br>",
state$Population, "<br>",
state$Income
)
}
all_states %>%
arrange(group, order) %>%
ggvis(x = ~long, y = ~lat) %>%
layer_paths(fill = ~region, stroke := .2) %>%
add_tooltip(states_tooltip, "hover")
})
statesData %>% bind_shiny('map')
}
)

Add an index to the dataframe you want to pull the tooltip data from:
state$id <- 1:nrow(state)
ggvis takes a "key" argument to facilitate this kind of tooltip:
ggvis(x = ~long, y = ~lat, key := ~id) %>%
I tried figuring out that movie example and didn't find it very helpful. This always works for me:
add_tooltip(function(x) {
row <- state[state$id == x$key,]
paste0("<b>", row[,"region"], "</b><br>",
row[,"Population"], "<br>",
row[,"Income"]
)})
As for the issue w/ the tooltip always coming up the same, I don't know for sure but think it's due to the order of your layers in the ggvis command. Had a similar problem where I had some polygons layered on top of a scatterplot. It kept trying to draw the tooltip for the polygons (which covered the whole chart) when what I wanted was the individual points to display the tooltip. By reversing their order in the ggvis command (ie layer_points() %>% layer_shapes()) I got it to work.

I realise this is quite late but for future reference and others that stumble across this page. If your dataframe has been converted using fortify and has the group variable then this may be equivalent to the State level. Group can then be used to filter for the tooltip as it is in the ggvis command. That then allowed me to gain access to other variables I wanted.
In my problem I couldn't use the key solution because I was creating the plot to react to numerous years. So to change what you have above states_tooltip would become:
states_tooltip <- function(x){
row <- allstates[allstates$group==x$group,] %>%
select(region, Population, Income) %>% unique
paste0("<b>", row[,"region"], "</b><br>",
row[,"Population"], "<br>",
row[,"Income"]
)})

Related

How can I get Leaflet to ignore NULL or empty objects

In the actual problem this variable is created by a script filtering the coordinates specified by the user, so sometimes variables return NULL. After specifying the coordinates I want to run the rest of the script without editing any part of it.
For simplicity I have used the breweries dataset to represent this.
##load required package
library(mapview)
library(leaflet)
##create variable with points
breweries_A <- breweries
##create variable with no points
breweries_B <- NULL
##create a leaflet plot
breweries_plot <- leaflet() %>%
addProviderTiles('CartoDB.Positron') %>%
addCircleMarkers(data = breweries_A) %>%
addCircleMarkers(data = breweries_B)
The result is an error because breweries B has no data.
Therefore it would be really helpful if there was a way to make leaflet ignore NULL objects, or dataframes with no rows?
You can add the data conditionally to the map:
breweries_plot <- leaflet() %>%
addProviderTiles('CartoDB.Positron')
if (!is.null(breweries_A))
breweries_plot <- breweries_plot %>% addCircleMarkers(data = breweries_A)
if (!is.null(breweries_B))
breweries_plot <- breweries_plot %>% addCircleMarkers(data = breweries_B)

ggvis barplot: negative values

I'm trying to draw a barplot using ggvis, for some data where for each variable I have both a negative and a positive value. It would be similar to this example from ggplot2.
However, when I try something similar in ggvis, I end up with basically no plot at all, just some weird lines.
Example data:
df <- data.frame(
direction=rep(c("up", "down"), each=3),
value=c(1:3, -c(1:3)),
x=rep(c("A", "B", "C"), 2))
This works, for all positive values:
df %>%
mutate(value.pos=abs(value)) %>%
ggvis(x=~x, y=~value.pos) %>%
group_by(direction) %>%
layer_bars(stack=TRUE)
This gives me nothing:
df %>%
ggvis(x=~x, y=~value) %>%
group_by(direction) %>%
layer_bars(stack=TRUE)
I've also tried various combinations of plotting them one by one, e.g.:
df %>%
spread(key=direction, value=value) %>%
ggvis(x=~x, y=~up) %>%
layer_bars() %>%
layer_bars(x=~x, y=~down)
So far, no luck. I suspect I'm missing some simple solution...
I don't ggvis lets you produce stacked bar plots with negative values within the same groups as positive data.
This is because if an x value appear more than once in the data, then ggvis will sum up the y values at each x. I had thought that since you plotted the vector 1:3, they canceled out, but that's not the case.
As of now, I do not believe that dodged bar plots exist for this. It also messes with the labels.
You can produce the plot non-stacked, while filling in the position.
df %>%
group_by(direction) %>%
ggvis(x=~x, y=~value, fill = ~direction) %>%
layer_bars(stack = FALSE)
Anyways, you might consider avoiding ggvis for any production work since it is under development, and hasn't been updated in a couple of months.
#shayaa
Thanks, this does seem to be working, although it will probably require some tweaking, and may not look as nicely as if I was using ggplot2. Actually, the reason I am using ggvis, is because I would like to combine it with shiny, to make a small interactive web version. For example:
df <- data.frame(
direction=rep(c("up", "down"), each=3),
value=c(1:3, -c(1:3)),
x=rep(c("A", "B", "C"), 2))
plot_fct <- function(letter) {
df %>%
filter(x==letter) %>%
ggvis(x=~x, y=~value, fill = ~direction) %>%
layer_bars(stack = FALSE) %>%
scale_numeric("y", domain=c(NA,NA))
}
ui <- fluidPage(
sidebarPanel(
selectInput("letter", "Choose letter", c("A", "B", "C"), selected="A")
),
mainPanel(
ggvisOutput("letter_barplot")
)
)
server <- function(input, output) {
plot_fct(letter=reactive(input$letter)) %>% bind_shiny("letter_barplot")
}
runApp(shinyApp(ui, server))
However, it does not seem to work for me anyway, since there is some issue with the reactive being of class character. I keep getting the error:
Error in eval(substitute(expr), envir, enclos) :
comparison (1) is possible only for atomic and list types
Guess I'll have to keep trying.

How to add tooltip with shares to ggvis histogram?

I would like to create an interactive histogram which gives information about the bins by hover. This thread gives answer to how to add tooltip with count numbers.
library("ggvis")
cocaine %>%
ggvis(x = ~weight) %>%
layer_histograms() %>%
add_tooltip(function(df) (paste("count:", df$stack_upr_ - df$stack_lwr_)))
How can I add the share of each bin as well? I should somehow add nrow(cocaine) to ggvis and create the shares from count but I did not succeed on how to achieve that (tried to take the suggestions of this post but apparently that solves a different problem).
You could do something like this I imagine:
cocaine %>%
ggvis(x = ~weight) %>%
layer_histograms() %>%
add_tooltip(function(df) paste("count:", df$stack_upr_, 'share:',
format(df$stack_upr_/nrow(cocaine), digits=2)))
This will show both the share and the bin number.
Also, as a side note you do not need df$stack_upr_ - df$stack_lwr_ because df$stack_lwr_ will be zero. Just df$stack_upr_ will do.

ggvis graphic with group selection

I want to use ggvis for data exploration (because I am familiar with ggplot2), and it would be of great help, due to many groups in my data sets, to be able to select and unselect groups to make different specific (data) comparisons.
set.seed(10)
dat <- data.frame(x=c(1:3,1:3),y=rnorm(6),groups=factor(rep(1:2,each=3)))
library(ggvis)
dat %>% ggvis(~x, ~y) %>% layer_points(fill=~groups)
# i know this example does not work - but is that possible somehow?
dat %>% ggvis(~x, ~y) %>% layer_points(fill=input_checkbox(~groups))
What I want at the end, is a graphic with which I can select a subset of groups by using radio buttons (for example).
Is there any way to do that?
Thank you!
From the documentation
Limitations
Currently, interactive inputs can only be used in two places:
as arguments to transforms: layer_smooths(span = input_slider(0, 1))
as properties: props(size = input_slider(10, 1000))
This means that interactive inputs can only modify the data, not the
underlying plot specification. In other words, with only basic
interactivity there’s no way to add or remove layers, or switch
between different datasets. This is a reasonable limitation because if
you’re doing exploration you can always create a new ggvis with R
code, or if you’re polishing a plot for presentation, you can embed it
in a Shiny app and gain full control over the plot.
For simple data exploration, one idea could be to use filter():
set.seed(10)
dat <- data.frame(x = c(1:5,1:5,1:5),
y = rnorm(15), groups = factor(rep(1:5,each=3)))
Note: I edited your initial dataset to illustrate the concept with more groups
library(dplyr)
library(ggvis)
dat %>% ggvis(~x, ~y) %>% layer_points(fill = ~groups)
You could pass the arguments (either manually directly in your R code or with your radio buttons in a Shiny app) to filter() to isolate specific groups:
dat %>%
filter(groups == 1 | groups == 3) %>%
ggvis(~x, ~y) %>% layer_points(fill = ~groups)

Leaflet package in R not plotting all coordinates

I'm trying to plot using leaflet with a somewhat sizable set of coordinates (~34K latitude/longitude pairs) however, using the code below it seems that leaflet is only plotting a small portion of these:
data <- read.csv("Food_inspections.csv", header = TRUE)
names(data) <- tolower(names(data))
data1 <- filter(data, risk == c("Risk 1 (High)","Risk 2 (Medium)","Risk 3 (Low)"))
data1$risk <- droplevels(data1$risk)
leaflet(data1) %>%
addTiles() %>%
addMarkers(lat = ~latitude, lng = ~longitude)
What I get back is a map like this:
This clearly does not contain all ~34K coordinates. Even if I use "addCircles" I get the same thing. Other mapping packages (RgoogleMaps for instance) seem to plot everything correctly. Does leaflet round the coordinates it takes as input before plotting because I could see that making several of the coordinates appear to overlap in the plot.
The points are there, you have to zoom in to see them. But... at least in my browser... anything more than 80 points or so, and it takes super long to zoom.
url <- "http://data.cityofchicago.org/api/views/4ijn-s7e5/rows.csv?accessType=DOWNLOAD"
data <- read.csv(url, header = TRUE) # takes a minute...
names(data) <- tolower(names(data))
data1 <- subset(data, risk %in% c("Risk 1 (High)","Risk 2 (Medium)","Risk 3 (Low)"))
data1$risk <- droplevels(data1$risk)
data1 <- data1[1:50,]
library(leaflet)
leaflet(data1) %>%
addTiles() %>%
addMarkers(lat = ~latitude, lng = ~longitude)

Resources