R Shiny: Tooltip in ggplot - r

I want the values of the height or weight to show when I hover over a point in the graph. I already tried to make this work by using the plotly package and the example of this link. But I got all kind of errors and I do not know how to make it work.
I've included my whole code so I hope someone can help me with this problem.
library("shiny")
library("ggplot2")
library('readxl')
library('gridExtra')
ui<- fluidPage(
titlePanel("Animals"),
sidebarLayout(
sidebarPanel(
helpText("Create graph of height and/or weight animals"),
selectInput("location",
label = "Choose a location",
choices = list("New York"="New York", "Philadelphia" = "Philadelphia"),
selected = "New York"),
uiOutput("animal"),
checkboxGroupInput("opti",
label = "Option",
choices = c("weight", "height"),
selected = "weight")
),
mainPanel(plotOutput("graph"))
))
server <- function(input, output){
animal <- read_excel('data/animals.xlsx', sheet =1)
var <- reactive({
switch(input$location,
"New York" = list("Cat1", "Dog2"),
"Philadelphia"= list("Cat4","Dog3"))
})
output$animal <- renderUI({
checkboxGroupInput("anim", "Choose an animal",
var())
})
output$graph <- renderPlot({
if (length(input$anim)==1){
p <- ggplot(subset(animal, Name %in% input$anim & Location %in% input$location), aes(x=date))
if ("weight" %in% input$opti){
p <- p + geom_line(aes(y=weight)) + geom_point(aes(y=weight))
}
if ("height" %in% input$opti){
p <- p + geom_line(aes(y=height)) + geom_point(aes(y=height))
}
print(p)
}
if (length(input$anim)==2){
p1 <- ggplot(subset(animal, Name %in% input$anim[1] & Location %in% input$location), aes(x=date))
p2 <- ggplot(subset(animal, Name %in% input$anim[2] & Location %in% input$location), aes(x=date))
if ("weight" %in% input$opti){
p1 <- p1 + geom_line(aes(y=weight)) + geom_point(aes(y=weight))
p2 <- p2 + geom_line(aes(y=weight)) + geom_point(aes(y=weight))
}
if ("height" %in% input$opti){
p1 <- p1 + geom_line(aes(y=height)) + geom_point(aes(y=height))
p2 <- p2 + geom_line(aes(y=height)) + geom_point(aes(y=height))
}
grid.arrange(p1,p2, ncol = 2)
}
})
}
shinyApp(ui=ui, server= server)
A part of the data:
Location Name date weight height
New York Cat1 Mar-16 34,20 22,50
New York Cat1 Apr-16 35,02 23,02
New York Cat1 May-16 35,86 23,55
New York Cat1 Jun-16 36,72 24,09
New York Dog2 Mar-16 33,55 22,96
New York Dog2 Apr-16 33,62 23,42
New York Dog2 May-16 33,68 23,89
New York Dog2 Jun-16 33,75 24,37
Philadelphia Cat4 Mar-16 20,33 16,87

I used this tooltip and customised it a little bit.
Your plots initially don't show up because you don't return any plot. I return an ggplot object p without calling print function.
In general, I heavily modified your code and this is the result:
As the function nearPoints needs the same dataset that you pass to ggplot, I had to create a new reactive, in which I did some subsetting and reshaping of your data.
Instead of grid.arrange to create two seperate plots I used facet_grid (and hence I had to transform the data). I also used colours to differentiate lines.
Everything works fine with the example data you provided.
Full example:
rm(ui)
rm(server)
library("shiny")
library("ggplot2")
library('readxl')
library('gridExtra')
library(reshape) # for "melt"
ui<- fluidPage(
titlePanel("Animals"),
sidebarLayout(
sidebarPanel(
helpText("Create graph of height and/or weight animals"),
selectInput("location",
label = "Choose a location",
choices = list("New York"="New York", "Philadelphia" = "Philadelphia"),
selected = "New York"),
uiOutput("animal"),
checkboxGroupInput("opti",
label = "Option",
choices = c("weight", "height"),
selected = "weight")
),
mainPanel(
# this is an extra div used ONLY to create positioned ancestor for tooltip
# we don't change its position
div(
style = "position:relative",
plotOutput("graph",
hover = hoverOpts("plot_hover", delay = 100, delayType = "debounce")),
uiOutput("hover_info")
)
)
))
server <- function(input, output){
animal <- read_excel('data/animals.xlsx', sheet =1)
#animal <- read_excel("~/Downloads/test2.xlsx")
var <- reactive({
switch(input$location,
"New York" = c("Cat1", "Dog2"),
"Philadelphia"= c("Cat4","Dog3"))
})
output$animal <- renderUI({
checkboxGroupInput("anim", "Choose an animal",
var())
})
output$graph <- renderPlot({
req(input$anim, sub())
if (length(input$anim) == 1) {
p <- ggplot(sub(), aes(x = date, colour = variable))
p <- p + geom_line(aes(y = value)) +
geom_point(aes(y = value)) +
guides(colour = guide_legend(title = NULL))
return(p) # you have to return the plot
}
if (length(input$anim) == 2) {
p <- ggplot(sub(), aes(x = date, colour = variable)) +
geom_line(aes(y = value)) +
geom_point(aes(y = value)) +
facet_grid(~ Name) +
guides(colour = guide_legend(title = NULL))
return(p) # you have to return the plot
}
})
observe({
print(sub())
})
sub <- reactive({
req(input$anim)
if (length(input$anim) == 1) {
df <- animal[animal$Name %in% input$anim & animal$Location %in% input$location, ]
df <- melt(as.data.frame(df), measure.vars = c("weight", "height"))
df <- subset(df, df$variable %in% input$opti)
return(df)
}
if (length(input$anim) == 2) {
df <- animal[animal$Name %in% input$anim & animal$Location %in% input$location, ]
df$Name <- factor(df$Name)
df <- melt(as.data.frame(df), measure.vars = c("weight", "height"))
df <- subset(df, df$variable %in% input$opti)
return(df)
}
})
output$hover_info <- renderUI({
hover <- input$plot_hover
point <- nearPoints(sub(), hover, threshold = 5, maxpoints = 1, addDist = TRUE)
if (nrow(point) == 0) return(NULL)
left_pct <- (hover$x - hover$domain$left) / (hover$domain$right - hover$domain$left)
top_pct <- (hover$domain$top - hover$y) / (hover$domain$top - hover$domain$bottom)
left_px <- hover$range$left + left_pct * (hover$range$right - hover$range$left)
top_px <- hover$range$top + top_pct * (hover$range$bottom - hover$range$top)
style <- paste0("position:absolute; z-index:100; background-color: rgba(245, 245, 245, 0.85); ",
"left:", left_px + 2, "px; top:", top_px + 2, "px;")
wellPanel(
style = style,
p(HTML(paste0("<b>", point$variable, ": </b>", point$value)))
)
})
}
shinyApp(ui = ui, server = server)

Related

Warning: Error in as.character: cannot coerce type 'environment' to vector of type 'character'

Why do I keep getting the error message: Warning: Error in as.character: cannot coerce type 'environment' to vector of type 'character'? I also updated later and httpuv, but they did not help. I wonder if the server has some functions. This is the code from 2014, and I am trying to reproduce it with updated data. Thank you!
Main server function
server = shinyServer(function(input, output){
# Session selector
Select_session <- reactive({
df <- session
# Search function
# TODO: change from "or" to "and"
if (length(input$keywords!=0)){
kwd_pattern <- gsub(",", "|", input$keywords)
df <- subset(df, grepl(kwd_pattern, df$descr, ignore.case = T))
}
# Date selector
if (!is.null(input$DateRange)){
df <- subset(df,
as.Date(df$date)>=input$DateRange[1] & as.Date(df$date)<=input$DateRange[2])
}
# Area of interest selector
if ("me" %in% input$IssueArea){
df <- subset(df, df$me==1)
}
if ("nu" %in% input$IssueArea){
df <- subset(df, df$nu==1)
}
if ("di" %in% input$IssueArea){
df <- subset(df, df$di==1)
}
if ("hr" %in% input$IssueArea){
df <- subset(df, df$hr==1)
}
if ("hr" %in% input$IssueArea){
df <- subset(df, df$hr==1)
}
if ("ec" %in% input$IssueArea){
df <- subset(df, df$ec==1)
}
if ("us" %in% input$IssueArea){
df <- subset(df, df$importantvote==1)
}
return(df)
})
# Session table output
output$sessionTable <- renderDataTable({
df <- Select_session()
if (length(input$keywords!=0)){
kwd_pattern <- gsub(",", "|", input$keywords)
df <- subset(df, grepl(kwd_pattern, df$descr, ignore.case = T))
}
# Vote title selector
if (!is.null(input$voteTitle)){
df <- subset(df, df$unres_title==input$voteTitle)
}
# Date selector
df <- subset(df,
as.Date(df$date)>=input$DateRange[1] & as.Date(df$date)<=input$DateRange[2])
# Select only following variables in data table and downloaded csv file
vars <- c("date","session","unres_title", "descr", "yes", "no", "abstain")
df <- df[,vars]
return(df)},
# Turn off searching function
# List length, 3 options: 5/25/all
# Page Length, default = 5
options = list(searching = FALSE,
lengthMenu = list(c(5, 25, -1), c('5', '25', 'All')),
pageLength = 5)
)
# Voting selector
Select_voting <- reactive({
df <- vote
# Link session data and vote data by rcid
if (length(Select_session()$rcid)!=0){
df <- subset(df, df$rcid %in% unique(Select_session()$rcid))
}
# Vote title selector
if (!is.null(input$voteTitle)){
df <- subset(df, df$unres_title==input$voteTitle)
}
return(df)
})
# Voting table output
output$votingTable <- renderDataTable({
df <- vote
# Select voting data based on rcid
df <- subset(df, df$rcid %in% unique(Select_voting()$rcid))
vars <- c("unres", "Country", "CABB", "Vote")
df <- df[,vars]
},
options = list(pageLength = 10)
)
# Session data downloader
output$downloadSession <- downloadHandler(
filename = "UN_Session.csv",
content = function(file){
vars <- c("session","unres_title", "date", "yes", "no", "abstain")
df <- Select_session()[,vars]
write.csv(df, file)
}
)
# Voting data downloader
output$downloadVoting <- downloadHandler(
filename = "UN_Voting.csv",
content = function(file){
vars <- c("unres", "Country", "CABB", "Vote")
df <- Select_voting()[,vars]
write.csv(df, file)
}
)
# Map visualization
output$map <- renderPlot({
if (length(unique(Select_voting()$rcid))==1){
# Load map color
color_for_map <- subset(colormatrix,
colormatrix$breaksvalue %in% unique(Select_voting()$vote))
# Main function to visualize map
ggplot()+
# Base map, fill=white, line=gray
geom_map(data=World.points,
map = World.points,
aes(map_id=region),
fill="#ecf0f1", color="white")+
# Vote map, fill based on vote, line = white
geom_map(data=Select_voting(),
map = World.points,
aes(map_id=region,
fill = as.character(vote)),
color="white")+
# Expand axis
expand_limits(x = world_map$long, y = world_map$lat)+
# Change fill color based on color matrix file
scale_fill_manual(
values=color_for_map$colors,
name="Vote",
breaks=color_for_map$breaksvalue,
labels=color_for_map$breakslabel)+
# Stephen Few plot theme, require(ggthemes)
theme_few()+
# No axis line, axis text, axis title
theme(axis.line=element_blank(),
axis.text.x=element_blank(),
axis.text.y=element_blank(),
axis.ticks=element_blank(),
axis.title.x=element_blank(),
axis.title.y=element_blank(),
#legend.position="none",
panel.background=element_blank(),
panel.border=element_blank(),
panel.grid.major=element_blank(),
panel.grid.minor=element_blank(),
plot.background=element_blank())
}
# Map without vote title selection
else if (length(input$voteTitle)==0){
ggplot()+
geom_map(data=World.points,
map = World.points,
aes(map_id=region),
fill="#ecf0f1",
color="white")+
expand_limits(x = world_map$long, y = world_map$lat)+
theme_few()+
geom_text(aes(x = mean(world_map$long),
y = mean(world_map$lat)),
label="Select the vote title to view map",
size = 10, colour = "#3498db")+
theme(axis.line=element_blank(),
axis.text.x=element_blank(),
axis.text.y=element_blank(),
axis.ticks=element_blank(),
axis.title.x=element_blank(),
axis.title.y=element_blank(),
legend.position="none",
panel.background=element_blank(),
panel.border=element_blank(),
panel.grid.major=element_blank(),
panel.grid.minor=element_blank(),
plot.background=element_blank())
}
# Map without voting data
else{
ggplot() +
geom_map(data=World.points, map = World.points, aes(map_id=region), fill="#ecf0f1", color="white") +
expand_limits(x = world_map$long, y = world_map$lat)+
theme_few()+
geom_text(aes(x = mean(world_map$long), y = mean(world_map$lat)), label="VOTING DATA UNAVAILABLE", size = 10, colour = "#3498db")+
theme(axis.line=element_blank(),axis.text.x=element_blank(),
axis.text.y=element_blank(),axis.ticks=element_blank(),
axis.title.x=element_blank(),
axis.title.y=element_blank(),legend.position="none",
panel.background=element_blank(),panel.border=element_blank(),panel.grid.major=element_blank(),
panel.grid.minor=element_blank(),plot.background=element_blank())
}
}, height = 400, width = 800)
# Title selection
output$TitleSelectUI <- renderUI({
selectizeInput("voteTitle", "Select the vote title",
choices = Select_session()$unres_title,
multiple = T,
options = list(maxItems = 1))
})
# Official document link
official_doc_link <- reactive({
df <- Select_session()
if (!is.null(input$voteTitle)){
df <- subset(df, df$unres_title==input$voteTitle)
if (df$session>30){
# UN official document URL
url_string <- paste("http://www.un.org/en/ga/search/view_doc.asp?symbol=%20A/RES/",
gsub("\\D", "",strsplit(df$unres[1], split = "/")[[1]][2]),
"/",
gsub("\\D", "",strsplit(df$unres[1], split = "/")[[1]][3]),
sep = "")
}
else {url_string = NULL}
}
else {
url_string = NULL
}
return(url_string)
})
# Official document hyperlink
output$OfficialDoc <- renderUI({
h5(a("Click to view official document at un.org", href = official_doc_link(), target="_blank"))
})
})

Shiny app: Download data source outside of renderPlot for quicker user manipulation

This is my first shiny app. I would like for the user to be able to update the number of facet columns and the dimensions of downloaded plot. readNWISuv, the function to download data can take a long time if multiple years are queried. Currently, the app downloads the data each time the user wants to change the plot format or plot dimensions. Not sure if I need to use reactiveValues, but I would assume that I want the data to be downloaded and manipulated outside of renderPlot. Thanks!
library(shiny)
library(dataRetrieval)
library(lubridate)
library(tidyverse)
library(plotly)
#flow wrecker
ui <- pageWithSidebar( #fluidPage(
# Application title
titlePanel("Flow Record"),
# Sidebar with a date input
#sidebarLayout
sidebarPanel(
dateRangeInput("daterange", "Date range: (yyyy-mm-dd)",
start = Sys.Date()-10,
min = "1980-10-01"),
textInput("gage", "USGS Gage #", "11532500"),
#actionButton("dload","Download data"),
selectInput("facet_x", "Facet Column #:", 2, choices =1:4),
submitButton("Update View", icon("refresh")),
helpText("When you click the button above, you should see",
"the output below update to reflect the values you",
"entered above:"),
#verbatimTextOutput("value"),
downloadButton('downloadImage', 'Download figure'),
numericInput("fig_x", "Fig. Dim. x:", 10, min = 3, max = 16),
numericInput("fig_y", "Fig. Dim. y:", 10, min = 3, max = 16),
width = 3
),
# Show a plot of the generated WY
mainPanel(
plotlyOutput("WYfacet")
)
)
# Define server draw WY facets
server <- function(input, output) {
parameterCd <- "00060" # discharge
#water year
wtr_yr <- function(dates, start_month=10) {
# Convert dates into POSIXlt
dates.posix = as.POSIXlt(dates)
# Year offset
offset = ifelse(dates.posix$mon >= start_month - 1, 1, 0)
# Water year
adj.year = dates.posix$year + 1900 + offset
# Return the water year
adj.year
}
output$WYfacet <- renderPlotly({
#progress bar
withProgress(readNWISuv(input$gage, parameterCd, input$daterange[1], input$daterange[2],tz="America/Los_Angeles") %>% addWaterYear,
message = 'Download in progress',
detail = 'This may take a while...', value = 1)
#download
temperatureAndFlow <- readNWISuv(input$gage, parameterCd, input$daterange[1], input$daterange[2],tz="America/Los_Angeles") %>% addWaterYear
names(temperatureAndFlow)<-c("agc","site","date","WY", "flow","a","tzone")
temperatureAndFlow$commonDate <- as.Date(format(temperatureAndFlow$date, format="2000-%m-%d"))
tf.df<-temperatureAndFlow %>%
filter(WY<=max(WY) & WY>=if_else(month(min(date))<10,min(WY)+1,min(WY)))
tf.df$date.d<-format(tf.df$date, format="%Y-%m-%d")
#mutate commonDate
df4 <- tf.df %>%
mutate(WY=factor(wtr_yr(date.d))) %>%
#seq along dates starting with the beginning of your water year
mutate(commonDate=as.Date(paste0(ifelse(month(date.d) < 10, "2001", "2000"),
"-", month(date.d), "-", day(date.d))), Date=date.d)
#plot
ploty<-ggplot(data = df4,mapping = aes(x = commonDate, y = flow,label=Date, colour = factor(WY))) +
geom_line() +
labs(x = " ", y = "Discharge (cfs)") +
facet_wrap(facets = ~WY,ncol=as.integer(input$facet_x)) +
scale_y_log_eng()+
annotation_logticks(sides = "l")+
theme_bw()+
theme(panel.grid.minor.x = element_blank())+
scale_x_date(labels = function(x) format(x, "%b"),date_breaks = "1 months")+
guides(colour=FALSE)
ggplotly(ploty, tooltip=c("flow","Date"))
})
#fig dimensions
output$fig_x <- renderText({ input$fig_x })
output$fig_y <- renderText({ input$fig_y })
#facet columns
output$facet_x <- renderText({ input$facet_x })
#download to computer
output$downloadImage <- downloadHandler(
filename = function(){paste("plot",'.png',sep='')},
content = function(file){
ggsave(file,width = input$fig_x,height = input$fig_y, dpi = 600, units = "in", device='png')
print(ggplot(data = df4,mapping = aes(x = commonDate, y = flow, colour = factor(WY))) +
geom_line() +
#geom_point()+
#geom_vline(data = trip,aes(xintercept=commonDate),trip_df,color="black")+
labs(x = " ", y = "Discharge (cfs)") +
facet_wrap(facets = ~WY,ncol=as.integer(input$facet_x)) +
scale_y_log_eng()+
annotation_logticks(sides = "l")+
theme_bw()+
theme(panel.grid.minor.x = element_blank())+
scale_x_date(labels = function(x) format(x, "%b"),date_breaks = "1 months")+
guides(colour=FALSE))
})
}
# Run the application
shinyApp(ui = ui, server = server)
There are a few changes to make to your sever section to make this work. Primarily:
splitting the creation of the dataframe into a new eventReactive function, dependent on an actionButton.
referring to the function inside the renderPlotly call
Try this:
## Within ui function call ############################################
# submitButton("Update View", icon("refresh")), # line to replace
actionButton(inputId = "update", "Update View", icon("refresh")),
## (if you want to keep a button to control when data is downloaded ##
server <- function(input, output) {
parameterCd <- "00060" # discharge
#water year
wtr_yr <- function(dates, start_month=10) {
# Convert dates into POSIXlt
dates.posix = as.POSIXlt(dates)
# Year offset
offset = ifelse(dates.posix$mon >= start_month - 1, 1, 0)
# Water year
adj.year = dates.posix$year + 1900 + offset
# Return the water year
adj.year
}
# New part here - use `reactive` to make df4 a new thing, which is processed separately. The `eventReactive` function waits till it sees the button pressed.
df4 <- eventReactive(input$update, ignoreNULL = FALSE, {
#progress bar
withProgress(readNWISuv(input$gage, parameterCd, input$daterange[1], input$daterange[2],tz="America/Los_Angeles") %>% addWaterYear,
message = 'Download in progress',
detail = 'This may take a while...', value = 1)
#download
temperatureAndFlow <- readNWISuv(input$gage, parameterCd, input$daterange[1], input$daterange[2],tz="America/Los_Angeles") %>% addWaterYear
names(temperatureAndFlow)<-c("agc","site","date","WY", "flow","a","tzone")
temperatureAndFlow$commonDate <- as.Date(format(temperatureAndFlow$date, format="2000-%m-%d"))
tf.df<-temperatureAndFlow %>%
filter(WY<=max(WY) & WY>=if_else(month(min(date))<10,min(WY)+1,min(WY)))
tf.df$date.d<-format(tf.df$date, format="%Y-%m-%d")
#mutate commonDate
tf.df %>%
mutate(WY=factor(wtr_yr(date.d))) %>%
#seq along dates starting with the beginning of your water year
mutate(commonDate=as.Date(paste0(ifelse(month(date.d) < 10, "2001", "2000"),
"-", month(date.d), "-", day(date.d))), Date=date.d)
})
output$WYfacet <- renderPlotly({
# req will pause plot loading till new data downloaded above, but changes to display will render without new download
req(df4())
#plot
ploty<-ggplot(data = df4(), # Put brackets here to refer to df4 as a reactive input!!!
mapping = aes(x = commonDate, y = flow, label=Date, colour = factor(WY))) +
geom_line() +
labs(x = " ", y = "Discharge (cfs)") +
facet_wrap(facets = ~WY,ncol=as.integer(input$facet_x)) +
scale_y_log10()+
# annotation_logticks(sides = "l")+
theme_bw()+
theme(panel.grid.minor.x = element_blank())+
scale_x_date(labels = function(x) format(x, "%b"),date_breaks = "1 months")+
guides(colour=FALSE)
ggplotly(ploty, tooltip=c("flow","Date"))
})
#fig dimensions
output$fig_x <- renderText({ input$fig_x })
output$fig_y <- renderText({ input$fig_y })
#facet columns
output$facet_x <- renderText({ input$facet_x })
#download to computer
output$downloadImage <- downloadHandler(
filename = function(){paste("plot",'.png',sep='')},
content = function(file){
ggsave(file,width = input$fig_x,height = input$fig_y, dpi = 600, units = "in", device='png')
print(ggplot(data = df4() ,mapping = aes(x = commonDate, y = flow, colour = factor(WY))) +
geom_line() +
#geom_point()+
#geom_vline(data = trip,aes(xintercept=commonDate),trip_df,color="black")+
labs(x = " ", y = "Discharge (cfs)") +
facet_wrap(facets = ~WY,ncol=as.integer(input$facet_x)) +
scale_y_log10()+
annotation_logticks(sides = "l")+
theme_bw()+
theme(panel.grid.minor.x = element_blank())+
scale_x_date(labels = function(x) format(x, "%b"),date_breaks = "1 months")+
guides(colour=FALSE))
})
}

multiple selection in checkboxGroupInput and plotting in shiny

In my shiny app I have a checkboxGroupInput
How should I do the plot command in server function, in a way that I plot the TurbInt_mean against MeanWindSpeed_mean and add lines (curves) to the plot by user selection ?
I have tried to summaries my shiny app as reproduce-able code as follow (you have to first load the sample data that I have provided)
library(shiny)
ui <- fluidPage(
checkboxGroupInput("variable", "Select IEC Classes for TI",c("A Plus" = "ap","A" = "a","B" = "b","C"="c")),
plotOutput("plotmeanTI",width = "100%") )
server <- function(input, output, session){
output$plotmeanTI <- renderPlot({
plot(as.matrix(TI_plot[,1]),as.matrix(TI_plot[,2]),t='o',ylim=c(0,1),xaxs="i",
xlab="Mean Wind Speed", ylab="<TI>")
if(input$variable=="ap"){lines(as.matrix(TI_plot[,1]),TI_plot$NTM_A_Plus_mean,col=6)}
if(input$variable=="a"){lines(as.matrix(TI_plot[,1]),TI_plot$NTM_A_mean,col=2)}
if(input$variable=="b"){lines(as.matrix(TI_plot[,1]),TI_plot$NTM_B_mean,col=3)}
if(input$variable=="c"){lines(as.matrix(TI_plot[,1]),TI_plot$NTM_C_mean,col=4)}
})
}
shinyApp(ui=ui,server=server)
If user select 1, one curve should be added, if select more than one, I want to have multiple curves added to my plot.I can do it for single selection like I have explained in my code, but when I have multi selection it does not work.
My data set looks like :
dput(TI_plot)
structure(list(MeanWindSpeed_mean = c(0.292023070097604, 1.12011882699226,
2.0283906614786, 3.00947886508396, 4.01428066037736, 5.01250749719984,
6.0080377166157, 7.00777409860191, 8.0049941822883, 9.00201938353988,
9.99646762244478, 10.9883558855227, 11.9798700705476, 12.976996101646,
13.9653724394786, 14.9495068163593, 15.9628459343795, 16.9708685581934,
17.9623943661972, 18.992621231979, 19.9643220338983, 20.9834693877551,
22.0170278637771, 22.9658904109589, 24.0025266903915, 24.9935025380711
), TurbInt_mean = c(3.02705430346051, 0.420402191213343, 0.264195029831388,
0.215109260166585, 0.18794121258946, 0.16699392997796, 0.148261539245668,
0.134479958525654, 0.122038442146089, 0.110595865904036, 0.097103704211826,
0.0836329541372291, 0.0708397249149876, 0.0622491842333237, 0.0591184473929236,
0.0611678829190056, 0.0652080242510699, 0.0690131441806601, 0.073762588028169,
0.0756961992136304, 0.0805696610169492, 0.0817446428571429, 0.0830263157894737,
0.0827277397260274, 0.0749537366548043, 0.0765532994923858),
NTM_A_Plus_mean = c(Inf, 1.10260388189292, 0.642329939163608,
0.473065816856713, 0.387417559923049, 0.336769624752903,
0.303163441845455, 0.27908457313955, 0.261084722917897, 0.247090026094941,
0.235918715179959, 0.226796351934008, 0.219190019655214,
0.212713243118379, 0.20720881268079, 0.202452008587075, 0.19816685602934,
0.19441329542209, 0.191131377464549, 0.188086340606011, 0.185500707351721,
0.18304730715887, 0.180790073836667, 0.178898058874634, 0.177002145398197,
0.175335040729601), NTM_A_mean = c(Inf, 0.98009233946037,
0.570959945923208, 0.420502948317078, 0.344371164376044,
0.299350777558136, 0.269478614973738, 0.248075176124045,
0.232075309260353, 0.219635578751059, 0.209705524604408,
0.201596757274674, 0.194835573026857, 0.189078438327448,
0.184185611271814, 0.179957340966289, 0.176148316470525,
0.172811818152969, 0.169894557746266, 0.167187858316455,
0.164889517645975, 0.162708717474551, 0.160702287854815,
0.159020496777452, 0.157335240353953, 0.155853369537423),
NTM_B_mean = c(Inf, 0.857580797027824, 0.499589952682807,
0.367940079777444, 0.301324768829038, 0.261931930363369,
0.23579378810202, 0.217065779108539, 0.203065895602809, 0.192181131407176,
0.183492334028857, 0.176397162615339, 0.1704811263985, 0.165443633536517,
0.161162409862837, 0.157462673345503, 0.154129776911709,
0.151210340883848, 0.148657738027983, 0.146289376026898,
0.144278327940228, 0.142370127790232, 0.140614501872963,
0.139142934680271, 0.137668335309708, 0.136371698345246),
NTM_C_mean = c(Inf, 0.735069254595278, 0.428219959442406,
0.315377211237809, 0.258278373282033, 0.224513083168602,
0.202108961230303, 0.186056382093034, 0.174056481945265,
0.164726684063294, 0.157279143453306, 0.151197567956005,
0.146126679770143, 0.141808828745586, 0.13813920845386, 0.134968005724717,
0.132111237352894, 0.129608863614727, 0.127420918309699,
0.125390893737341, 0.123667138234481, 0.122031538105913,
0.120526715891111, 0.119265372583089, 0.118001430265464,
0.116890027153068)), class = c("tbl_df", "tbl", "data.frame"
), row.names = c(NA, -26L), .Names = c("MeanWindSpeed_mean",
"TurbInt_mean", "NTM_A_Plus_mean", "NTM_A_mean", "NTM_B_mean",
"NTM_C_mean"))
the head of TI_plot is like :
head(TI_plot)
# A tibble: 6 x 6
MeanWindSpeed_mean TurbInt_mean NTM_A_Plus_mean NTM_A_mean NTM_B_mean NTM_C_mean
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 0.2920231 3.0270543 Inf Inf Inf Inf
2 1.1201188 0.4204022 1.1026039 0.9800923 0.8575808 0.7350693
3 2.0283907 0.2641950 0.6423299 0.5709599 0.4995900 0.4282200
4 3.0094789 0.2151093 0.4730658 0.4205029 0.3679401 0.3153772
5 4.0142807 0.1879412 0.3874176 0.3443712 0.3013248 0.2582784
6 5.0125075 0.1669939 0.3367696 0.2993508 0.2619319 0.2245131
We could use switch
library(shiny)
ui <- fluidPage(
checkboxGroupInput("variable", "Select IEC Classes for TI",c("A Plus" = "ap","A" = "a","B" = "b","C"="c"),
selected = c("A Plus" = "ap")),
plotOutput("plotmeanTI",width = "100%")
)
server <- function(input, output, session){
output$plotmeanTI <- renderPlot({
f1 <- function(nm1){
switch(nm1,
ap = lines(TI_plot[[1]],TI_plot$NTM_A_Plus_mean,col=6),
a = lines(TI_plot[[1]],TI_plot$NTM_A_mean,col=2),
b = lines(TI_plot[[1]],TI_plot$NTM_B_mean,col=3),
c = lines(TI_plot[[1]],TI_plot$NTM_C_mean,col=4)
)
}
if(is.null(input$variable)) {
plot(TI_plot[[1]], TI_plot[[2]],t='o',ylim=c(0,1),xaxs="i",
xlab="Mean Wind Speed", ylab="<TI>")
} else {
plot(TI_plot[[1]], TI_plot[[2]],t='o',ylim=c(0,1),xaxs="i",
xlab="Mean Wind Speed", ylab="<TI>")
f1(input$variable)
}
})
}
shinyApp(ui=ui,server=server)
-output
Using ggplot2
library(shiny)
library(ggplot2)
library(tidyr)
library(dplyr)
ui <- fluidPage(
checkboxGroupInput("variable", "Select IEC Classes for TI",c("A Plus" = "ap","A" = "a","B" = "b","C"="c"),
selected = c("A Plus" = "ap")),
plotOutput("plotmeanTI",width = "100%") )
server <- function(input, output, session){
output$plotmeanTI <- renderPlot({
keyvaldata <- data.frame(key = c('NTM_A_Plus_mean', 'NTM_A_mean', 'NTM_B_mean', 'NTM_C_mean' ),
Var = c('ap', 'a', 'b', 'c'), stringsAsFactors = FALSE)
p1 <- gather(TI_plot, key, val, -MeanWindSpeed_mean, -TurbInt_mean) %>%
left_join(., keyvaldata) %>%
filter(Var %in% input$variable) %>%
ggplot(., aes(MeanWindSpeed_mean, TurbInt_mean, colour = Var)) +
geom_line() +
geom_line(aes(y =val)) +
labs(x = "Mean Wind Speed", y = "<TI>") +
theme_bw()
if(is.null(input$variable)) {
ggplot(TI_plot, aes(MeanWindSpeed_mean, TurbInt_mean)) +
geom_line() +
labs(x = "Mean Wind Speed", y = "<TI>") +
theme_bw()
} else {
p1
}
})
}
shinyApp(ui=ui,server=server)
-output

How to hover over ggplot with transformed values in shiny

I want to display some of the data in tooltip when hovering on the plot in shiny. I have used this script, and the data is showing nicely when I use the variables as they are (p and min_p). However what I really need is to display a log-transformed p and min_p, so my ggplot would be the following:
ggplot(dataset, aes(x = -log10(p), y = -log10(min_p))) +
geom_point()
And that's the problem, because hover_info does not recognize the data anymore, and I get the following error:
Error: replacement table has 0 rows, replaced table has 20
I am not sure how this can be fixed, and I admit I don't fully understand how the hovering works.
Here is the code with a sample data:
library(shiny)
library(shinydashboard)
library(ggplot2)
sidebar <- dashboardSidebar(
sidebarMenu(
menuItem("Plot result", tabName = "scatterplot", icon = icon("area-chart"))
))
body <- dashboardBody(
tabItems(
tabItem(tabName = "scatterplot",
fluidRow(
box(
uiOutput("scatterPlotButton"),
width = 5
),
box(
title="PLOT",solidHeader = TRUE, status="primary",
plotOutput("plot",
hover = hoverOpts("plot_hover", delay = 100, delayType = "debounce")),
uiOutput("hover_info"),
width=9
)
)
)
)
)
ui=dashboardPage(
dashboardHeader(title = "analysis"),
sidebar,
body
)
server=shinyServer(function(input, output, session) {
dataset <- structure(list(p = c(6.03934743495282e-02, 1.50433174696588e-01,
2.08047037184403e-03, 5.89297106629446e-05, 0.000102485231497565,
0.0010651774924444, 0.0126458836222225, 0.000210364148948929,
0.00274720409905674, 0.281095738489031, 0.000316170681574214,
0.0316321461125659, 0.000369171267912158, 0.000369171267912158,
0.0395213746526263, 0.475174078010843, 0.000718770258398781,
0.760859052164441, 0.000810153915789446, 0.000875314011490406),
ratio_p_group_min = c(1.57380553778931, 1.11245772000324,
1.504084996599, 1.00963266560562, 1.28098052443163, 1.49882201127675,
1.10761702001084, 0.767267328293303, 1.03412495601202, 1.33508933929913,
0.835478202626155, 0.998537147454481, 1.2008830437325, 1.2008830437325,
1.15710746065582, 0.99677375722945, 1.37744067975694, 1.3666109673056,
1.34583027836758, 1.34766012381264),
min_p = c(0.15789, 0.25772, 0.56599, 0.99632, 0.00004, 0.00275, 0.10761,
0.76726, 0.00103, 0.00013, 0.83547, 0.99853, 0.00120, 0.12008,
0.01157, 0.99677, 0.01377, 0.13666, 0.14583, 0.01347),
genes = c("Gene1", "Gene2", "Gene3", "Gene4", "Gene5", "Gene6", "Gene7",
"Gene8", "Gene9", "Gene10", "Gene11", "Gene12", "Gene13", "Gene14",
"Gene15", "Gene16", "Gene17", "Gene18", "Gene19", "Gene20")),
.Names = c("p", "ratio_p_group_min","min_p","genes"),
row.names = c(NA, 20L), class = "data.frame")
output$scatterPlotButton <- renderUI({
actionButton("scatterPlotButton", "Generate Plot", class="btn-block btn-primary")
})
scatterPlot <- eventReactive(input$scatterPlotButton,{
if (is.null(input$scatterPlotButton)) return()
dataset <- dataset[which(round(dataset$ratio_p_group_min,digits=2)>=0 & round(-log10(dataset$p),digits=2)>=0 & !is.na(dataset$ratio_p_group_min)),]
dataset$ratio_p_group_min=ifelse(dataset$ratio_p_group_min>2 & dataset$p>0.05,1,dataset$ratio_p_group_min)
ggplot(dataset, aes(x = -log10(p), y = -log10(min_p))) +
geom_point()
})
output$plot <- renderPlot({ scatterPlot() })
output$hover_info <- renderUI({
if (is.null(input$scatterPlotButton)) return()
dataset <- dataset[which(round(dataset$ratio_p_group_min,digits=2)>=0 & round(-log10(dataset$p),digits=2)>=0 & !is.na(dataset$ratio_p_group_min)),]
hover <- input$plot_hover
point <- nearPoints(dataset, hover, threshold = 5, maxpoints = 1, addDist = TRUE)
if (nrow(point) == 0) return(NULL)
left_pct <- (hover$x - hover$domain$left) / (hover$domain$right - hover$domain$left)
top_pct <- (hover$domain$top - hover$y) / (hover$domain$top - hover$domain$bottom)
left_px <- hover$range$left + left_pct * (hover$range$right - hover$range$left)
top_px <- hover$range$top + top_pct * (hover$range$bottom - hover$range$top)
style <- paste0("position:absolute; z-index:100; background-color: rgba(245, 245, 245, 0.85); ",
"left:", left_px + 2, "px; top:", top_px + 2, "px;")
wellPanel(
style = style,
p(HTML(paste0(point)))
)
})
})
shinyApp(ui=ui, server=server)
UPDATE
I have found a not so elegant solution: create new variables in dataset for -log10(p) and -log10(min_p) and use these new variables in ggplot.
dataset$LogP = -log10(dataset$p)
dataset$LogMinP = -log10(dataset$min_p)
ggplot(dataset, aes(x = LogP, y = LogMinP)) +
geom_point()
But I am still wondering if this could have been avoided somehow.
You could also use the plotly package. Simply call ggploty() after your ggplot object.

Delay update to R Shiny multiple-plot app

I'm trying to speed up an R Shiny app I'm building to explore a set of data. The app displays sentences for some of the data and a series of bar charts for other data. Each of these is rendered separately.
Every time I click one of the checkboxes, however, to filter the data, the whole thing re-renders and this takes about a second to complete. How can I isolate the rendering of all of the charts until a "go" button is clicked? I've tried a few other suggestions on SO but haven't found out how to do it with multiple renderPlots.
Sorry for the mess of code. I didn't want to shorten it too much or I'll lose some of the context.
library(ggplot2)
d <- read.csv("dm_survey.csv")
server <- function(input, output) {
output$surveyPlot1 <- renderPlot({
d <- d[d$"Frequency of Games" %in% c(input$frequency),]
d <- d[d$"Length of Games" %in% c(input$length),]
d <- d[d$"Primary Locations" %in% c(input$locations),]
d <- d[d$"Campaign Worlds" %in% c(input$worlds),]
d <- d[d$"Adventures" %in% c(input$adventures),]
d <- d[d$"Preferred Combat Type" %in% c(input$combat),]
d <- d[d$"Preparation Time" %in% c(input$preptime),]
output$textmain <- renderUI(HTML("<h1>2016 D&D Dungeon Master Survey</h1>"))
table_columns <- c("Campaign Worlds", "Primary Locations",
"Adventures",
"Preferred Combat Type")
total_sentences <- c()
for (table_column in table_columns) {
num_respondents <- nrow(d[table_column])
question_title <- tolower(table_column)
sentence <- paste("Of", num_respondents, "respondents on", question_title, collapse = "")
tbl <- data.frame(sort(table(d[table_column]),decreasing = TRUE))
if (nrow(tbl) == 1) {
tbl <- data.frame("Activity" = d[table_column][1,], "Count" = nrow(d),"Freq" = 100)
print(tbl)
} else {
tbl["Percentage"] <- round(tbl["Freq"] / colSums(tbl["Freq"]) * 100, 0)
}
for(i in 1:nrow(tbl)) {
answer_title <- tolower(as.character(tbl[i,1]))
answer_percentage <- tbl[i,3]
sentence <- paste(sentence, ", ", answer_percentage, "% answered ", answer_title, collapse="", sep = '')
}
sentence <- paste(sentence, ".", collapse="", sep = '')
total_sentences <- c(total_sentences, sentence)
}
output$text1 <- renderUI(HTML(paste(total_sentences[1],"<br/><br/>")))
output$text2 <- renderUI(HTML(paste(total_sentences[2],"<br/><br/>")))
output$text3 <- renderUI(HTML(paste(total_sentences[3],"<br/><br/>")))
output$text4 <- renderUI(HTML(paste(total_sentences[4],"<br/><br/>")))
column_name <- "Frequency of Games"
factor_labels <- c("Less than monthly","Monthly","Twice monthly","Weekly","Twice a week","More than twice weekly")
d[,column_name] <- factor(d[,column_name], levels = factor_labels)
p1 <- ggplot(d, aes(factor(d[,column_name])))
p1 + geom_bar() + coord_flip() + theme_minimal() +
scale_y_continuous(expand=c(.1, 0)) +
labs(x = "",
title = column_name,
y=paste("Number of Respondants out of",nrow(d))) +
geom_text(aes(label = scales::percent((..count..)/sum(..count..))),
stat= "count", hjust=-.1)
})
output$surveyPlot2 <- renderPlot({
d <- d[d$"Frequency of Games" %in% c(input$frequency),]
d <- d[d$"Length of Games" %in% c(input$length),]
d <- d[d$"Primary Locations" %in% c(input$locations),]
d <- d[d$"Campaign Worlds" %in% c(input$worlds),]
d <- d[d$"Adventures" %in% c(input$adventures),]
d <- d[d$"Preferred Combat Type" %in% c(input$combat),]
d <- d[d$"Preparation Time" %in% c(input$preptime),]
column_name <- "Length of Games"
factor_labels <- c("Longer than eight hours","About eight hours","About six hours","About four hours","About three hours","About two hours","About an hour")
d[,column_name] <- factor(d[,column_name], levels = factor_labels)
p2 <- ggplot(d, aes(factor(d[,column_name])))
p2 + geom_bar() + coord_flip() + theme_minimal() +
scale_y_continuous(expand=c(.1, 0)) +
labs(x = "",
title = column_name,
y=paste("Number of Respondants out of",nrow(d))) +
geom_text(aes(label = scales::percent((..count..)/sum(..count..))),
stat= "count", hjust=-.1)
})
output$surveyPlot3 <- renderPlot({
d <- d[d$"Frequency of Games" %in% c(input$frequency),]
d <- d[d$"Length of Games" %in% c(input$length),]
d <- d[d$"Primary Locations" %in% c(input$locations),]
d <- d[d$"Campaign Worlds" %in% c(input$worlds),]
d <- d[d$"Adventures" %in% c(input$adventures),]
d <- d[d$"Preferred Combat Type" %in% c(input$combat),]
d <- d[d$"Preparation Time" %in% c(input$preptime),]
column_name <- "Preparation Time"
factor_labels <- c("More than four hours","About four hours","About three hours","About two hours","About an hour","About 30 minutes","About 15 minutes","I don't prepare at all")
d[,column_name] <- factor(d[,column_name], levels = factor_labels)
p3 <- ggplot(d, aes(factor(d[,column_name])))
p3 + geom_bar() + coord_flip() + theme_minimal() +
scale_y_continuous(expand=c(.1, 0)) +
labs(x = "",
title = column_name,
y=paste("Number of Respondants out of",nrow(d))) +
geom_text(aes(label = scales::percent((..count..)/sum(..count..))),
stat= "count", hjust=-.1)
})
output$surveyPlot4 <- renderPlot({
d <- d[d$"Frequency of Games" %in% c(input$frequency),]
d <- d[d$"Length of Games" %in% c(input$length),]
d <- d[d$"Primary Locations" %in% c(input$locations),]
d <- d[d$"Campaign Worlds" %in% c(input$worlds),]
d <- d[d$"Adventures" %in% c(input$adventures),]
d <- d[d$"Preferred Combat Type" %in% c(input$combat),]
d <- d[d$"Preparation Time" %in% c(input$preptime),]
# Set up a bunch of facets to show bar plots
l <- reshape(d,
varying = c("Campaign and Worldbuilding","Story and Adventures","Combat Encounters","NPC Development","Exploration and Roleplay","Treasure and Magic Items","Prop and Handouts"),
v.names = "Times",
timevar = "Activities",
times = c("Campaign and Worldbuilding","Story and Adventures","Combat Encounters","NPC Development","Exploration and Roleplay","Treasure and Magic Items","Prop and Handouts"),
direction = "long")
keeps <- c("Activities", "Times")
l <- l[keeps]
l[l=="None"] <- "None"
l[l=="About 5 minutes"] <- "5 min"
l[l=="About 15 minutes"] <- "15 min"
l[l=="About 30 minutes"] <- "30 min"
l[l=="About an hour"] <- "1 hr"
l[l=="About two hours"] <- "2 hrs"
l[l=="More than two hours"] <- "> 2 hrs"
factor_labels <- c("None","5 min","15 min","30 min","1 hr","2 hrs","> 2 hrs")
factor_charts <- c("Campaign and Worldbuilding","Story and Adventures","Combat Encounters","NPC Development","Exploration and Roleplay","Treasure and Magic Items","Prop and Handouts")
l[,"Times"] <- factor(l[,"Times"], levels = factor_labels)
l[,"Activities"] <- factor(l[,"Activities"], levels = factor_charts)
row_count <- nrow(d)
ggplot(l, aes(x=Times)) + geom_bar() + facet_wrap(~Activities, nrow = 2, scales="free_x") +
xlab(paste("Preparation Time for Specific Activities out of",nrow(d),"Respondants")) +
ylab("Number of respodants") +
scale_y_continuous(expand=c(.1, 0)) +
theme(axis.text.x = element_text(angle = 90, hjust = 1),
axis.title.x=element_text(),
axis.title.x=element_text()) +
geom_text(aes(row_count=row_count, label = paste(round((..count../row_count)*100,0),"%", sep="")),
stat= "count", vjust=-.2, size=3)
})
}
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
actionButton("recalculate", "Recalculate"),
checkboxGroupInput("frequency", "Frequency of Games",
unique(d[,2]), selected = unique(d[,2])),
checkboxGroupInput("length", "Length of Games",
unique(d[,3]), selected = unique(d[,3])),
checkboxGroupInput("locations", "Primary Locations",
unique(d[,5]), selected = unique(d[,5])),
checkboxGroupInput("worlds", "Campaign Worlds",
unique(d[,6]), selected = unique(d[,6])),
checkboxGroupInput("adventures", "Adventures",
unique(d[,7]), selected = unique(d[,7])),
checkboxGroupInput("combat", "Combat Type",
unique(d[,8]), selected = unique(d[,8])),
checkboxGroupInput("preptime", "Preparation Time",
unique(d[,9]), selected = unique(d[,9]))
),
mainPanel(htmlOutput("textmain"),
htmlOutput("text1"),
htmlOutput("text2"),
htmlOutput("text3"),
htmlOutput("text4"),
plotOutput("surveyPlot1"),
plotOutput("surveyPlot2"),
plotOutput("surveyPlot3"),
plotOutput("surveyPlot4"))
)
)
shinyApp(ui = ui, server = server)

Resources