I'm trying to create a shiny app as a practice planner where users can select which drills they are going to do and how long they will do each drill and the app then shows them the total meters covered for the whole practice. Now I'm trying to calculate the total values of meters covered during a session based on the drills selected and the number of minutes selected for each drill. However my total is always equal to 0 even though it works for calculating each drill separately. Could someone help me figure out what I'm doing wrong please. Below is my code with sample data.
library(shiny)
library(dplyr)
# MyData <- read.csv("/Users/sonamoravcikova/Desktop/ShinyTest/ForShiny1.csv")
MyData <- structure(list(Drill = c("GP Warm Up", "5v2 Rondo", "11v11", "10v6 Drop
Behind Ball"), PlayerLoadPerMinute = c(7.72949670665213, 6.49382926701571,
9.67483408668731, 5.86770863636364), MetersPerMinute = c(69.9524820610687,
45.823744973822, 95.9405092879257, 58.185375), class = "data.frame", row.names
= c(NA, -4L)))
# Define UI ----
ui <- fluidPage(
titlePanel("Practice Planner"),
sidebarLayout(
sidebarPanel(
#Select number of drills
numericInput("num", h3("Number of Drills"), value = 1),
textOutput("MpM_Total")
),
mainPanel(
#Show boxes for the number of drill selected and select drill type
selectInput("DrillName1",
label = "Choose a Drill:",
choices = unique(MyData$Drill),
selected = NULL,
multiple = FALSE),
sliderInput("slider1",
label = h3("Slider"),
min = 0,
max = 60,
value = 0),
textOutput("MpM1"),
br(),
conditionalPanel(
condition = "input.num > '1'",
selectInput("DrillName2",
label = "Choose a Drill:",
choices = unique(MyData$Drill),
selected = NULL,
multiple = FALSE),
sliderInput("slider2",
label = h3("Slider"),
min = 0,
max = 60,
value = 0),
textOutput("MpM2")),
br(),
conditionalPanel(
condition = "input.num > '2'",
selectInput("DrillName3",
label = "Choose a Drill:",
choices = unique(MyData$Drill),
selected = NULL,
multiple = FALSE),
sliderInput("slider3",
label = h3("Slider"),
min = 0,
max = 60,
value = 0),
textOutput("MpM3"))
)
)
)
# Define server logic ----
server <- function(input, output, session) {
#Calculate number of meters covered
lapply(1:10, function(x) {
MetersPerMin <- reactive({
chosendrill <- input[[paste0("DrillName",x)]]
MpM <- MyData %>%
distinct(MetersPerMinute, .keep_all = T)
MpM_text <- (MpM$MetersPerMinute[MpM$Drill == chosendrill]) * (input[[paste0("slider",x)]])
})
output[[paste0("MpM", x)]] <- renderText({
paste0("Meters covered: ", MetersPerMin())
})
MpM_Sum <- reactive({
sum(MetersPerMin())
})
output$MpM_Total <- renderText({
paste("Total Meters Covered", MpM_Sum())
})
})
}
# Create Shiny app ----
shinyApp(ui = ui, server = server)
library(shiny)
library(dplyr)
MyData <- data.frame(Drill = c('GP Warm Up', '5v2 Rondo', '11v11', '10v6 Drop Behind Ball'),
PlayerLoadPerMinute = c(7.72949670665213, 6.49382926701571, 9.67483408668731, 5.86770863636364),
MetersPerMinute = c(69.9524820610687, 45.823744973822, 95.9405092879257, 58.185375))
MpM <- MyData %>%
distinct(MetersPerMinute, .keep_all = T)
# Define UI ----
ui <- fluidPage(
titlePanel('Practice Planner'),
sidebarLayout(
sidebarPanel(
#Select number of drills
numericInput('num', h3('Number of Drills'), value = 1),
textOutput('MpM_Total')
),
mainPanel(
#Show boxes for the number of drill selected and select drill type
selectInput('DrillName1',
label = 'Choose a Drill:',
choices = unique(MyData$Drill),
selected = NULL,
multiple = FALSE),
sliderInput('slider1',
label = h3('Slider'),
min = 0,
max = 60,
value = 0),
textOutput('MpM1'),
br(),
conditionalPanel(
condition = 'input.num > "1"',
selectInput('DrillName2',
label = 'Choose a Drill:',
choices = unique(MyData$Drill),
selected = NULL,
multiple = FALSE),
sliderInput('slider2',
label = h3('Slider'),
min = 0,
max = 60,
value = 0),
textOutput('MpM2')
),
br(),
conditionalPanel(
condition = 'input.num > "2"',
selectInput('DrillName3',
label = 'Choose a Drill:',
choices = unique(MyData$Drill),
selected = NULL,
multiple = FALSE),
sliderInput('slider3',
label = h3('Slider'),
min = 0,
max = 60,
value = 0),
textOutput('MpM3')
)
)
)
)
# Define server logic ----
server <- function(input, output, session) {
MetersPerMin <- reactive({
idx <- input$num
if (idx < 1) {
idx <- 1
} else if (idx > 3) {
idx <- 3
}
mpms <- sapply(1:idx, function(x) {
chosendrill <- input[[ paste0('DrillName', x) ]]
mpm <- (MpM$MetersPerMinute[ MpM$Drill == chosendrill ]) * (input[[ paste0('slider', x) ]])
output[[ paste0('MpM', x) ]] <- renderText(paste0('Meters covered: ', mpm))
mpm
})
mpms
})
output$MpM_Total <- renderText({
paste('Total Meters Covered', sum(MetersPerMin()))
})
}
# Create Shiny app ----
shinyApp(ui = ui, server = server)
EDIT: I have simplified the application and make it all the code reproducible.
EDIT 2: I just discovered that when I use the navBarPage I must click on Additional Parameters -> Colour. Then is coloured as expected.
I'm developing a shiny app which filters my genes and then plots a heatmap of the remaining genes. Recently, I have found shinyHeatmaply package. I have download their global, UI and Server, and when I try it on my own computer they work as expected. Unfortunately, when I try to combine my filter app and their heatmap using navbarPage, the last one is not rending properly.
I have created a minimalist example adding the shinyheatmap to the second tabPanel of navbarPage in the https://shiny.rstudio.com/gallery/shiny-theme-selector.html app, but I get the same grey render anyway.
Same mistake in a simpler application
The UI:
Navbar 1 belongs to the shinytheme application, whilst the content of Navbar 2 belongs to the shinyheatmaply
tagList(
shinythemes::themeSelector(),
navbarPage(
# theme = "cerulean", # <--- To use a theme, uncomment this
"shinythemes",
tabPanel("Navbar 1",
sidebarPanel(
fileInput("file", "File input:"),
textInput("txt", "Text input:", "general"),
sliderInput("slider", "Slider input:", 1, 100, 30),
tags$h5("Deafult actionButton:"),
actionButton("action", "Search"),
tags$h5("actionButton with CSS class:"),
actionButton("action2", "Action button", class = "btn-primary")
),
mainPanel(
tabsetPanel(
tabPanel("Tab 1",
h4("Table"),
tableOutput("table"),
h4("Verbatim text output"),
verbatimTextOutput("txtout"),
h1("Header 1"),
h2("Header 2"),
h3("Header 3"),
h4("Header 4"),
h5("Header 5")
),
tabPanel("Tab 2", "This panel is intentionally left blank"),
tabPanel("Tab 3", "This panel is intentionally left blank")
)
)
),
tabPanel("Navbar 2",
fluidPage(
sidebarLayout(
sidebarPanel(width=4,
h4('Data Selection'),
fileInput(inputId="mydata", label = "Import Data",multiple = T),
uiOutput('data'),
checkboxInput('showSample','Subset Data'),
conditionalPanel('input.showSample',uiOutput('sample')),
hr(),h4('Data Preprocessing'),
column(width=4,selectizeInput('transpose','Transpose',choices = c('No'=FALSE,'Yes'=TRUE),selected = FALSE)),
column(width=4,selectizeInput("transform_fun", "Transform", c(Identity=".",Sqrt='sqrt',log='log',Scale='scale',Normalize='normalize',Percentize='percentize',"Missing values"='is.na10', Correlation='cor'),selected = '.')),
uiOutput('annoVars'),
br(),hr(),h4('Row dendrogram'),
column(width=6,selectizeInput("distFun_row", "Distance method", c(Euclidean="euclidean",Maximum='maximum',Manhattan='manhattan',Canberra='canberra',Binary='binary',Minkowski='minkowski'),selected = 'euclidean')),
column(width=6,selectizeInput("hclustFun_row", "Clustering linkage", c(Complete= "complete",Single= "single",Average= "average",Mcquitty= "mcquitty",Median= "median",Centroid= "centroid",Ward.D= "ward.D",Ward.D2= "ward.D2"),selected = 'complete')),
column(width=12,sliderInput("r", "Number of Clusters", min = 1, max = 15, value = 2)),
#column(width=4,numericInput("r", "Number of Clusters", min = 1, max = 20, value = 2, step = 1)),
br(),hr(),h4('Column dendrogram'),
column(width=6,selectizeInput("distFun_col", "Distance method", c(Euclidean="euclidean",Maximum='maximum',Manhattan='manhattan',Canberra='canberra',Binary='binary',Minkowski='minkowski'),selected = 'euclidean')),
column(width=6,selectizeInput("hclustFun_col", "Clustering linkage", c(Complete= "complete",Single= "single",Average= "average",Mcquitty= "mcquitty",Median= "median",Centroid= "centroid",Ward.D= "ward.D",Ward.D2= "ward.D2"),selected = 'complete')),
column(width=12,sliderInput("c", "Number of Clusters", min = 1, max = 15, value = 2)),
#column(width=4,numericInput("c", "Number of Clusters", min = 1, max = 20, value = 2, step = 1)),
br(),hr(), h4('Additional Parameters'),
column(3,checkboxInput('showColor','Color')),
column(3,checkboxInput('showMargin','Layout')),
column(3,checkboxInput('showDendo','Dendrogram')),
hr(),
conditionalPanel('input.showColor==1',
hr(),
h4('Color Manipulation'),
uiOutput('colUI'),
sliderInput("ncol", "Set Number of Colors", min = 1, max = 256, value = 256),
checkboxInput('colRngAuto','Auto Color Range',value = T),
conditionalPanel('!input.colRngAuto',uiOutput('colRng'))
),
conditionalPanel('input.showDendo==1',
hr(),
h4('Dendrogram Manipulation'),
selectInput('dendrogram','Dendrogram Type',choices = c("both", "row", "column", "none"),selected = 'both'),
selectizeInput("seriation", "Seriation", c(OLO="OLO",GW="GW",Mean="mean",None="none"),selected = 'OLO'),
sliderInput('branches_lwd','Dendrogram Branch Width',value = 0.6,min=0,max=5,step = 0.1)
),
conditionalPanel('input.showMargin==1',
hr(),
h4('Widget Layout'),
column(4,textInput('main','Title','')),
column(4,textInput('xlab','X Title','')),
column(4,textInput('ylab','Y Title','')),
sliderInput('row_text_angle','Row Text Angle',value = 0,min=0,max=180),
sliderInput('column_text_angle','Column Text Angle',value = 45,min=0,max=180),
sliderInput("l", "Set Margin Width", min = 0, max = 200, value = 130),
sliderInput("b", "Set Margin Height", min = 0, max = 200, value = 40)
)
),
mainPanel(
tabsetPanel(
tabPanel("Heatmaply",
tags$a(id = 'downloadData', class = paste("btn btn-default shiny-download-link",'mybutton'), href = "", target = "_blank", download = NA, icon("clone"), 'Download Heatmap as HTML'),
tags$head(tags$style(".mybutton{color:white;background-color:blue;} .skin-black .sidebar .mybutton{color: green;}") ),
plotlyOutput("heatout",height='600px')
),
tabPanel("Data",
DT::dataTableOutput('tables')
)
)
)
)
)
),
tabPanel("Navbar 3", "This panel is intentionally left blank")
)
)
The server:
Regarding to the server, first two output correspond to the shinytheme and the others belong to shinyheatmaply
d=data(package='datasets')$results[,'Item']
d=d[!grepl('[\\()]',d)]
d=d[!d%in%c('UScitiesD','eurodist','sleep','warpbreaks')]
d=d[unlist(lapply(d,function(d.in) eval(parse(text=paste0('ncol(as.data.frame(datasets::',d.in,'))')))))>1]
d=d[-which(d=='mtcars')]
d=c('mtcars',d)
server <- shinyServer(function(input, output,session) {
####This to output belongs to the shinytheme application####
output$txtout <- renderText({
paste(input$txt, input$slider, format(input$date), sep = ", ")
})
output$table <- renderTable({
head(cars, 4)
})
#######################################################
#Up to here the code belongs to shinyheatmaply
output$txtout <- renderText({
paste(input$txt, input$slider, format(input$date), sep = ", ")
})
output$table <- renderTable({
head(cars, 4)
})
TEMPLIST<-new.env()
TEMPLIST$d<-d
#Annotation Variable UI ----
observeEvent(data.sel(),{
output$annoVars<-renderUI({
data.in=data.sel()
NM=NULL
if(any(sapply(data.in,class)=='factor')){
NM=names(data.in)[which(sapply(data.in,class)=='factor')]
}
column(width=4,
selectizeInput('annoVar','Annotation',choices = names(data.in),selected=NM,multiple=T,options = list(placeholder = 'select columns',plugins = list("remove_button")))
)
})
#Sampling UI ----
output$sample<-renderUI({
list(
column(4,textInput(inputId = 'setSeed',label = 'Seed',value = sample(1:10000,1))),
column(4,numericInput(inputId = 'selRows',label = 'Number of Rows',min=1,max=pmin(500,nrow(data.sel())),value = pmin(500,nrow(data.sel())))),
column(4,selectizeInput('selCols','Columns Subset',choices = names(data.sel()),multiple=T))
)
})
})
#Data Selection UI ----
output$data=renderUI({
if(!is.null(input$mydata)) TEMPLIST$d=c(input$mydata$name,TEMPLIST$d)
selData=head(TEMPLIST$d,1)
selectInput("data","Select Data",TEMPLIST$d,selected = selData)
})
#Color Pallete UI ----
output$colUI<-renderUI({
colSel='Vidiris'
if(input$transform_fun=='cor') colSel='RdBu'
if(input$transform_fun=='is.na10') colSel='grey.colors'
selectizeInput(inputId ="pal", label ="Select Color Palette",
choices = c('Vidiris (Sequential)'="viridis",
'Magma (Sequential)'="magma",
'Plasma (Sequential)'="plasma",
'Inferno (Sequential)'="inferno",
'Magma (Sequential)'="magma",
'Magma (Sequential)'="magma",
'RdBu (Diverging)'="RdBu",
'RdYlBu (Diverging)'="RdYlBu",
'RdYlGn (Diverging)'="RdYlGn",
'BrBG (Diverging)'="BrBG",
'Spectral (Diverging)'="Spectral",
'BuGn (Sequential)'='BuGn',
'PuBuGn (Sequential)'='PuBuGn',
'YlOrRd (Sequential)'='YlOrRd',
'Heat (Sequential)'='heat.colors',
'Grey (Sequential)'='grey.colors'),
selected=colSel)
})
#Manual Color Range UI ----
output$colRng=renderUI({
if(!is.null(data.sel())) {
rng=range(data.sel(),na.rm = TRUE)
}else{
rng=range(mtcars) # TODO: this should probably be changed
}
# sliderInput("colorRng", "Set Color Range", min = round(rng[1],1), max = round(rng[2],1), step = .1, value = rng)
n_data = nrow(data.sel())
min_min_range = ifelse(input$transform_fun=='cor',-1,-Inf)
min_max_range = ifelse(input$transform_fun=='cor',1,rng[1])
min_value = ifelse(input$transform_fun=='cor',-1,rng[1])
max_min_range = ifelse(input$transform_fun=='cor',-1,rng[2])
max_max_range = ifelse(input$transform_fun=='cor',1,Inf)
max_value = ifelse(input$transform_fun=='cor',1,rng[2])
a_good_step = 0.1 # (max_range-min_range) / n_data
list(
numericInput("colorRng_min", "Set Color Range (min)", value = min_value, min = min_min_range, max = min_max_range, step = a_good_step),
numericInput("colorRng_max", "Set Color Range (max)", value = max_value, min = max_min_range, max = max_max_range, step = a_good_step)
)
})
#Import/Select Data ----
data.sel=eventReactive(input$data,{
if(input$data%in%d){
eval(parse(text=paste0('data.in=as.data.frame(datasets::',input$data,')')))
}else{
data.in=importSwitch(input$mydata[input$mydata$name%in%input$data,])
}
data.in=as.data.frame(data.in)
# data.in=data.in[,sapply(data.in,function(x) class(x))%in%c('numeric','integer')] # no need for this
return(data.in)
})
#Building heatmaply ----
interactiveHeatmap<- reactive({
data.in=data.sel()
if(input$showSample){
if(!is.null(input$selRows)){
set.seed(input$setSeed)
if((input$selRows >= 2) & (input$selRows < nrow(data.in))){
# if input$selRows == nrow(data.in) then we should not do anything (this save refreshing when clicking the subset button)
if(length(input$selCols)<=1) data.in=data.in[sample(1:nrow(data.in),pmin(500,input$selRows)),]
if(length(input$selCols)>1) data.in=data.in[sample(1:nrow(data.in),pmin(500,input$selRows)),input$selCols]
}
}
}
# ss_num = sapply(data.in,function(x) class(x)) %in% c('numeric','integer') # in order to only transform the numeric values
if(length(input$annoVar)>0){
if(all(input$annoVar%in%names(data.in)))
data.in <- data.in%>%mutate_at(funs(factor),.vars=vars(input$annoVar))
}
ss_num = sapply(data.in, is.numeric) # in order to only transform the numeric values
if(input$transpose) data.in=t(data.in)
if(input$transform_fun!='.'){
if(input$transform_fun=='is.na10'){
updateCheckboxInput(session = session,inputId = 'showColor',value = T)
data.in[, ss_num]=is.na10(data.in[, ss_num])
}
if(input$transform_fun=='cor'){
updateCheckboxInput(session = session,inputId = 'showColor',value = T)
updateCheckboxInput(session = session,inputId = 'colRngAuto',value = F)
data.in=cor(data.in[, ss_num],use = "pairwise.complete.obs")
}
if(input$transform_fun=='log') data.in[, ss_num]= apply(data.in[, ss_num],2,log)
if(input$transform_fun=='sqrt') data.in[, ss_num]= apply(data.in[, ss_num],2,sqrt)
if(input$transform_fun=='normalize') data.in=heatmaply::normalize(data.in)
if(input$transform_fun=='scale') data.in[, ss_num] = scale(data.in[, ss_num])
if(input$transform_fun=='percentize') data.in=heatmaply::percentize(data.in)
}
if(!is.null(input$tables_true_search_columns))
data.in=data.in[activeRows(input$tables_true_search_columns,data.in),]
if(input$colRngAuto){
ColLimits=NULL
}else{
ColLimits=c(input$colorRng_min, input$colorRng_max)
}
distfun_row = function(x) dist(x, method = input$distFun_row)
distfun_col = function(x) dist(x, method = input$distFun_col)
hclustfun_row = function(x) hclust(x, method = input$hclustFun_row)
hclustfun_col = function(x) hclust(x, method = input$hclustFun_col)
p <- heatmaply(data.in,
main = input$main,xlab = input$xlab,ylab = input$ylab,
row_text_angle = input$row_text_angle,
column_text_angle = input$column_text_angle,
dendrogram = input$dendrogram,
branches_lwd = input$branches_lwd,
seriate = input$seriation,
colors=eval(parse(text=paste0(input$pal,'(',input$ncol,')'))),
distfun_row = distfun_row,
hclustfun_row = hclustfun_row,
distfun_col = distfun_col,
hclustfun_col = hclustfun_col,
k_col = input$c,
k_row = input$r,
limits = ColLimits) %>%
layout(margin = list(l = input$l, b = input$b, r='0px'))
p$elementId <- NULL
p
})
#Render Plot ----
observeEvent(input$data,{
output$heatout <- renderPlotly({
if(!is.null(input$data))
interactiveHeatmap()
})
})
#Render Data Table ----
output$tables=DT::renderDataTable(data.sel(),server = T,filter='top',
extensions = c('Scroller','FixedHeader','FixedColumns','Buttons','ColReorder'),
options = list(
dom = 't',
buttons = c('copy', 'csv', 'excel', 'pdf', 'print','colvis'),
colReorder = TRUE,
scrollX = TRUE,
fixedColumns = TRUE,
fixedHeader = TRUE,
deferRender = TRUE,
scrollY = 500,
scroller = TRUE
))
#Clone Heatmap ----
observeEvent({interactiveHeatmap()},{
h<-interactiveHeatmap()
l<-list(main = input$main,xlab = input$xlab,ylab = input$ylab,
row_text_angle = input$row_text_angle,
column_text_angle = input$column_text_angle,
dendrogram = input$dendrogram,
branches_lwd = input$branches_lwd,
seriate = input$seriation,
colors=paste0(input$pal,'(',input$ncol,')'),
distfun_row = input$distFun_row,
hclustfun_row = input$hclustFun_row,
distfun_col = input$distFun_col,
hclustfun_col = input$hclustFun_col,
k_col = input$c,
k_row = input$r,
limits = paste(c(input$colorRng_min, input$colorRng_max),collapse=',')
)
#l=l[!l=='']
l=data.frame(Parameter=names(l),Value=do.call('rbind',l),row.names = NULL,stringsAsFactors = F)
l[which(l$Value==''),2]='NULL'
paramTbl=print(xtable::xtable(l),type = 'html',include.rownames=FALSE,print.results = F,html.table.attributes = c('border=0'))
h$width='100%'
h$height='800px'
s<-tags$div(style="position: relative; bottom: 5px;",
HTML(paramTbl),
tags$em('This heatmap visualization was created using',
tags$a(href="https://github.com/yonicd/shinyHeatmaply/",target="_blank",'shinyHeatmaply'),
Sys.time()
)
)
output$downloadData <- downloadHandler(
filename = function() {
paste("heatmaply-", gsub(' ','_',Sys.time()), ".html", sep="")
},
content = function(file) {
libdir <- paste(tools::file_path_sans_ext(basename(file)),"_files", sep = "")
htmltools::save_html(htmltools::browsable(htmltools::tagList(h,s)),file=file,libdir = libdir)
if (!htmlwidgets:::pandoc_available()) {
stop("Saving a widget with selfcontained = TRUE requires pandoc. For details see:\n",
"https://github.com/rstudio/rmarkdown/blob/master/PANDOC.md")
}
htmlwidgets:::pandoc_self_contained_html(file, file)
unlink(libdir, recursive = TRUE)
}
)
})
#End of Code ----
})
Thanks in advance to the hero who solves this problem.
Best rewards, Daniel.
The problem was a conflict between a conditional panel (which uses js) and the navbar page, for any reason default parameters were not read, thus autocoloring which should be enabled wasn't. I just removed this conditional panel and set always its options.