Related
I’m super new to RShiny and I’m trying to create an app that will calculate the total meters players will run during practice. I have a csv file in which I have meters per minute for each drill and I want this app to calculate the total based on the drills selected and the time selected.
And I don’t know how to pull the data from the csv file for the specific drill selected and multiply it by the number of minutes selected.
This is what I have right now but it doesn’t work.
ui <- fluidPage(
titlePanel("Practice Planner"),
sidebarLayout(
sidebarPanel(
numericInput("num", h3("Number of Drills"), value = 1)
),
mainPanel(
selectInput("DrillName",
label = "Choose a Drill:",
choices = unique(MyData$Drill),
selected = NULL,
multiple = FALSE),
sliderInput("slider11",
label = h3("Slider"),
min = 0,
max = 60,
value = 0),
conditionalPanel(
condition = "input.num > '1'",
selectInput("Drill Name",
label = "Choose a Drill:",
choices = unique(MyData$Drill),
selected = NULL,
multiple = FALSE),
sliderInput("slider1",
label = h3("Slider"),
min = 0,
max = 60,
value = 0)),
conditionalPanel(
condition = "input.num > '2'",
selectInput("Drill Name",
label = "Choose a Drill:",
choices = unique(MyData$Drill),
selected = NULL,
multiple = FALSE),
sliderInput("slider1",
label = h3("Slider"),
min = 0,
max = 60,
value = 0)),
conditionalPanel(
condition = "input.num > '3'",
selectInput("Drill Name",
label = "Choose a Drill:",
choices = unique(MyData$Drill),
selected = NULL,
multiple = FALSE),
sliderInput("slider1",
label = h3("Slider"),
min = 0,
max = 60,
value = 0)),
conditionalPanel(
condition = "input.num > '4'",
selectInput("Drill Name",
label = "Choose a Drill:",
choices = unique(MyData$Drill),
selected = NULL,
multiple = FALSE),
sliderInput("slider1",
label = h3("Slider"),
min = 0,
max = 60,
value = 0)),
conditionalPanel(
condition = "input.num > '5'",
selectInput("Drill Name",
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")
)
)
)
# Define server logic ----
server <- function(input, output, session) {
output$MpM1 <- renderText({
chosendrill <- (input$DrillName)
MpM <- unique.data.frame(MyData$MetersPerMinute)
MpM1 <- (MpM[[chosendrill]]) * (input$slider11)
})
}
# Create Shiny app ----
shinyApp(ui = ui, server = server)
I'm not certain of a lot of details of what you are looking for, and I don't have your data set, but I think I was able to come up with a relatively simple update of your app to hopefully show how to make it work. First, I made a test dataset, which I just used mtcars and renamed some columns to match yours. Then I wrote the file, then read it in, so that way I can show how one can read data for a shiny app. Otherwise, if you are looking to have more dynamic read in of data, refer to #r2evans comment on shiny::fileInput, or maybe even a reactiveFileReader.
The next thing I did was update the inputId of many of your inputs, as you used the same name for different inputs. As I expect you want each input to do something different, a different inputId is needed. Additionally, I put a new textOutput for each conditionalPanel, so that each can display their own data. I also added some spacing for visual clarity with br().
For the server side, I changed a couple of things. First, I have never used unique.data.frame, but I have used distinct from dplyr, so I used that instead. Then, I changed your MpM_text, I'm nto really certain what exactly you wanted to happen, but this shows how to use rows that match the input and to use them to multiply against something else. This was then output in a paste0.
I also did a repeat of this for the other 5 drills that were in the conditionalPanel, just as a little show of how you can repeat the calculations with different inputs/outputs. Again, I'm not sure what the precise nature of your program/data, but hopefully this helps to point you in the right direction. If you are posting on stack in the future, I'd suggest making your code as simple as possible that will show whatever error you are seeing, including any necessary data so that the viewers can easily recreate your issue. Best of luck, shiny can be a pain sometimes to figure out, but I've really enjoyed using it over the years and so I hope you have success yourself!
library(shiny)
library(dplyr)
MyData<-mtcars%>% #Since I don't have your dataset, I made my own using mtcars
rename(Drill = cyl, #Renaming column names to match yours
MetersPerMinute = mpg)
write.table(MyData, "Test.csv") #Writing it into a csv so I can demonstrate how to read and use the data from a csv
MyData<-read.table("Test.csv") #reading the csv
ui <- fluidPage(
titlePanel("Practice Planner"),
sidebarLayout(
sidebarPanel(
numericInput("num", h3("Number of Drills"), value = 1)
),
mainPanel(
selectInput("DrillName",
label = "Choose a Drill:",
choices = unique(MyData$Drill),
selected = NULL,
multiple = FALSE),
sliderInput("slider11",
label = h3("Slider"),
min = 0,
max = 60,
value = 0),
textOutput("MpM1"),
br(), #Spacing for clarity
conditionalPanel(
condition = "input.num > '1'",
selectInput("DrillName1", #name of the select input should differ if expecting to be used separately, changed to `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("MpM2")),
br(), #Spacing for clarity
conditionalPanel(
condition = "input.num > '2'",
selectInput("DrillName2", #name of the select input should differ if expecting to be used separately, changed to `DrillName2`
label = "Choose a Drill:",
choices = unique(MyData$Drill),
selected = NULL,
multiple = FALSE),
sliderInput("slider2", #name of the sliderinput should differ if expecting to be used separately, changed to 2
label = h3("Slider"),
min = 0,
max = 60,
value = 0),
textOutput("MpM3")),
br(), #Spacing for clarity
conditionalPanel(
condition = "input.num > '3'",
selectInput("DrillName3", #name of the select input should differ if expecting to be used separately, changed to `DrillName3`
label = "Choose a Drill:",
choices = unique(MyData$Drill),
selected = NULL,
multiple = FALSE),
sliderInput("slider3", #name of the sliderinput should differ if expecting to be used separately, changed to 3
label = h3("Slider"),
min = 0,
max = 60,
value = 0),
textOutput("MpM4")),
br(), #Spacing for clarity
conditionalPanel(
condition = "input.num > '4'",
selectInput("DrillName4", #name of the select input should differ if expecting to be used separately, changed to `DrillName4`
label = "Choose a Drill:",
choices = unique(MyData$Drill),
selected = NULL,
multiple = FALSE),
sliderInput("slider4", #name of the sliderinput should differ if expecting to be used separately, changed to 4
label = h3("Slider"),
min = 0,
max = 60,
value = 0),
textOutput("MpM5")),
br(), #Spacing for clarity
conditionalPanel(
condition = "input.num > '5'",
selectInput("DrillName5", #name of the select input should differ if expecting to be used separately, changed to `DrillName5`
label = "Choose a Drill:",
choices = unique(MyData$Drill),
selected = NULL,
multiple = FALSE),
sliderInput("slider5", #name of the sliderinput should differ if expecting to be used separately, changed to 5
label = h3("Slider"),
min = 0,
max = 60,
value = 0),
textOutput("MpM6"))
)
)
)
# Define server logic ----
server <- function(input, output, session) {
output$MpM1 <- renderText({
chosendrill <- (input$DrillName)
# MpM <- unique.data.frame(MyData$MetersPerMinute) #This doesn't work for me. I've never used unique.data.frame though.
# Instead I'll use distinct from dplyr, which is considerably faster, according to dplyr!
MpM <- MyData%>%
distinct(MetersPerMinute, .keep_all = T)
MpM_text <- (MpM$MetersPerMinute[MpM$Drill == chosendrill]) * (input$slider11)
#I'm not certain what the data looks like, or what the result you want should look like
# In the mtcars dataset I used for example, it has multiple matches to each cyl, or "Drill", so this will put multiple outputs
paste0("Drill Meters per minute * slider: ", paste0(MpM_text, collapse = " "))
})
lapply(2:6, function(x) { #This is just showing how to repeat the calculations for multiple sliders
output[[paste0("MpM", x)]] <- renderText({
chosendrill <- input[[paste0("DrillName",x-1)]]
MpM <- MyData%>%
distinct(MetersPerMinute, .keep_all = T)
MpM_text <- (MpM$MetersPerMinute[MpM$Drill == chosendrill]) * (input[[paste0("slider",x-1)]])
paste0("Drill Meters per minute * slider: ", paste0(MpM_text, collapse = " "))
})
})
}
# Create Shiny app ----
shinyApp(ui = ui, server = server)
I'm pretty new to shiny and am struggling on how to use check boxes to update values in a bar chart. The idea I'm after is when a user ticks on a check box, a numerical value is generated that will be added to an aggregate from other inputs to make a bar chart. Here is the code I have gotten to work so far:
library(shiny)
ui <- fluidPage(
titlePanel("TCO Calculator"),
mainPanel(
sidebarPanel(
helpText("Product 1 information:"),
numericInput(
inputId = "price_1",
label = "Purchase Price",
value = "0",
min = 0,
width = '50%'
),
numericInput(
inputId = "install_1",
label = "Installation cost",
value = "0",
min = 0,
width = '50%'
),
selectInput("disposal_1", "Disposal Cost",
choices = list(Buyback = (10),
Dump = (30),
Reuse = (5)),
width = '50%'),
checkboxGroupInput("maint_1", "Maintenance:",
choices = c("Waxing",
"Stripping", "Burnishing"),
selected = NULL)
),
sidebarPanel(
helpText("Product 2 information:"),
numericInput(
inputId = "price_2",
label = "Purchase Price",
value = "0",
min = 0,
width = '50%'
),
numericInput(
inputId = "install_2",
label = "Installation cost",
value = "0",
min = 0,
width = '50%'
),
# make list?
selectInput("disposal_2", "Disposal Cost",
choices = list(Buyback = (10),
Dump = (30),
Reuse = (5)),
width = '50%'),
checkboxGroupInput("maint_2", "Maintenance:",
choices = NULL,
selected = NULL,
inline = FALSE,
width = NULL,
choiceNames = c("Waxing",
"Stripping", "Burnishing"),
choiceValues = c(10, 20, 40))
),
plotOutput("costPlot")))
server <- function(input, output, session) {
# aggregate inputs into reactive bar chart values.
select_price <- reactive({
c(input$price_1 + input$install_1
+ as.numeric(input$disposal_1),
input$price_2 + input$install_2 +
as.numeric(input$disposal_2))
})
# Bar chart.
my_bar <- output$costPlot <- renderPlot({
barplot(select_price(),
beside = T,
border=F,
las=2 ,
col=c(rgb(0.3,0.1,0.4,0.6) ,
rgb(0.3,0.5,0.4,0.6)) ,
space = 3,
ylab = "Total cost per square foot, US Dollar")
abline(v=c(4.9 , 6.1) , col="grey")
legend("top", legend = c("Product 1", "Product 2" ),
col = c(rgb(0.3,0.1,0.4,0.6),
rgb(0.3,0.5,0.4,0.6)),
bty = "n",
pch=20 , pt.cex = 4,
cex = 1.6, horiz = FALSE,
inset = c(0.05, 0.05))
my_bar
})
}
shinyApp(ui = ui, server = server)
I've been successful with the numericInput and selectInput stuff so far, I am having trouble putting together a concise way to include check boxes (with corresponding numeric values) into a reactive function that I can path into select_price(), like I have done with the numeric and selectBox stuff. Things go sideways when I try to map from other examples. I feel like there is an elegant, or in least working solution that exists. Any insight towards how to solve this would be so appreciated, thanks!
I am not sure whether this entirely solves all your problems but try this:
For maint_2, you correctly separate choiceNames and choiceValues. For maint_1 you dont't
checkboxGroupInput("maint_1", "Maintenance:",
choices = NULL,
selected = NULL,
choiceNames = c("Waxing", "Stripping", "Burnishing"),
choiceValues = c(10, 20, 40))
Then you can add input$maint_1 and input$maint_2 to your reactive (also wrapped in as.numeric(). I also use sum for + as you don't have a default for input$maint_1 and input$maint_2. sum evaluates this to 0 while + throws an error.
select_price <- reactive({
c(sum(input$price_1, input$install_1, as.numeric(input$disposal_1), as.numeric(input$maint_1)),
sum(input$price_2, input$install_2, as.numeric(input$disposal_2), as.numeric(input$maint_1)))
})
I have four user inputs in my ShinyApp such that:
The first input (total_price) is always present
Optional input for rrsp which allows users to input a value (max 35,000)
Optional input for fthbi which allows users to select a value up to 10%
Other payment for cash which allows user to input a value
In my code, total_input and cash are numericInput, rrsp and fthbi are checkBoxInput + conditionalPanel
total_price is independent of the other three. However, the other other three summed up and can not exceed 20% of total_price i.e. rrsp + fthbi * total_price + cash <= total_price*0.2. How can I achieve this - basically as any of the inputs change, the limits of the remaining inputs (in the order mentioned above) should change as well.
CODE
ui <- fluidPage(
titlePanel(
'My App'
),
sidebarLayout(
sidebarPanel = sidebarPanel(
numericInput(
inputId = 'total_price',
label = 'Total Price',
value = 200000,
min = 200000
),
# Use RRSP for down-payment
checkboxInput(
inputId = 'use_rrsp',
label = 'Use RRSP?',
value = F
),
# If using RRSP, select amount to use
conditionalPanel(
condition = "input.use_rrsp == true",
numericInput(
inputId = 'rrsp', label = 'RRSP Amount?',value = 25000, min = 0, 35000
)
),
# Use first time home buyer incentive?
checkboxInput(
inputId = 'use_fthbi',
label = 'Use FTHBI?',
value = F
),
# If using FTHBI, select % to use
conditionalPanel(
condition = "input.use_fthbi == true",
sliderInput(
inputId = 'fthbi', label = 'FTHBI Percent',
step = 1, min = 0, max = 10, value = 0, post = '%'
)
),
# Cash Downpayment
numericInput(
inputId = 'cash', label = 'Cash Payment', value = 0, min = 0, max = 40000
)
),
mainPanel = mainPanel(
textOutput('main_text')
)
)
)
server <- function(input, output, session){
output$main_text <- renderText({
sprintf('Sample Text')
})
}
shinyApp(ui, server)
I've tried playing around with updateSliderInput and reactiveUI but haven't been successful..
Update
Here's the logic:
by default rrsp and ftbhi are not selected, so cash can be set to 20% of total_price
Once rrsp is selected, it should begin with a default value of 25000. The max. value for rrsp is 35000 which is less than 20% of the min. allowable total_value. If some value for cash is selected that would bring rrsp + cash > total_price, the cash value should be updated such taht the total is 20% max.
Once ftbhi is selected, the default value should be zero (updated code now). The max. value for this should be updated based on the rrsp value (if already selected) else it should be 10%.
cash should get updated as other values are selected, input.
Aou are on the right track in using the update* functions. I am not going to implement the complete logic yet the snippet below should point you in the right direction:
# Basic usage
library("shiny")
library(shinyWidgets)
ui <- fluidPage(
titlePanel(
'My App'
),
sidebarLayout(
sidebarPanel = sidebarPanel(
numericInput(
inputId = 'total_price',
label = 'Total Price',
value = 200000,
min = 200000
),
# Use RRSP for down-payment
checkboxInput(
inputId = 'use_rrsp',
label = 'Use RRSP?',
value = F
),
# If using RRSP, select amount to use
conditionalPanel(
condition = "input.use_rrsp == true",
numericInput(
inputId = 'rrsp', label = 'RRSP Amount?',value = 25000, min = 0, 35000
)
),
# Use first time home buyer incentive?
checkboxInput(
inputId = 'use_fthbi',
label = 'Use FTHBI?',
value = F
),
# If using FTHBI, select % to use
conditionalPanel(
condition = "input.use_fthbi == true",
sliderInput(
inputId = 'fthbi', label = 'FTHBI Percent',
step = 1, min = 0, max = 10, value = 0, post = '%'
)
),
# Cash Downpayment
numericInput(
inputId = 'cash', label = 'Cash Payment', value = 0, min = 0, max = 40000
)
),
mainPanel = mainPanel(
textOutput('main_text')
)
)
)
server <- function(input, output, session){
output$main_text <- renderText({
sprintf('Sample Text')
})
observe({
# check that the input exists, is not null etc. check ?req()
req(input$cash)
if(input$cash > 0)
updateSliderInput(session = session,
inputId = 'fthbi',
max = round(40000 / input$cash))
})
}
shinyApp(ui, server)
Just wrap your update function inside of observe. However, you should be carefull that you do not implement a infinite loop. In this case it is an option to determine each value, safe it in reactiveValues and use these to update your inputs.
EDIT: Updated with a slightly better code.
I'm working on a very clunky UI that has branches of inputs....but I'm wondering if I should be doing it a different way, possibly on the server side? I want to progress down through the inputs as each one is selected, and to not show the next input until the previous is set. Ultimately each decision tree leads to a data table being displayed from a server side SQL function. (I created two similar functions, one which renders a table with a single select, and one that renders with multi select. Then the selected rows from the table will be sent back to the server along with the inputs via a submit button.
Ultimately I am trying to augment this app: https://shiny.rstudio.com/gallery/phylo-tree-view-subset.html
to have a branch that lets a user manipulate custom data, and then feed it back to the tree plotting function.
Should I be trying to do this sort of input structure on the server instead of UI? If so, is there a decent example somewhere? I'm struggling trying to see how the various demos would work with this.
I have a tree of inputs like so:
1) Do you have a file to upload? (yes/no)
a)Yes
1)File type (list)
2)Choose file (file explorer)
b)No
1)Choose single sample or multiple sample: (single/multiple)
a)Single
1)choose type: (otu/sequence)
a)anychoice
1)Abundance or Incidence? (abundance/incidence)
a)abundance
1)Slider for value between 0-10,000
2)Distance method (list of options)
3) Display datatable (select single row)
4) Submit button
a)Multiple
1)choose type: (otu/sequence)
a)anychoice
1)Abundance or Incidence? (abundance/incidence)
a)abundance
1)Slider for value between 0-10,000
2)Cluster method (list of options)
3)Distance method (list of options)
4) Display datatable (select multiple rows)
5) Submit button
Current code, its not giving all the functionality I want, but I'm still chipping away at it.
ui.R
library(shiny)
library(shinyjs)
library(shinyalert)
ui <- shinyUI(tagList(
useShinyalert(),
useShinyjs(),
navbarPage(
title = "Phylogenetic Tree Subsetting",
tabPanel(
title = "Explore Tree",
fluidRow(
class = "inputs",
column(
4,
selectInput(
inputId = "own_file",
label = "Do you already have a tree file to upload?",
choices = c("No" = "no",
"Yes" = "yes",
" " = " "),
selected = " "
)
),
conditionalPanel(condition = "input.own_file == 'yes'",
column(
4,
selectInput(
inputId = "file_type",
label = "Select Tree File Type:",
choices = c(
"Tree" = "tree",
"Beast" = "beast",
# "CodeML" = "codeml",
"CodeML mlc" = "mlc",
# "HYPHY" = "hyphy",
"jplace" = "jplace",
"MrBayes" = "mrbayes",
"NHX" = "nhx",
"rst (CODEML/BASEML)" = "rst",
"phylip" = "phylip",
# "r8s" = "r8s",
"RAxML" = "raxml"
),
selected = "tree"
)
),
column(
4,
fileInput(inputId = "upload_tree",
label = "Select Tree File:")
)),
conditionalPanel(
condition = "input.own_file == 'no'",
column(
4,
selectInput(
inputId = "tree_type",
label = "Would you like to view a single sample, or cluster multiple samples?",
choices = c(
"Single" = "single",
"Multiple" = "multiple",
" " = " "
),
selected = " "
)
),
conditionalPanel(
condition = "input.tree_type == 'single'",
column(
4,
selectInput(
inputId = "cluster_type1",
label = "View by Organism, or by Sequence?",
choices = c(
Choose = '',
OTU = 'otu',
Sequence = 'sequence'
),
selectize = FALSE
)
),
conditionalPanel(
condition = "input.cluster_type1 == 'sequence'|input.cluster_type1 == 'otu'",
column(
4,
selectInput(
inputId = "presence_type1",
label = "Generate tree from Presence/Absence, or Relative Abundance?",
choices = c(
Choose = '',
Incidence = 'incidence',
Abundance = 'abundance'
),
selectize = FALSE
)
),
conditionalPanel(condition = "input.presence_type1 == 'abundance'",
column(
4,
sliderInput(
"norm_value1",
"Choose normalization value: (Use keyboard arrows to fine tune value.)",
min = 0,
max = 10000,
value = 3999
)
)),
conditionalPanel(
condition = "input.presence_type1 == 'incidence'|input.presence_type1 == 'abundance'",
column(
4,
selectInput(
inputId = "distance_method1",
label = "Which distance method would you like to use for the distance matrix?",
choices = c(
"Manhattan" = "manhattan",
"Canberra" = "canberra",
"Bray" = "bray",
"Kulczynski" = "kulczynski",
"Jaccard" = "jaccard",
"Gower" = "gower",
"AltGower" = "altGower",
"Morisita" = "morisita",
"Horn" = "horn",
"Mountford" = "mountford",
"Raup" = "raup",
"Binomial" = "binomial",
"Chao" = "chao",
"Cao" = "cao",
"Mahalanobis" = "mahalanobis"
),
selected = "gower"
)
),
conditionalPanel(condition = "input.distance_method1 == 'bray'|input.norm_value1 == '4000'",
column(
4,
DT::dataTableOutput("tbl1"),
actionButton(
"button",
"SUBMIT",
style = "background-color:#221B70;
color:#E0EB15;
border-color:#E61029;
border-style:double;
border-width:4px;
border-radius:50%;
font-size:19px;"
)
))
)
)
)
),
conditionalPanel(
condition = "input.tree_type == 'multiple'",
column(
4,
selectInput(
inputId = "cluster_type2",
label = "View by Organism, or by Sequence?",
choices = c(
Choose = '',
OTU = 'otu',
Sequence = 'sequence'
),
selectize = FALSE
)
),
conditionalPanel(
condition = "input.cluster_type2 == 'sequence'|input.cluster_type2 == 'otu'",
column(
4,
selectInput(
inputId = "presence_type2",
label = "Generate tree from Presence/Absence, or Relative Abundance?",
c(
Choose = '',
Incidence = 'incidence',
Abundance = 'abundance'
),
selectize = FALSE
)
),
conditionalPanel(condition = "input.presence_type2 == 'abundance'",
column(
4,
sliderInput(
"norm_value2",
"Choose normalization value: (Use keyboard arrows to fine tune value.)",
min = 0,
max = 10000,
value = 3999
)
)),
conditionalPanel(
condition = "input.presence_type2 == 'incidence'|input.presence_type2 == 'abundance'",
column(
4,
selectInput(
inputId = "cluster_method",
label = "Which clustering method would you like to use?",
choices = c(
"Ward.D" = "ward.D",
"Ward.D2" = "ward.D2",
"Single" = "single",
"Complete" = "complete",
"Average (= UPGMA)" = "average",
"Mcquitty (= WPGMA)" = "mcquitty",
"Median (= WPGMC)" = "median",
"Centroid (= UPGMC)" = "centroid"
),
selected = "single"
)
),
conditionalPanel(
condition = "input.cluster_method == 'ward.D2'",
column(
4,
selectInput(
inputId = "distance_method2",
label = "Which distance method would you like to use for the distance matrix?",
choices = c(
"Manhattan" = "manhattan",
"Canberra" = "canberra",
"Bray" = "bray",
"Kulczynski" = "kulczynski",
"Jaccard" = "jaccard",
"Gower" = "gower",
"AltGower" = "altGower",
"Morisita" = "morisita",
"Horn" = "horn",
"Mountford" = "mountford",
"Raup" = "raup",
"Binomial" = "binomial",
"Chao" = "chao",
"Cao" = "cao",
"Mahalanobis" = "mahalanobis"
),
selected = "gower"
)
),
conditionalPanel(
condition = "input.distance_method2 == 'bray'|input.norm_value2 == '4000'",
DT::dataTableOutput("tbl2"),
actionButton(
"button",
"SUBMIT",
style = "background-color:#221B70;
color:#E0EB15;
border-color:#E61029;
border-style:double;
border-width:4px;
border-radius:50%;
font-size:19px;"
)
)
)
)
)
)
),
uiOutput("select_node_render"),
fluidRow(uiOutput("subtree_render"))
)
)
))
server <- function(input, output){
}
shinyApp(ui, server)
I try to put properly three elements on my Shiny dashboard
# User interface
ui <- fluidPage(theme = shinytheme("united"),
titlePanel("Crimes in Washington, DC (2017)"),
fluidRow(column(4,
selectInput("offenceInput", "Type of Offence",
choices =
sort(unique(incidents$OFFENSE)),
selected =
sort(unique(incidents$OFFENSE)),
multiple = TRUE),
selectInput("methodInput", "Method of Offence",
choices =
sort(unique(incidents$METHOD)),
selected =
sort(unique(incidents$METHOD)),
multiple = TRUE),
selectInput("shiftInput", "Police Shift",
choices =
sort(unique(incidents$SHIFT)),
selected =
sort(unique(incidents$SHIFT)),
multiple = TRUE),
selectInput('background', 'Background',
choices = providers,
multiple = FALSE,
selected = 'Stamen.TonerLite'),
dateRangeInput('dateRange',
label = 'Date',
start = as.Date('2017-01-01') ,
end = as.Date('2017-12-31')
)
),
column(10,
dataTableOutput('my_table'),
column(12,
leafletOutput(outputId = 'map', height = 600)
)
)
))
My map goes somewhere else, I tried different options. Just need map in a proper right top corner and a table below.
Here I have put all selectInput fields in left panel, map in right panel and my_table below these two panels. Trick is that column's 1st parameter should add to 12 (i.e. 4+8 in case of top panel and 12 in case of bottom panel).
ui <- fluidPage(fluidRow(column(4,
selectInput(...),
selectInput(...),
selectInput(...),
selectInput(...),
dateRangeInput(...)),
column(8,
leafletOutput(outputId = 'map', height = 600)),
column(12,
dataTableOutput('my_table'))))
Note: I was not able to test it due to lack of reproducible example but I hope this should work in your case.
Resolved with the help of RCommunity worldwide.
# User interface
ui <- fluidPage(theme = shinytheme("united"),
titlePanel(HTML("<h1><center><font size=14> Crimes in Washington, DC (2017) </font></center></h1>")),
fluidRow(column(4, align="center",
selectInput("offenceInput", "Type of Offence",
choices = sort(unique(incidents$Offense)),
selected = sort(unique(incidents$Offense)),
multiple = TRUE),
selectInput("methodInput", "Method of Offence",
choices = sort(unique(incidents$Method)),
selected = sort(unique(incidents$Method)),
multiple = TRUE),
selectInput("shiftInput", "Police Shift",
choices = sort(unique(incidents$Shift)),
selected = sort(unique(incidents$Shift)),
multiple = TRUE),
selectInput('background', 'Background',
choices = providers,
multiple = FALSE,
selected = 'Stamen.TonerLite'),
dateRangeInput('daterangeInput',
label = 'Date',
start = as.Date('2017-01-01') , end = as.Date('2017-12-31')
),
br(),
plotOutput("bar")
),
column(8,
leafletOutput(outputId = 'map', height = 600, width = 800),
dataTableOutput('my_table')
)
))
This gives the following layout. It is messy, but the structure is what I really wanted. Will improved small tweaks.