Shiny App won't deploy but it runs locally - r

My Shiny app is running locally but won't deploy. I've looked through similar questions and tried going through simple things which could be causing it e.g., wrong filepaths, setwd but that's not the case.
Here is some stuff from the logs:
Error in value[3L] :
Execution halted
dataTableOutput, renderDataTable
Error in value[3L] :
Shiny application exiting ...
The following object is masked from ‘package:graphics’:
dataTableOutput, renderDataTable
Here are some of the more relevant bits of the app.R file:
preds_with_mins <- read.csv("data/preds_with_mins.csv",
stringsAsFactors = FALSE)
filename <- paste0("data/all_players_final/all_players_finalgw", season,"_",current_gw, ".csv")
xg_data <- read.csv(filename, stringsAsFactors = FALSE) %>%
dplyr::rename('npxg90' = "npxG.90",
'xa90'= "xA.90") %>%
dplyr::select(player_name, npxg90, xa90, Team)
xg_data <- normal_preds %>%
dplyr::select(Player, Price, Position) %>%
dplyr::left_join(xg_data, by = c("Player" = "player_name"))
# xg_data[xg_data$Player == "Rúben Dias", "Price"] <- 6
# normal_preds[normal_preds$Player == "Rúben Dias", "Player"] <- "Ruben Dias"
# normal_preds[normal_preds$Player == "João Cancelo", "Player"] <- "Joao Cancelo"
review_data <- read.csv("data/fplreview_mins.csv",
stringsAsFactors = FALSE,
encoding = "UTF-8") %>%
dplyr::select(2,3,4,6,8,10,12,14,16,1) %>%
dplyr::rename('Price' = 'BV') %>%
dplyr::select(1,2, 5:9, 3:4,10) %>%
dplyr::rename('Position' = 'X.U.FEFF.Pos')
review_data[review_data$Position == "D", "Position"] <- "Defenders"
review_data[review_data$Position == "M", "Position"] <- "Midfielders"
review_data[review_data$Position == "F", "Position"] <- "Forwards"
review_data[review_data$Position == "G", "Position"] <- "Goalkeepers"
rev_gw_cols <- paste0("X", c(first_gw:(first_gw + 4)), "_Pts")
review_total <- review_data %>%
tidyr::pivot_longer(rev_gw_cols,names_to = "Gameweek",values_to = "points") %>%
dplyr::select(ID, Name,Team,Position,Price,Gameweek,points)%>%
dplyr::group_by(ID,Name,Team,Position,Price) %>%
dplyr::summarise(`Review Total`=round(sum(points),1)) %>%
dplyr::ungroup() %>%
dplyr::select(ID,
Team,
Name,
`Review Total`,
Price,
Position) %>%
rename('Price (£m)' = 'Price',
'Player' = 'Name') %>%
filter(`Review Total` > 0) %>%
dplyr::arrange(desc(`Review Total`)) %>%
dplyr::filter(Position != "Goalkeepers")
ae_total <- preds_with_mins %>%
dplyr::select(1,2,4,6,8,10, id) %>%
tidyr::pivot_longer(rev_gw_cols,names_to = "Gameweek",values_to = "points") %>%
dplyr::select(id, player_name,Gameweek,points) %>%
dplyr::group_by(id,player_name) %>%
dplyr::summarise(`AE Total`=round(sum(points),1)) %>%
dplyr::ungroup()
all_model_preds <- review_total %>%
dplyr::left_join(ae_total,
by = c("ID" = "id")) %>%
dplyr::filter(!is.na(`AE Total`)) %>%
dplyr::select(Player,
`AE Total`,
`Review Total`,
`Price (£m)`,
Position,
Team)
levels(all_model_preds$Position) <- c("Defenders","Midfielders","Forwards")
#ui / front end
ui <- fluidPage(
titlePanel(tags$h1("Albert's FPL Model" ,align="center")),
sidebarLayout(
sidebarPanel(#h3("Filters"),
sliderInput("gwrange","Gameweek Range",value=c(first_gw,first_gw + 3),min = first_gw, max = 38, step=1),
sliderInput("price_filter","Price (£m)",value=c(0,13.5),min=0,max=13.5,step=0.5),
selectInput("plot_pos",label="Position",choices=c("All Players","Defenders","Midfielders","Forwards")),
selectInput("team_filter",label="Team",choices=c("All Teams", sort(unique(normal_preds$Team)))),
selectInput("time_decay", label = "Time Decay", choices = c("Yes", "No"))
,width=2) #,textOutput("gwrange") #h3("Gameweek Range:3-6"),
,
mainPanel(
tabsetPanel(
tabPanel("Albert's Model",
DT::dataTableOutput("dynamic_df"),downloadButton('download','Download')
),
# tabPanel("Comparison With Review",
# DT::dataTableOutput("all_models")),
tabPanel("Points vs Price Graph",plotlyOutput("plot", width = "800px")
),
tabPanel("xG graphs",plotlyOutput("xgplot", width = "800px")
),
tabPanel("Methodology",htmlOutput("text"))
)#,width=10
)
)
)
#server/back end
server <- function(input, output, session) {
#summarise data based on the gw range they've chosen
gws_cols <- reactive(paste0("gw",seq(input$gwrange[1],input$gwrange[2],1)))
#gws_cols <- paste0("gw",gws())
predictions <- shiny::reactive(
if (input$time_decay == "No") {
normal_preds
} else {
decayed_preds
})
all_model_preds2 <- shiny::reactive(
if (input$time_decay == "No") {
all_model_preds
} else {
all_model_preds
})
base_data <- reactive(pivot_longer(predictions(),gws_cols(),names_to = "Gameweek",values_to = "Expected_points") %>%
select(Player,Team,Position,Price,Gameweek,Expected_points)%>%
group_by(Player,Team,Position,Price) %>%
summarise(Points=round(sum(Expected_points),1)) %>%
ungroup() %>%
dplyr::select(Team,
Player,
Points,
Price,
Position) %>%
rename('Price (£m)' = 'Price') %>%
filter(Points>0) %>%
arrange(desc(Points)) )
price_filtered_data <- reactive(base_data() %>%
dplyr::filter(`Price (£m)` >= input$price_filter[1],
`Price (£m)` <= input$price_filter[2]))
#output$static <- renderTable(head(all_preds))
#table_data <- reactive(if(input$plot_pos=="All Players"){filter(select(base_data(),-Position),`Price (£m)` >= input$price_filter[1] & `Price (£m)` <= input$price_filter[2])}else{ select(filter(base_data(),Position==input$plot_pos & `Price (£m)` >= input$price_filter[1] & `Price (£m)` <= input$price_filter[2], Team == input$team_filter),-Position)})
table_data <- reactive(if(input$plot_pos=="All Players" & input$team_filter == "All Teams"){
price_filtered_data()} else if (input$plot_pos=="All Players" & input$team_filter != "All Teams"){
dplyr::filter(price_filtered_data(),Team == input$team_filter)}
else if (input$plot_pos!="All Players" & input$team_filter == "All Teams"){
dplyr::filter(price_filtered_data(),Position==input$plot_pos)} else {
dplyr::filter(price_filtered_data(),Position==input$plot_pos & Team == input$team_filter)
})
output$dynamic_df <- DT::renderDataTable(select(table_data(), -Team),options = list(pageLength = 10))#,extensions="buttons",buttons=c('csv')
price_filtered_data_rev <- reactive(all_model_preds2() %>%
dplyr::filter(`Price (£m)` >= input$price_filter[1],
`Price (£m)` <= input$price_filter[2]))
#output$static <- renderTable(head(all_preds))
#table_data <- reactive(if(input$plot_pos=="All Players"){filter(select(base_data(),-Position),`Price (£m)` >= input$price_filter[1] & `Price (£m)` <= input$price_filter[2])}else{ select(filter(base_data(),Position==input$plot_pos & `Price (£m)` >= input$price_filter[1] & `Price (£m)` <= input$price_filter[2], Team == input$team_filter),-Position)})
table_data_rev <- reactive(if(input$plot_pos=="All Players" & input$team_filter == "All Teams"){
price_filtered_data_rev()} else if (input$plot_pos=="All Players" & input$team_filter != "All Teams"){
dplyr::filter(price_filtered_data_rev(),Team == input$team_filter)}
else if (input$plot_pos!="All Players" & input$team_filter == "All Teams"){
dplyr::filter(price_filtered_data_rev(),Position==input$plot_pos)} else {
dplyr::filter(price_filtered_data_rev(),Position==input$plot_pos & Team == input$team_filter)
})
#output$all_models <- DT::renderDataTable(table_data_rev(),options = list(pageLength = 10), rownames = FALSE)
output$download <- downloadHandler(filename=function(){"albertsfplmodel.csv"},
content=function(fname){
write.csv(preds_with_mins,fname)
})
#output$plot <- renderPlotly({if (input$plot_pos=="Defenders"){
# ggplotly(plot1, tooltip = "text") #ggplotly(plot1, tooltip = "text")
#} #else if (input$plot_pos=="Midfielders"){
# plot2
#
#} else {
# plot3
#}}) #, res = 96
plot_data <- reactive(if(input$plot_pos=="All Players" & input$team_filter == "All Teams"){
base_data()} else if (input$plot_pos=="All Players" & input$team_filter != "All Teams"){
dplyr::filter(base_data(),Team == input$team_filter)}
else if (input$plot_pos!="All Players" & input$team_filter == "All Teams"){
dplyr::filter(base_data(),Position==input$plot_pos)} else {
dplyr::filter(base_data(),Position==input$plot_pos & Team == input$team_filter)
})
# plot_cols <- reactive(if(input$plot_pos=="All Players"))
output$plot <- renderPlotly({ggplotly(ggplot(plot_data(),
aes(x=`Price (£m)`,y=Points,group=1,col=Position,
text=paste("Player: ",Player,"<br> Points: ",Points,"<br> Price: £",`Price (£m)`,"m",sep="")))+
geom_point() +
xlab("Price (£m)")+
ylab("Points")+scale_color_manual(values=c("Defenders"="#F8766D","Midfielders"="#00BA38","Forwards"="#619CFF")),tooltip="text")})
xg_plot_data <- reactive(if(input$plot_pos=="All Players" & input$team_filter == "All Teams"){
xg_data} else if (input$plot_pos=="All Players" & input$team_filter != "All Teams"){
dplyr::filter(xg_data,Team == input$team_filter)}
else if (input$plot_pos!="All Players" & input$team_filter == "All Teams"){
dplyr::filter(xg_data,Position==input$plot_pos)} else {
dplyr::filter(xg_data,Position==input$plot_pos & Team == input$team_filter)
})
output$xgplot <- renderPlotly({ggplotly(ggplot(xg_plot_data(),
aes(x=xa90,y=npxg90,group=1,col=Position,
text=paste("Player: ",Player,"<br> Price: £",Price,"m",sep="")))+
geom_point() +
xlab("xA/90")+
ylab("npxG/90")+scale_color_manual(values=c("Defenders"="#F8766D","Midfielders"="#00BA38","Forwards"="#619CFF")),tooltip="text")})
output$text <- renderText({paste0(h3("Data"),"The data used for the model is expected goal and assist data from www.Fbref.com " ,"</p>",h3("Goal and Assist Points"),"</p>",
"A weighted average of the last 20 games is used to calculate a player's average non-penalty expected goals per 90 (npxg/90) and expected assists per 90 (xA/90).
A player's average npxg/90 and xa/90 are adjusted for each game by the defensive strength of the opposition and if they're playing home or away. This is then multiplied by the number of points scored for a goal or assist.",h3("Clean Sheet Points"),"</p>",
"Weighted averages of non-penalty expected goals are also used to determine the attacking and defensive strength of each team.","</p>","To estimate points from clean sheets, a team's defensive strength is adjusted by the attacking strength of the opposition team and if they are playing at home or away. Their adjusted defsenive strength is then used as the mean of a poisson distribtution, to work out the probability of conceding zero goals.
This probability is then multiplied by the number of points scored for keeping a clean sheet.","</p>",h3("Miscallaneous"),"</p>","Players may also have their npxg/90 average modified depending on their finishing skill and if they take penalties.",
"</p>","All Predictions are adjusted by the number of minutes each player is estimated to play, with estimates taken from www.fplreview.com. This means players who are currently injured and more likely to be rotated are predicted fewer points.","</p>","Predictions for new signings or promoted players are not available or inaccurate due to lack of data.",
"</p>", "Alpha = 0.8 is used for the decayed predictions.")})
#output$gwrange <- renderText({"These Predictions are for gameweeks 3 to 6"})
#+
#scale_color_manual(values=c("#F8766D","00BA38","619CFF"))
#
#original mins_data df
#output$mins_data_original <- DT::renderDataTable(mins_data,options = list(pageLength = 10))
#reactive values to store mins_data df (which gets updated)
#values <- reactiveValues(df = mins_data)
#updating the df when user updates their estimates of a player's mins
#observeEvent(input$update_mins,{values$df[values$df$player_name==input$player_name,"avg_mins"] <- input$new_mins})
#output$mins_data_dynamic <- DT::renderDataTable(values$df)#,options = list(pageLength = 10))
}
shinyApp(ui, server)
It deployed fine before but I'm now having problems due to the 'all_model_preds' dataframe.
I've written this in a rush as I'm about to head out, please let me know if I need to be more specific

Related

How to remove error while is loading in Shiny

I'm trying to build a Shiny App, everything works ok, but my issue is at the beginning, the first time that my app is launched i get an error in my highcharts due the size of the data (more than 3M of rows),
After 10 seconds the error disapear and everithing looks ok, but i want to remove the error, now i'm using waiter package, loading screeen is displayed 1.5 seconds, then the error appear and later the graph is showed .
I want to use Waiter package to hide this error until every calculation is finished. This is the Error
Below here my code for the graph
# Graph for shortInterest tab By CvsI (bars) --Dynamic
output$graph_bars_shortInterest_hc <- renderHighchart({
waiter_show(
id = "graph_bars_shortInterest_hc",
html = tagList(spin_fading_circles(),
"Loading Model ..."),
color = "#63666a",
logo = "",
hide_on_render = !is.null(id)
)
Client <- subset(Data_russel, Metrics == "marketCap") %>%
filter(Value >= input$MC_bars_[1])%>%
filter(Value <= input$MC_bars_[2])%>%
select(Client_Name) %>% unique()
Client_2 <- subset(Data_russel, Metrics == "Annual_Limit_Adequacy") %>%
filter(Value >= input$AL_filter_[1])%>%
filter(Value <= input$AL_filter_[2])%>%
select(Client_Name) %>% unique()
Data_Metric <- subset(Data_russel, Metrics == "shortInterest" & Industry %in% input$industry_CvsI_bars)
Client_filtered <- inner_join(Client, Client_2, by = "Client_Name")
Data_ <- inner_join(Client_filtered, Data_Metric, by = "Client_Name") # Clients in the range of Selected Market cap
Data_c <- subset(Data_russel, Metrics == "shortInterest" & Industry %in% input$industry_CvsI_bars & Client_Name == input$clientname_CvsI_bars)
Table_ <- seq(input$perc_range_[1], input$perc_range_[2], 1) %>% as.data.frame()
names(Table_) <- "Percentile"
Table_$Value <- round( quantile(Data_c$Value, Table_$Percentile/100), digits = 2)
Table_$Industry <- round( quantile(Data_$Value, Table_$Percentile/100), digits = 2)
hc_1 <- Table_ %>%
hchart(. , type = "line", hcaes(x = Percentile, y = Value), name = "Client", color = "#FFB81C") %>%
hc_add_series(data = Table_ ,type = 'line' , color = "#00a0d2", name = "Industry", hcaes(x = Percentile, y = Industry))%>%
hc_yAxis(opposite = TRUE) %>%
hc_title(text = "shortInterest Benchmark", margin = 30,
align = "center",
style = list(color = "#702080", useHTML = TRUE)) %>%
hc_yAxis(max = max(Table_$Industry)+(sd(Table_$Industry)/5))%>%
hc_yAxis(min = min(Table_$Industry)-(sd(Table_$Industry)/5))%>%
hc_add_theme(hc_theme_google())
hc_1
})
Thanks !!
I fixed using next function, and using each output in the UI into this function
output %>% withSpinner(
type = getOption("spinner.type", default = 3),
color.background = getOption("spinner.color.background", default = "#C8D7DF" ),
color="#00A0D2")
}```

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()).

Connecting Shiny Movie gallery example with my own cvs file

I have read now the stackoverflow Q&A for several hours on various days and have also seen the latest specific Shiny debugging video from the Shiny developer conference (Jonathan McPherson):
Now the problem looks simple to me, but I went through lots of checks, revisions of the naming conventions and thought of various hypotheses: Making column titles starting with capital letters, calling the initial file similar to the template, renaming the column titles, ...
I like the interactive scatter plots from the Movie Gallery and would like to reproduce it with my own records, located in a cvs file, which I uploaded in my RStudio session with the name all_flexitime, which I understand now is not enough.
How do I connect or integrate my cvs file into the given template? I have renamed all necessary fields, I believe. The error I am getting says:
Error in eval(substitute(expr), envir, enclos) :
object 'Flexileave2015' not found
Flexileave2015 is, I believe, the first variable the server file is looking for to produce the scatter plot, but since the file needs to be found somewhere in the server file, it cannot find it there. I can see it in my Studio.
Can somebody confirm my understanding and possibly help, please.
My all_flexitime data frame is made of the following columns titles:
"Number", "First", "Last", "Contract", "Grade", "Flexileave2015", "Certifiedsickleave2015", "Uncertifiedsickleave2015", "Daysnotrecorded2015", "Excess2015".
My server.R is:
library(ggvis)
library(dplyr)
if (FALSE) library(RSQLite)
shinyServer(function(input, output, session) {
# Filter staff, returning a data frame
flexitimes <- reactive({
# Due to dplyr issue #318, we need temp variables for input values
flexileave2015 <- input$flexileave2015
certifiedsickleave2015 <- input$certifiedsickleave2015
uncertifiedsickleave2015 <- input$uncertifiedsickleave2015
daysnotrecorded2015 <- input$daysnotrecorded2015
excess2015 <- input$excess2015
# Apply filters
m <- all_flexitimes %>%
filter(
Flexileave2015 >= flexileave2015,
Excess2015 >= excess2015,
Certifiedsickleave2015 >= certifiedsickleave2015,
Uncertifiedsickleave2015 >= uncertifiedsickleave2015,
Daysnotrecorded2015 >= daysnotrecorded2015
) %>%
arrange(Flexileave2015)
# Optional: filter by Contract
if (input$contract != "All") {
contract <- paste0("%", input$contract, "%")
m <- m %>% filter(Contract %like% contract)
}
# Optional: filter by Grade
if (input$grade != "All") {
grade <- paste0("%", input$grade, "%")
m <- m %>% filter(Grade %like% grade)
}
# Optional: filter by Number
if (!is.null(input$number) && input$number != "") {
number <- paste0("%", input$number, "%")
m <- m %>% filter(Number %like% number)
}
# Optional: filter by Last Name
if (!is.null(input$last) && input$last != "") {
last <- paste0("%", input$last, "%")
m <- m %>% filter(Last %like% last)
}
m <- as.data.frame(m)
m
})
# Function for generating tooltip text
flexitime_tooltip <- function(x) {
if (is.null(x)) return(NULL)
if (is.null(x$Number)) return(NULL)
# Pick out the staff with this Number
all_flexitimes <- isolate(flexitimes())
flexitime <- all_flexitimes[all_flexitimes$Number == x$Number, ]
paste0("<b>", flexitime$First, flexitime$Last, "</b><br>",
flexitime$Grade, "<br>",
flexitime$Contract
)
}
# A reactive expression with the ggvis plot
vis <- reactive({
# Lables for axes
xvar_name <- names(axis_vars)[axis_vars == input$xvar]
yvar_name <- names(axis_vars)[axis_vars == input$yvar]
# Normally we could do something like props(x = ~BoxOffice, y = ~Reviews),
# but since the inputs are strings, we need to do a little more work.
xvar <- prop("x", as.symbol(input$xvar))
yvar <- prop("y", as.symbol(input$yvar))
flexitimes %>%
ggvis(x = xvar, y = yvar) %>%
layer_points(size := 50, size.hover := 200,
fillOpacity := 0.2, fillOpacity.hover := 0.5,
key := ~ Number) %>%
add_tooltip(flexitime_tooltip, "hover") %>%
add_axis("x", title = xvar_name) %>%
add_axis("y", title = yvar_name) %>%
set_options(width = 500, height = 500)
})
vis %>% bind_shiny("plot1")
output$n_flexitimes <- renderText({ nrow(flexitimes()) })
})
The ui.R file is the following:
library(ggvis)
# For dropdown menu
actionLink <- function(inputId, ...) {
tags$a(href='javascript:void',
id=inputId,
class='action-button',
...)
}
shinyUI(fluidPage(
titlePanel("Overview of Flexitime usage"),
fluidRow(
column(3,
wellPanel(
h4("Filter"),
sliderInput("flexileave2015", "Flexileave 2015", 0, 14, 0, step = 1),
sliderInput("certifiedsickleave2015", "Certified sickleave 2015", 0, 230, 0, step = 1),
sliderInput("uncertifiedsickleave2015", "Uncertified sickleave 2015", 0, 13, 0, step = 1),
sliderInput("daysnotrecorded2015", "Days not recorded 2015", 0, 110, 0, step = 10),
sliderInput("excess2015", "Excess 2015", -100, 1500, 0, step = 50),
selectInput("contract", "Contract",
c("All", "Temporary Agent", "Contract Agent", "National Expert", "Interim")),
selectInput("grade", "Grade",
c("All", "AD05","AD06","AD07","AD08","AD09", "AD10","AD11", "AD12","AD13", "AD14","AD15","AST01","AST02","AST03","AST04","AST05","AST06","AST07",
"AST08","AST09","AST10","FGII.04","FGII.05","FGII.06","FGIII.08","FGIII.09","FGIII.10",
"FGIV.13","FGIV.14","FGIV.16","FGIV.18","SNE")),
textInput("number", "SAP Personnelnumber"),
textInput("last", "Initial of Last Name")
),
wellPanel(
selectInput("xvar", "X-axis variable", axis_vars, selected = "Flexileave2015"),
selectInput("yvar", "Y-axis variable", axis_vars, selected = "Uncertifiedsickleave2015"),
tags$small(paste0(
"Note: AD and AST are Temporary agent grades.",
" FG are Contract agent grades.",
" SNE is the only National expert grade.",
" Interims should not have an FG grade."
))
)
),
column(9,
ggvisOutput("plot1"),
wellPanel(
span("Number of staff members selected:",
textOutput("n_flexitimes")
)
)
)
)
))
I got external help for my shiny app, so I am posting how I sorted the problems in the end:
There was a spelling mistake for the all_flexitime data set, I changed it to be all_flexitimes.
In the preparatory work file (the one where I created the original database), I have made sure that the variables are read as characters and not as factors:
all_flexitimes$Grade <- as.character(all_flexitimes$Grade)
all_flexitimes$Contract <- as.character(all_flexitimes$Contract)
all_flexitimes$First <- as.character(all_flexitimes$First)
all_flexitimes$Last <- as.character(all_flexitimes$Last)
I have saved the all_flexitimes file into an .RData file via the following command, while I was in the RStudio working environment:
saveRDS(all_flexitimes, "all_flexitimes.RData")
In the global.R file I have added at the end the following line, so that the database can be read:
all_flexitimes <- readRDS("all_flexitimes.Rdata")
In the ui.file I used the following, as this was the safer option, as it avoids any misspelling:
selectInput("contract", "Contract",
c("All", sort(unique(all_flexitimes$Contract)))),
selectInput("grade", "Grade",
c("All", sort(unique(all_flexitimes$Grade)))),
In the server file, I have changed the manual filters to:
Optional: filter by Contract
if (input$contract != "All") {
contract <- paste0("%", input$contract, "%")
m <- m %>% filter(Contract == input$contract)
}
Optional: filter by Grade
if (input$grade != "All") {
grade <- paste0("%", input$grade, "%")
m <- m %>% filter(Grade == input$grade)
}
Optional: filter by Number
if (!is.null(input$number) && input$number != "") {
number <- paste0("%", input$number, "%")
m <- m %>% filter(Number == input$number)
}
Optional: filter by Last Name
if (!is.null(input$last) && input$last != "") {
last <- paste0("%", input$last, "%")
m <- m %>% filter(Last == input$last)

How to make fill color consistent when plotting subsets of a dataframe with ggvis

I am trying to make the colors in a ggvis plot remain consistent whenever the data is re-plotted based on the factors (unfortunately I apparently lack enough reputation to include pictures to show you).
I could only find one other post about this controlling-color-of-factor-group-in-ggvis-r but none of his solutions or workarounds work in my situation.
my data looks like this:
month year date entity_name prefix module module_entry_key entity_table_name count
0 January 2011 2011.000 AbLibrary LIB Base BS AB_LIBRARY 0
1 February 2011 2011.083 AbLibrary LIB Base BS AB_LIBRARY 0
2 March 2011 2011.167 AbLibrary LIB Base BS AB_LIBRARY 0
3 April 2011 2011.250 AbLibrary LIB Base BS AB_LIBRARY 0
4 May 2011 2011.333 AbLibrary LIB Base BS AB_LIBRARY 0
5 June 2011 2011.417 AbLibrary LIB Base BS AB_LIBRARY 0
3000 January 2011 2011.000 Vector VEC Base BS VECTOR 0
3001 February 2011 2011.083 Vector VEC Base BS VECTOR 0
3002 March 2011 2011.167 Vector VEC Base BS VECTOR 0
3003 April 2011 2011.250 Vector VEC Base BS VECTOR 569
3004 May 2011 2011.333 Vector VEC Base BS VECTOR 664
3005 June 2011 2011.417 Vector VEC Base BS VECTOR 775
I'm using a shiny app to display the page in a browser, and the relevant code is:
# render the plot, filtering for entities within the module minus any entities selected from the exclude panel
plot <- reactive({
if (input$filter==1){
data <- dplyr::filter(.data=melted, module_entry_key %in% input$module)
}
else{
data <- dplyr::filter(.data=melted, entity_name == input$entity)
}
data <- dplyr::filter(.data=data, !entity_name %in% input$excluded)
data$entity_name <- factor(data$entity_name)
data %>%
ggvis(x = ~date, y = ~count, fill = ~entity_name, key := ~id, fillOpacity := 0.5, fillOpacity.hover := 0.9) %>%
add_legend("fill", title="Entities") %>%
layer_points() %>%
add_tooltip(tooltipText, "hover") %>%
add_axis("y", title = "Count", title_offset = 50) %>%
add_axis("x", title="Date", title_offset=50, subdivide=6, tick_size_minor=3, format=parseDate(~year, ~month))
})
the filter is creating the subset of "melted" as "data" based on the filters in the UI (see picture)
since as far as I can tell there is no way to associate a fill color to a factor (the entity name) explicitly and the color is chosen by alphabetical order of the factors, whenever I make a new subset of data the colors are changed.
Is there any way to work around this?
(full shiny code)
server.R
library(ggvis)
library(shiny)
library(dplyr)
shinyServer(function(input, output, session){
modules_list <- as.character(c("Base" = "BS",
"Screening" = "SC",
"Protein Engineering" = "EN",
"Protein Production" = "PP",
"CD",
"PT",
"PD"))
#melted <- read.table(file="~/dataOut.txt", sep="\t", strip.white=TRUE, row.names=1, header=TRUE);
modules <- as.character(as.vector(unique(melted$module_entry_key)))
modules <- modules[modules != "null"]
entities <- as.character(as.vector(unique(melted$entity_name)))
entities <- entities[entities != "null"]
for (i in entities){
melted <- rbind(melted, data.frame(month=NA, year=NA, date=NA, entity_name=i, prefix=NA, module=NA, module_entry_key=NA, entity_table_name=NA, count=NA))
}
melted$id <- 1:nrow(melted)
#create ui checkbox for modules in the data
output$module_list <- renderUI({
checkboxGroupInput(inputId = "module",
label = "Module",
choices = modules,
selected = "BS")
})
#create the ui list for entities
output$entity_list <- renderUI({
checkboxGroupInput(
inputId = "entity",
label = "Entity",
choices = entities,
selected = "Vector"
)
})
#ex <- entities
#create the checkboxGroupInput with entities to 'exclude'
output$exclusion_entities <- renderUI({
checkboxGroupInput(inputId = "excluded", label = "Exclude",
choices = entities)
})
#update the excluded entities list with entities within a particular module
observe({
if (input$filter==1)
ex1 <- as.character(as.vector(unique(dplyr::filter(.data=melted, module_entry_key %in% input$module)$entity_name)))
updateCheckboxGroupInput(session, inputId = "excluded", "Exclude", choices=ex1, selected = input$excluded )
})
# render the plot, filtering for entities within the module minus any entities selected from the exclude panel
plot <- reactive({
if (input$filter==1){
data <- dplyr::filter(.data=melted, module_entry_key %in% input$module)
}
else{
data <- dplyr::filter(.data=melted, entity_name == input$entity)
}
data <- dplyr::filter(.data=data, !entity_name %in% input$excluded)
data$entity_name <- factor(data$entity_name)
data %>%
ggvis(x = ~date, y = ~count, fill = ~entity_name, key := ~id, fillOpacity := 0.5, fillOpacity.hover := 0.9) %>%
add_legend("fill", title="Entities") %>%
layer_points() %>%
add_tooltip(tooltipText, "hover") %>%
add_axis("y", title = "Count", title_offset = 50) %>%
add_axis("x", title="Date", title_offset=50, subdivide=6, tick_size_minor=3, format=parseDate(~year, ~month))
})
#function to add color and mouse-over effect to layer_points() (unused in this code)
points <- reactive({
layer_points(fillOpacity := 0.5, fillOpacity.hover := 1, fill.hover := "red")
})
#d3 date format for formatting x-axis text
parseDate <- function(year, month){
paste("d3.time.format(\"%Y\").parse(", year, ")", sep="")
}
#function for what to display in mouse-hover tooltip
tooltipText <- function(x) {
if(is.null(x)) return(NULL)
row <- melted[melted$id == x$id, ]
paste(row$entity_name, ": ", row$count, sep="")
}
#bind the plot to the UI
plot %>% #layer_points(fill = ~factor(entity_name)) %>%
bind_shiny("ggvis")
#select all button for modules
observe({
if (input$selectall ==0){
return(NULL)
}
else if ((input$selectall%%2)==0){
updateCheckboxGroupInput(session, inputId = "module", "Module", choices = modules)
}
else{
updateCheckboxGroupInput(session, inputId = "module", "Module", choices=modules, selected=modules)
}
})
#select all button for excluded entities
observe({
list <- as.character(as.vector(unique(dplyr::filter(.data=melted, module_entry_key %in% input$module)$entity_name)))
if (input$exclude_all ==0){
return(NULL)
}
else if ((input$exclude_all%%2)==0){
updateCheckboxGroupInput(session, inputId = "excluded", "Exclude", choices=list )
}
else{
updateCheckboxGroupInput(session, inputId = "excluded", "Exclude", choices=list, selected=list )
}
})
#---general output / debugging stuff ----#
output$table <- renderTable({dataInput()})
output$entity_selected = renderPrint({
list <- as.character(as.vector(unique(dplyr::filter(.data=melted, module_entry_key %in% input$module)$entity_name)))
entities[!entities %in% input$excluded & entities %in% list]
})
output$filter_value = renderPrint({input$filter})
output$modules = renderPrint({input$module})
output$link = renderPrint(input$selectall%%2)
#----------------------------------------#
})
ui.R
library(shiny)
shinyUI(fluidPage(
titlePanel("DB Analysis"),
sidebarLayout(
sidebarPanel(
width=3,
radioButtons(inputId="filter",
label="Filter",
choices = list("By Module" = 1, "By Entity" = 2),
selected = 1),
conditionalPanel(condition = "input.filter == 1",
uiOutput("module_list"),
actionButton("selectall", "Select All"),
uiOutput("exclusion_entities"),
actionButton("exclude_all", "Select All")
),
conditionalPanel(condition = "input.filter == 2",
uiOutput("entity_list")
)
),
mainPanel(
h2("Cumulative Entity Counts over Time (years)", align="center"),
#verbatimTextOutput("value"),
#verbatimTextOutput("filter_value"),
#verbatimTextOutput("modules"),
#tableOutput("table"),
ggvisOutput("ggvis"),
verbatimTextOutput("link"),
verbatimTextOutput("entity_selected")
#textOutput("entities_plot")
)
)
)
)
This is probably the best way to do it. Try something like this:
df[which(df$entity_name == "AbLibrary"),]$color <- "FF0000"
df[which(df$entity_name == "Vector"),]$color <- "#FFB90F"
For each one in your data frame. Set your fill then to color each time. The only problem is trying to make a legend. (I have been trying to figure that out, so if I find it I will edit this post.

Barplot stops functioning when adding a key in ggvis (needed for tooltip)

I want to have a tooltip on my bar graph that shows detailed info about a customer when hovered over. The problem is that without a defined key the tooltip does not function and with a defined key the barplot does not function properly anymore. Here is the data I used:
CustomerData:
id;CustomerID;CLV;Gender;Channel;Age
1;1;300;male;facebook;24
2;2;2000;female;google ads;34
3;3;500;female;other;43
4;4;1300;male;google ads;34
5;5;100;male;other;46
6;6;400;female;other;32
7;7;600;female;google ads;43
8;8;1000;male;other;46
9;9;200;female;other;75
10;10;1700;male;google ads;35
11;11;1600;female;google ads;23
12;12;800;female;other;54
13;13;400;female;other;34
14;14;700;male;google ads;42
15;15;500;male;facebook;18
16;16;200;male;other;42
17;17;1900;male;google ads;46
18;18;400;female;other;23
19;19;600;male;other;45
20;20;200;female;other;42
21;21;1400;male;facebook;57
22;22;1200;female;facebook;54
Ui Code:
#this is the ui code
shinyUI(pageWithSidebar(
headerPanel("CLV Reporting"),
sidebarPanel(
navbarMenu(
checkboxGroupInput("gender", 'Gender:',
c("female" = "female",
"male" = "male"))),
navbarMenu(
checkboxGroupInput("channel", 'Channel:',
c("Facebook" = "facebook",
"Google Ads" = "google ads",
"Other" = "other"))),
navbarMenu(
sliderInput("age", "Age Range:",
min = 0, max = 100, value = c(20,50)))
),
mainPanel(
ggvisOutput("barplot"),
textOutput("mean"),
textOutput("price")
)
))
Server Code:
#this is the server code
library(ggvis)
library(dplyr)
library(ggplot2)
library(shiny)
shinyServer(function(input, output, session) {
report <- reactive({
gender <- input$gender
channel <- input$channel
minage <- input$age[1]
maxage <- input$age[2]
rep <- CustomerData %>%
filter(
Gender %in% gender,
Channel %in% channel,
Age >= minage,
Age <= maxage
)
})
#tooltip input
Customer_tooltip <- function (x) {
if (is.null(x)) return(NULL)
if (is.null(x$id)) return(NULL)
CustomerData <- isolate(report())
customer <- CustomerData[CustomerData$id == x$id, ]
paste0("<b>", "Customer ID: ", customer$CustomerID, "</b><br>",
"Gender: ", customer$Gender, "</b><br>",
"Channel: ", customer$Channel, "</b><br>",
"Age: ", customer$Age, "<br>",
"CLV: $", format(customer$CLV, big.mark = "'", scientific = FALSE)
)
}
# output
vis <- reactive({
report %>%
ggvis(x = ~factor(CustomerID), y = ~CLV) %>%
layer_bars(fillOpacity := 0.5, fillOpacity.hover := 1, key := ~id) %>%
add_tooltip(Customer_tooltip, "hover") %>%
add_axis("x", title = "Customer") %>%
add_axis("y", title = "CLV", title_offset = 60) %>%
set_options(width = 500, height = 300)
})
vis %>% bind_shiny("barplot")
output$mean <- renderText({
m <- report()
if (nrow(m) != 0) {paste("The mean CLV of the selected customers is: $", round(mean(m$CLV)))}
else {"There are no customers with these specifications."}
})
output$price <- renderText({
m <- report()
if (nrow(m) != 0) {paste("We recommend to spend $", round(mean(m$CLV)/12)*nrow(m), " on retaining these customers.")}
else {""}
})
})
I added the id column because I thought this could solve the problem (using a key which is not used by anything else in the code). Just in case you wondered why there were two variables with the exact same values ;)
(edit) I uploaded the newest version to gisthub:
https://gist.github.com/anonymous/f04325078f9c0656ab72
packages needed: shiny, ggvis, dplyr and ggplot2

Resources