Related
EDIT WITH MWE BELOW
I have below a snippet of my code which is part of a larger app. I'm trying to rewrite the app to work with R6 classes and gargoyle as per this article. However, I cannot figure out why the observe part of the data below does not trigger except when it's initialized. To my understanding should if observe all the filters that are in input based on the map function, am I wrong?
output$filters <- renderUI({
gargoyle::watch("first thing")
data <- Data$get_data(unfiltered = TRUE)
data_names <- names(data)
if(nrow(data) > 0){
map(data_names, ~ render_ui_filter(data[[.x]], .x))
}
}
)
observe({
data <- Data$get_data(unfiltered = TRUE)
data_names <- names(data)
if(ncol(data) > 0){
each_var <- map(data_names, ~ filter_var(data[[.x]], input[[paste0("filter",.x)]]))
Transactions <- Data$set_filters(reduce(each_var, `&`))
gargoyle::trigger("second thing")
}
})
I've had a working case of the second reactive element like this:
selectedData <- reactive({
if(nrow(data()) > 0){
each_var <- map(dataFilterNames(), ~ filter_var(data()[[.x]], input[[paste0("filter",.x)]]))
reduce(each_var, `&`)
}
})
where data and dataFilterNames are reactiveVal and dataFilterNames is the column names of data.
Here you can find render_ui_filter and filter_var:
render_ui_filter <- function(x, var) {
if(all(is.null(x) | is.na(x))){
#If all data is null, don't create a filter from it
return(NULL)
}
id <- paste0("filter",var)
var <- stringr::str_to_title(var)
if (is.numeric(x)) {
if(is.integer(x)){
step = 1
}
else{
step = NULL
}
rng <- range(x, na.rm = TRUE)
sliderInput(id,
var,
min = rng[1],
max = rng[2],
value = rng,
round = TRUE,
width = "90%",
sep = " ",
step = step
)
} else if (is.factor(x)) {
levs <- levels(x)
if(length(levs) < 5){
pickerInput(id, var, choices = levs, selected = levs, multiple = TRUE,
options = list(
title = sprintf("Filter on %s...", var),
#`live-search` = TRUE,
#`actions-box` = TRUE,
size = 10
))
}else {
pickerInput(id, var, choices = levs, selected = levs, multiple = TRUE,
options = list(
title = sprintf("Filter on %s...", var),
`live-search` = TRUE,
`actions-box` = TRUE,
size = 10,
`selected-text-format` = "count > 5"
))
}
} else if (is.Date(x)){
dateRangeInput(id,
var,
start = min(x),
end = max(x),
weekstart = 1,
autoclose = FALSE,
separator = "-")
} else if (is.logical(x)) {
pickerInput(id, var, choices = unique(x), selected = unique(x), multiple = TRUE,
options = list(
title = sprintf("Filter on %s...", var),
`live-search` = TRUE,
#`actions-box` = TRUE,
size = 10
))
} else {
# Not supported
NULL
}
}
filter_var <- function(x, val) {
if(all(is.null(x) | is.na(x))){
#If all data is null, don't create a filter from it
return(TRUE)
}
if (is.numeric(x)) {
!is.na(x) & x >= val[1] & x <= val[2]
} else if (is.factor(x)) {
x %in% val
} else if(is.Date(x)){
!is.na(x) & x >= val[1] & x <= val[2]
} else if (is.logical(x)) {
x %in% val
} else {
# No control, so don't filter
TRUE
}
}
Edit: Here is a MWE that can be run in a notebook for example. It does not currently work since the gargoyle trigger triggers the observe it is in and we end up in a infinity loop. If you remove that you can see that the normal reactive part works, but the R6 version does not create the table ever.
if (interactive()){
require("shiny")
require("R6")
require("gargoyle")
require("purrr")
require("stringr")
# R6 DataSet ----
DataSet <- R6Class(
"DataSet",
private = list(
.data = NA,
.data_loaded = FALSE,
.filters = logical(0)
),
public = list(
initialize = function() {
private$.data = data.frame()
},
get_data = function(unfiltered = FALSE) {
if (!unfiltered) {
return(private$.data[private$.filters, ])
}
else{
return(private$.data)
}
},
set_data = function(data) {
stopifnot(is.data.frame(data))
private$.data <- data
private$.data_loaded <- TRUE
private$.filters <- rep(T, nrow(private$.data))
return(invisible(self))
},
set_filters = function(filters) {
stopifnot(is.logical(filters))
private$.filters <- filters
}
)
)
# Filtering ----
render_ui_filter <- function(x, var) {
if(all(is.null(x) | is.na(x))){
#If all data is null, don't create a filter from it
return(NULL)
}
id <- paste0("filter",var)
var <- stringr::str_to_title(var)
if (is.numeric(x)) {
if(is.integer(x)){
step = 1
}
else{
step = NULL
}
rng <- range(x, na.rm = TRUE)
sliderInput(id,
var,
min = rng[1],
max = rng[2],
value = rng,
round = TRUE,
width = "90%",
sep = " ",
step = step
)
} else {
# Not supported
NULL
}
}
filter_var <- function(x, val) {
if(all(is.null(x) | is.na(x))){
#If all data is null, don't create a filter from it
return(TRUE)
}
if (is.numeric(x)) {
!is.na(x) & x >= val[1] & x <= val[2]
} else {
# No control, so don't filter
TRUE
}
}
# Options ----
options("gargoyle.talkative" = TRUE)
options(shiny.trace = TRUE)
options(shiny.fullstacktrace = TRUE)
ui <- function(request){
tagList(
h4('Filters'),
uiOutput("transactionFilters"),
h4('Reactive'),
tableOutput("table_reactive"),
h4('R6'),
tableOutput("table_r6")
)
}
server <- function(input, output, session){
gargoyle::init("df_r6_filtered")
Name <- c("Jon", "Bill", "Maria", "Ben", "Tina")
Age <- c(23, 41, 32, 58, 26)
df <- reactive(data.frame(Name, Age))
df_r6 <- DataSet$new()
df_r6$set_data(data.frame(Name, Age))
output$transactionFilters <- renderUI(
map(names(df()), ~ render_ui_filter(x = df()[[.x]], var = .x))
)
selected <- reactive({
if(nrow(df()) > 0){
each_var <- map(names(df()), ~ filter_var(df()[[.x]], input[[paste0("filter",.x)]]))
reduce(each_var, `&`)
}
})
observe({
data <- df_r6$get_data(unfiltered = TRUE)
data_names <- names(data)
if(ncol(data) > 0){
each_var <- map(data_names, ~ filter_var(data[[.x]], input[[paste0("filter",.x)]]))
filters_concatted <- reduce(each_var, `&`)
df_r6$set_filters(filters_concatted)
gargoyle::trigger("df_r6_filtered")
}
})
output$table_reactive <- renderTable(df()[selected(),])
gargoyle::on("df_r6_filtered",{
output$table_r6 <- renderTable(df_r6$get_data())
})
}
shinyApp(ui, server)
}
EDIT2: I noticed that the gargoyle::trigger("df_r6_filtered") creates a infinity loop of triggering the observe component. I'm not sure how to get out of it and that's what I am looking for help with.
The answer was simpler then expected of course. Just change the observe to a observeEvent on all of the input elements regarding the filter, i.e. like this:
observeEvent(
eventExpr = {
data <- df_r6$get_data(unfiltered = TRUE)
data_names <- names(data)
map(data_names, ~ input[[paste0("filter",.x)]])
},
{
...
}
})
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
I can't figure out what is wrong with this code. My shiny give the error when I click on the action button PlotContemp, so I think the problem is somewhere in the mvar function. When I run this code with the same data but outside the Shiny, it works great!So is there a problem with the reactive expressions? I will appreciate some help!
observeEvent(store$df, {
req(store$df)
updateSelectInput(session, "NetVariables", choices = colnames(store$df),
selected = "Anxiety")
})
Vars <- reactive({
Vars <- c(input$NetVariables)
return(Vars)
})
type <- reactive({
type <- rep("g",length(Vars()))
for (v in length(Vars())) {
if (class(store$df[Vars()][[v]]) == "character") {
type[v] <- "c"
}
}
})
levels <- reactive({
levels <- rep(1, length(Vars()))
for (v in length(Vars())) {
if (class(store$df[Vars()][[v]]) == "character") {
levels[v] <- 2
}
}
})
observeEvent(input$PlotContemp, {
req(store$df)
mvar1 <- mvar(store$df[,Vars()], type = type(),
level = levels(), lags=1, dayvar = store$df$day, beepvar = store$df$beep, lambdaSel = "CV", lambafolds = 10, overparameterize = FALSE, k=2, ruleReg = "AND")
qgraph(mvar1$wadj[,,1],
edge.color = mvar1$edgecolor,
layout = "spring",
labels = vars)
})
I have a bunch of reactive filters based on user inputs. I want to addCircleMarkers on my leaflet map only if the filters do not return a NULL value. How can I conditionally addCircleMarkers to a leaflet map in Shiny? Right now it seems that it only plots the results from the second filter instead of both even if user inputs are not NULL for both. My guess is that the second addCircleMarkers function is overwriting the first instead of adding more circles to the map. Here's my server code below:
server.R
server <- function(input, output) {
relig_pal <- colorFactor("magma", unique(all_cleaned$religion))
denom_pal <- colorFactor("viridis", unique(all_cleaned$denom))
output$mymap <- renderLeaflet({
input$years_map
input$map_button
isolate({
map <- leaflet() %>% addTiles()
if(!is.null(geography_1())) {
marker_1 <- addCircleMarkers(map = map, data = geography_1(),
radius = ~ifelse(is.na(denom), log(religion_population),
log(denom_pop)),
color = ~ifelse(is.na(denom), relig_pal(religion),
denom_pal(denom)),
label = ~ifelse(is.na(denom),
paste("Religion:",religion,
"Population:",religion_population),
paste("Denomination:", denom,
"Population:", denom_pop))
)
}
if(!is.null(geography_2())) {
marker_1 %>% addCircleMarkers(data = geography_2(),
radius = ~ifelse(is.na(denom), log(religion_population),
log(denom_pop)),
color = ~ifelse(is.na(denom), relig_pal(religion),
denom_pal(denom)),
label = ~ifelse(is.na(denom),
paste("Religion:", religion,
"Population:", religion_population),
paste("Denomination:", denom,
"Population:", denom_pop))
)
}
})
})
year <- reactive({
req(input$years_map)
all_cleaned %>% filter(year == input$years_map)
})
religion_1 <- reactive({
req(input$religion_1_map)
if(input$religion_1_map == "All") {
year()
}
else if(input$religion_1_map == "None") {
return()
}
else {
year() %>% filter(religion == input$religion_1_map)
}
})
denom_1 <- reactive({
req(input$denom_1_map)
if(input$denom_1_map == "All") {
religion_1()
}
else if(input$denom_1_map == "None") {
religion_1() %>% filter(is.na(denom))
}
else {
religion_1() %>% filter(denom == input$denom_1_map)
}
})
geography_1 <- reactive({
req(input$geography_1_map)
if(input$geography_1_map == "All") {
denom_1()
}
else if(input$geography_1_map == "None") {
return()
}
else {
denom_1() %>% filter(country_name == input$geography_1_map)
}
})
religion_2 <- reactive({
req(input$religion_2_map)
if(input$religion_2_map == "All") {
year()
}
else if(input$religion_2_map == "None") {
return()
}
else {
year() %>% filter(religion == input$religion_2_map)
}
})
denom_2 <- reactive({
req(input$denom_2_map)
if(input$denom_2_map == "All") {
religion_2()
}
else if(input$denom_2_map == "None") {
religion_2() %>% filter(is.na(denom))
}
else {
religion_2() %>% filter(denom == input$denom_2_map)
}
})
geography_2 <- reactive({
req(input$geography_2_map)
if(input$geography_2_map == "All") {
denom_2()
}
else if(input$geography_2_map == "None") {
return()
}
else {
denom_2() %>% filter(country_name == input$geography_2_map)
}
})
}
Error message:
Error:no applicable method for 'filter_' applied to an object of class "NULL"
Thanks in advance for any help!
Once you draw markers on the map, you need to save those to a variable (e.g. see how we solved this problem here.
For the second question (you should really post them separately), try paste instead of cat, e.g. paste(statement1, statement2, sep = "\n").
Update:
I have managed to solve the problem using #Roman Luštrik 's suggestion of storing the first circle marker as a variable and using a placeholder to plot a point of opacity 0 instead of dealing with NULL values whenever nothing is supposed to appear on the plot, which I couldn't quite figure out.
I am writing a shiny app (shinydashboard) that looks like the figure (the app run on my company private network,so I can't share the link to it).
The dataset consists of a table containing the expression values of different genes (rows) for different samples (columns).
The app should return a subset of that table based on the search criteria selected by the user. Information about the samples are stored in a different table (B38.Metadata in the code), that looks like this:
SampleID,RNA.ID,RNAseq.ID,Name,Description,Tissue Type,...
CP3027,CP3027,74,Hs514,Aortic_Endothelial,Vascular system,Endothelial,...
CP3028,CP3028,76,HEr1,Aortic_Endothelial,Vascular system,Endothelial,...
At every search, the metadata are checked and the main table is subset accordingly.
My approach has been to write a function for each search types (SearchByGene,SearchByTissue,...), and
use if-else statements to account for all the possible combinations.
For example, filter by GeneName, Tissue type, and Name, but not for the other options.
This led to a massive 14 if-else block, spanning almost 50 lines of code (see below).
everything works, but the code is dreadful to read and debug.
Furthermore the idea of adding additional search possibilities (e.g. search by sequencing technique)
made me shiver.
I considered using a switch construct, but, having multiple conditions to test I'm not sure it will clean the code too much.
Is there a way of simplify the if-else block with something easier to read and, especially, maintain?
Searchfunction <- function(dataSet2){
selectedTable <- reactive({
# Create a DF with only the gene names
DFgeneLevel <- DummyDFgeneLevel(dataSet2) # not used for now
# Subset by Columns first
if(is.null(input$tissues) && is.null(input$samples) && is.null(input$Name)){
TableByColumns <- dataSet2
} else if(!is.null(input$tissues) && !is.null(input$samples) && !is.null(input$Name)){
TableByTissue <- SearchByTissue(input$tissues,B38.metadata,dataSet2)
TableBySample <- SearchBySample(input$samples,TableByTissue)
TableByColumns <- SearchByName(input$Name,B38.metadata,TableBySample)
} else if(!is.null(input$tissues)){
if(is.null(input$samples) && is.null(input$Name)){
TableByColumns <- SearchByTissue(input$tissues,B38.metadata,dataSet2)
} else if(is.null(input$samples) && !is.null(input$Name)){
TableByTissue <- SearchByTissue(input$tissues,B38.metadata,dataSet2)
TableByColumns <- SearchByName(input$Name,B38.metadata,TableByTissue)
} else if(!is.null(input$samples) && is.null(input$Name)){
TableByTissue <- SearchByTissue(input$tissues,B38.metadata,dataSet2)
TableByColumns <- SearchBySample(input$samples,TableByTissue)
}
} else if(is.null(input$tissues)){
if(is.null(input$samples) && !is.null(input$Name)){
TableByColumns <- SearchByName(input$Name,B38.metadata,dataSet2)
} else if(!is.null(input$samples) && is.null(input$Name)){
TableByColumns <- SearchBySample(input$samples,dataSet2)
} else if(!is.null(input$samples) && !is.null(input$Name)){
TableByName <- SearchBySample(input$samples,dataSet2)
TableByColumns <- SearchByName(input$Name,B38.metadata,TableByName)
}
}
# Collect all the inputs & subset by Rows
#genes.Selected <- toupper(genes.Selected) # can't use it as some genes contains lowerletters
genesFromList <- unlist(strsplit(input$genesLists,","))
genes.Selected <- unlist(strsplit(input$SearchCrit," "))
if(input$SearchCrit == '' && input$genesLists == 0){
TableByRow <- TableByColumns
} else if(input$SearchCrit != '' && input$genesLists != 0){
TableByList <- subset(TableByColumns, TableByColumns$GeneName %in% genesFromList)
TableByRow <- subset(TableByList, TableByList$GeneName %in% genes.Selected)
} else if(input$SearchCrit != '' && input$genesLists == 0){
TableByRow <- subset(TableByColumns, TableByColumns$GeneName %in% genes.Selected)
} else if(input$SearchCrit == '' && input$genesLists != 0) {
TableByRow <- subset(TableByColumns, TableByColumns$GeneName %in% genesFromList)
}
return(TableByRow)
})
}
Is that what you are trying to achieve ?
Filter samples that match your attributes based on your metadata and display gene expressions only for these samples ?
library(shiny)
library(dplyr)
ui <- fluidPage(
titlePanel("mtcars"),
sidebarLayout(
sidebarPanel(
selectInput("vs",
label = "vs",
choices = c(0, 1),
selected = NULL,
multiple = TRUE),
selectInput("carb",
label = "carb",
choices = c(1, 2, 3, 4, 6, 8),
selected = NULL,
multiple = TRUE),
selectInput("gear",
label = "gear",
choices = c(3, 4, 5),
selected = NULL,
multiple = TRUE)
),
mainPanel(
tabsetPanel(
tabPanel("Expression values", tableOutput("mainTable")),
tabPanel("ID filtering", tableOutput("table"))
)
)
)
)
server <- function(input, output) {
samples.df <- data.frame(ID = paste0("ID", as.character(round(runif(nrow(mtcars),
min = 0,
max = 100 * nrow(mtcars))))),
gear = as.factor(mtcars$gear),
carb = as.factor(mtcars$carb),
vs = as.factor(mtcars$vs))
values.df <- cbind(paste0("Feature", 1:20),
as.data.frame(matrix(runif(20 * nrow(samples.df)), nrow = 20)))
colnames(values.df) <- c("Feature", as.character(samples.df$ID))
vs.values <- reactive({
if (is.null(input$vs)) {
return(c(0, 1))
} else {
return(input$vs)
}
})
carb.values <- reactive({
if (is.null(input$carb)) {
return(c(1, 2, 3, 4, 6, 8))
} else {
return(input$carb)
}
})
gear.values <- reactive({
if (is.null(input$gear)) {
return(c(3, 4, 5))
} else {
return(input$gear)
}
})
filtered.samples.df <- reactive({
return(samples.df %>% filter(gear %in% gear.values(),
vs %in% vs.values(),
carb %in% carb.values()))
})
filtered.values.df <- reactive({
selected.samples <- c("Feature", names(values.df)[names(values.df) %in% filtered.samples.df()$ID])
return(values.df %>% select(selected.samples))
})
output$mainTable <- renderTable({
filtered.values.df()
})
output$table <- renderTable({
filtered.samples.df()
})
}
shinyApp(ui = ui, server = server)
You can try something like this, where we loop over the inputs and subset on the according column if the input is not null.
Hope this helps!
library(shiny)
ui <- fluidPage(
selectizeInput('mpg','mpg:',unique(mtcars$mpg),multiple=T),
selectizeInput('cyl','cyl:',unique(mtcars$cyl),multiple=T),
selectizeInput('gear','gear:',unique(mtcars$gear),multiple=T),
selectizeInput('carb','carb:',unique(mtcars$carb),multiple=T),
tableOutput('mytable')
)
server <- function(input,output)
{
output$mytable <- renderTable({
df = mtcars
select_inputs = c('mpg','cyl','gear','carb')
for (inp in select_inputs)
{
if(!is.null(input[[inp]]))
{
df = df[df[[inp]] %in% input[[inp]],]
}
}
df
})
}
shinyApp(ui,server)