How do I access the date from an rShiny dateInput? - shiny

I am trying to write an input page that takes the date of a section's last training, then calculates the currency of that training (how many days since), but I seem to be having a problem accessing the date from the dateInput element. I'm currently just trying to get it to print, but it is eluding me. Is there something I'm missing, or how can I get this to work? I've commented out the code to (hopefully) calculate the date gap, as I haven't had a date to work through that just yet. If you see an issue there, I'd appreciate that pointer as well.
Thank you!
library(shiny)
ui <- fluidPage(
tags$h3("Section Training"),
dateInput("section_Last_Training",
"When was your last training course?",
daysofweekdisabled = c(0, 6),
max = Sys.Date()
),
)
server <- function(input, output, session) {
section_Last_Training <- reactive({
# dateGap = as.character(difftime(Sys.time(), input$section_Last_Training, units = "days"))
print(input$section_Last_Training)
})
}
shinyApp(ui, server)

It is working, just make sure the last value in reactive is the value you want to assign to the reactive. You can do print, but do it before your gap calculation. Another thing is reactive is "lazily" evaluated. It means if there is no downstream reactivity requires it, it will not be calculated. So you need to add some events that require this reactive to make it work. See the code below.
library(shiny)
ui <- fluidPage(
tags$h3("Section Training"),
dateInput("section_Last_Training",
"When was your last training course?",
daysofweekdisabled = c(0, 6),
max = Sys.Date()
),
)
server <- function(input, output, session) {
section_Last_Training <- reactive({
print(input$section_Last_Training)
as.character(difftime(Sys.time(), input$section_Last_Training, units = "days"))
})
observe(print(section_Last_Training()))
}
shinyApp(ui, server)

Related

How to update fillColor palette to selected input in shiny map?

I am having trouble transitioning my map from static to reactive so a user can select what data they want to look at. Somehow I'm not successfully connecting the input to the dataframe. My data is from a shapefile and looks roughly like this:
NAME Average Rate geometry
1 Alcona 119.7504 0.1421498 MULTIPOLYGON (((-83.88711 4...
2 Alger 120.9212 0.1204398 MULTIPOLYGON (((-87.11602 4...
3 Allegan 128.4523 0.1167062 MULTIPOLYGON (((-85.54342 4...
4 Alpena 114.1528 0.1410852 MULTIPOLYGON (((-83.3434 44...
5 Antrim 124.8554 0.1350004 MULTIPOLYGON (((-84.84877 4...
6 Arenac 127.8809 0.1413534 MULTIPOLYGON (((-83.7555 43...
In the server section below, you can see that I tried to use reactive to get the selected variable and when I write print(select) it does print the correct variable name, but when I try to put it into the colorNumeric() function it's clearly not being recognized. The map I get is all just the same shade of blue instead of different shades based on the value of the variable in that county.
ui <- fluidPage(
fluidRow(
selectInput(inputId="var",
label="Select variable",
choices=list("Average"="Average",
"Rate"="Rate"),
selected=1)
),
fluidRow(
leafletOutput("map")
)
)
server <- function(input, output, session) {
# Data sources
counties <- st_read("EITC_counties.shp") %>%
st_transform(crs="+init=epsg:4326")
counties_clean <- select(counties, NAME, X2020_Avg., X2020_Takeu)
counties_clean <- counties_clean %>%
rename("Average"="X2020_Avg.",
"Rate"="X2020_Takeu")
# Map
variable <- reactive({
input$var
})
output$map <- renderLeaflet({
select <- variable()
print(select)
pal <- colorNumeric(palette = "Blues", domain = counties_clean$select, na.color = "black")
color_pal <- counties_clean$select
leaflet()%>%
setView( -84.51, 44.18, zoom=5) %>%
addPolygons(data=counties_clean, layerId=~NAME,
weight = 1, smoothFactor=.5,
fillOpacity=.7,
fillColor=~pal(color_pal()),
highlightOptions = highlightOptions(color = "white",
weight = 2,
bringToFront = TRUE)) %>%
addProviderTiles(providers$CartoDB.Positron)
})
}
shinyApp(ui, server)
I've tried making the reaction into an event and also using the observe function using a leaflet proxy but it only produced errors. I also tried to skip the reactive definition and just put input$var directly into the palette (counties_clean$input$var), but it similarly did not show any color variation.
When I previously created a static map setting the palette using counties_clean$Average it came out correctly, but replacing Average with a user input is where I appear to be going wrong. Thanks in advance for any guidance you can provide and please let me know if I can share any additional clarification.
Unfortunately, your code is not reproducible without the data, but the mistake is most likely in this line
color_pal <- counties_clean$select
What this line does, is to extract a column named select from your data. This column is not existing, so it will return NULL.
What you want though, is to extract a column whose name is given by the content of select, so you want to try:
color_pal <- counties_clean[[select]]

isolate input in a module shiny when using insert ui

I'd like to create several ui which use an input parameter. The problem is that the new UI created are still reacting to the input even when I put an isolate()
The right behaviour would give a custom UI created and isolated from the new inputs coming from the selectInput()
For instance I'd like a first UI with the year 2019 selected and second UI with the year 2020.
Here we can see that adding 2020 will change in each UI which is wrong.
library(shiny)
customplotUI <- function(id){
ns <- NS(id)
fluidPage(
sidebarPanel(id=ns("sidebarpanel"),
actionButton(ns("add"),label = "Add"),
selectInput(inputId=ns("years"),label="Year :", choices = c(2019,2020),selected = 2019, multiple = TRUE)),
mainPanel(div(id=ns("placeholder"))
)
)
}
customplot <- function(input,output,session){
ns <- session$ns
output$res <- renderPrint({
data <- data.frame(year=c(2019,2020),value=c("mtcars2019","mtcars2020"))
data[data$year %in% input$years,]})
ctn <- reactiveVal(0)
Id <- reactive({
function(id){
paste0(id, ctn())
}
})
IdNS <- reactive({
function(id){
ns(paste0(id, ctn()))
}
})
observeEvent(input$add, {
ctn(ctn() + 1)
print(Id()('div'))
insertUI(
selector = paste0('#', ns('placeholder')),
ui = div(
id = Id()('div'),
verbatimTextOutput(IdNS()('chart'))
)
)
id <- Id()('chart')
output[[id]] <- renderPrint({
data <- data.frame(year=c(2019,2020),value=c("mtcars2019","mtcars2020"))
#data[data$year %in% isolate(input$years),]
data[data$year %in% input$years,]
})
})
}
ui <- fluidPage(
customplotUI(id="customplot")
)
server <- function(input, output, session){
callModule(customplot,id="customplot",session=session)
}
shinyApp(ui, server)
Perhaps I'm misunderstanding what you're trying to accomplish, but when I run the code, using the commented line with isolate seems to work as intended.
I'm guessing that in creating the minimal reprex (thank you for doing this btw!), you might have gone a little too minimal and removed another reactive that updates data. If you are trying to have the individual UI elements update based on some other input but keep the same filtering scheme, you need to capture the current value of input$years outside of the renderPrint statement.
Here you can see the subset of rows is unchanged, but the last column updates based on input box:
...
id <- Id()('chart')
targetYears <- input$years
output[[id]] <- renderPrint({
data <- data.frame(year=c(2019,2020),
value=c("mtcars2019","mtcars2020"),
yrInput = paste(input$years, collapse =" "))
data[data$year %in% targetYears, ]
...
isolate only prevents a change in the reactive from triggering an update. If the update is triggered by something else, the current/updated value of the reactive is still used. Through the wonders of R's scoping rules, by capturing the value of input$years in non-reactive variable, targetYears, outside of the renderPrint call and then using that in the renderPrint expression it will always use the the value of the input when output[[id]] was created. The isolate is not needed as you are using observeEvent which will prevent the observer from executing when you change the input.

How to format R Shiny numericInput?

I have a Shiny app with numerous numericInput fields. I would like a way to format the numericInput fields with commas separating every 10^3. For example, I want 5,000,000 instead of 5000000.
I can do this in R with the format and prettyNum functions. But I don't have a way to do this in Shiny.
This would be very helpful for the UI because it would work with percents, money, etc. Does anyone have any idea how to incorporate this into the numericInput field?
Thanks!
library(shiny)
# Define UI for application that draws a histogram
ui <- fluidPage(
mainPanel(
numericInput("formatNumber",
"Number should be formatted, e.g."5,000,000",
value = 1000),
p(format(5000000.10, big.mark=",", big.interval=3L,
digits=0, scientific=F))
)
)
server <- function(input, output) {
}
shinyApp(ui = ui, server = server)
The shinyWidgets package has a great new function (added as of version 0.5.4, also a disclaimer, I added it via a pull request), autonumericInput that will allow you to do just this. It is based on the javascript library autonumeric. There are a lot of options to the function, but the documentation is extensive and for simple uses most can be ignored.
What you are trying to do can be accomplished as follows:
library(shiny)
library(shinyWidgets)
ui <- fluidPage(
h1("Autonumeric Input Example"),
shinyWidgets::autonumericInput(
inputId = "num",
label = "Enter a large number:",
value = 1000000,
currencySymbolPlacement = "p",
decimalPlaces = 2,
digitGroupSeparator = ",",
decimalCharacter = "."
),
verbatimTextOutput("res1")
)
server <- function(input, output) {
output$res1 <- renderText(input$num)
}
shinyApp(ui = ui, server = server)
This is especially nice because it provides as-you-type formatting, so that the user can easily know how big the number is as they put it in. I know from experience that it is a real pain to try to put large numbers into the base shiny numericInput, trying to count digits in a small little box and figure out how many zeros there are. The goal of this function is to make formatting numeric inputs much easier.
Hopefully this is useful!
I could not find anything that would help with numericInput(), but here's what works with textInput() instead.
library(shiny)
if(interactive()){
shinyApp(
ui <- fluidPage(
mainPanel(
textInput("formatNumber1", "Number should be formatted, e.g.5,000,000", value = 1000),
textInput("formatNumber2", "Number should be formatted, e.g.5,000,000", value = 1000)
)
),
server <- function(input, output, session) {
observe({
updateTextInput(session, "formatNumber1", "Number should be formatted, e.g.5,000,000",
value = prettyNum(input$formatNumber1, big.mark=",", scientific=FALSE))
updateTextInput(session, "formatNumber2", "Number should be formatted, e.g.5,000,000",
value = prettyNum(input$formatNumber2, big.mark=",", scientific=FALSE))
})
}
)
}
That is the only method I found, however if you're too slow or add a digit after the commas have been added, the number is not displayed properly (e.g., 3,000 becomes 3,0,000 if you add a 0 at the end of the string). To correct that, I've changed the updateTextInput() function as below:
updateTextInput(
session,
"formatNumber1",
"Number should be formatted, e.g.5,000,000",
value = prettyNum(
gsub(",", "", input$formatNumber1),
big.mark=",", scientific=FALSE
)
)
In effect gsub() function is used to reset the input to a number every time the input is amended, otherwise the prettyNum() function is only using the digits after the comma and ignoring all digits on the left of the last comma.
If you've got multiple inputs to reformat, then create a function as follows (NB: I've also added req(input[[x]]) to avoid NA appearing when the input is blank):
updatetoprettynb <- function(x) {
req(input[[x]])
updateTextInput(
session,
x,
value = prettyNum(
gsub(",", "", input[[x]]),
big.mark = ",",
scientific = FALSE
)
)
}
You still have to use the function in a similar fashion but don't forget to use "":
observe({
updatetoprettynb("formatNumber1")
})

Selecting rows from a DT table using Crosstalk in Shiny

I confess, I did post this question over on RStudio three days ago but it has not had enough love yet, so I'm trying again here. I hope that's okay. The original question is here (the text is the same in both, I'm just being transparent). https://community.rstudio.com/t/selecting-rows-from-a-dt-table-using-crosstalk-in-shiny/4079
So I would like to brush across points in D3Scatter and use it to filter the rows of a datatable produced using the DT package with crosstalk.
Just like this, which totally works outside of shiny:
library(crosstalk)
library(d3scatter)
library(DT)
shared_iris <- SharedData$new(iris)
bscols(d3scatter(shared_iris, ~Petal.Length, ~Petal.Width, ~Species, width = "100%",
x_lim = range(iris$Petal.Length), y_lim = range(iris$Petal.Width)),
datatable(shared_iris))
But when I put it in Shiny, I can select points on the scatter from the table, but not vice versa:
library(shiny)
library(crosstalk)
library(d3scatter)
library(DT)
ui <- fluidPage(
fluidRow(
column(6, d3scatterOutput("scatter1")),
column(6, DT::dataTableOutput("scatter2"))
)
)
server <- function(input, output, session) {
jittered_iris <- reactive({
iris
})
shared_iris <- SharedData$new(jittered_iris)
output$scatter1 <- renderD3scatter({
d3scatter(shared_iris, ~Petal.Length, ~Petal.Width, ~Species, width = "100%",
x_lim = range(iris$Petal.Length), y_lim = range(iris$Petal.Width))
})
output$scatter2 <- DT::renderDataTable({
datatable(shared_iris)
})
}
shinyApp(ui, server)
They’ve got it working here: https://rstudio-pubs-static.s3.amazonaws.com/215948_95c1ab86ad334d2f82856d9e5ebc16af.html
I’m at a loss. I feel like I’ve tried everything. Any clues anyone?
Thanks,
Crosstalk integration in DT only works with client-side processing . Try DT::renderDataTable with server = FALSE
library(shiny)
library(crosstalk)
library(d3scatter)
library(DT)
ui <- fluidPage(
fluidRow(
column(6, d3scatterOutput("scatter1")),
column(6, DT::dataTableOutput("scatter2"))
)
)
server <- function(input, output, session) {
jittered_iris <- reactive({
iris
})
shared_iris <- SharedData$new(jittered_iris)
output$scatter1 <- renderD3scatter({
d3scatter(shared_iris, ~Petal.Length, ~Petal.Width, ~Species, width = "100%",
x_lim = range(iris$Petal.Length), y_lim = range(iris$Petal.Width))
})
output$scatter2 <- DT::renderDataTable({
datatable(shared_iris)
}, server = FALSE)
}
shinyApp(ui, server)
DT should throw an error when using Crosstalk with server-side processing
Error in widgetFunc: Crosstalk only works with DT client mode: DT::renderDataTable({...}, server=FALSE)
but I think that broke here: https://github.com/rstudio/DT/commit/893708ca10def9cfe0733598019b62a8230fc52b
Guess I can file an issue on this if no one else has.

Use Shiny to display bar graph by state

I'm trying to use shiny to create a bar graph for a state that is selected via drop-down box. I'm quite new to R and I've tried a variety of examples to no avail. I have three variables (state, claim #, total $) and for each state there are five values. So something like this:
state <- c("PA", "TX", "NY")
claim_num <- c(1:15)
total <- sample(1000:5000, 15)
df <- (state, claim_num, total)
I want to have something similar to https://beta.rstudioconnect.com/jjallaire/shiny-embedding/#inline-app but I don't know if I can format my data in that was since I would have a lot of NAs.
Do you mean something like this (you can download and run the example)?
library(shiny)
ui <- shinyUI(
fluidPage(
titlePanel("Sample Shiny App"),
sidebarLayout(
sidebarPanel(
uiOutput("stateInput")
),
mainPanel(
plotOutput("statePlot")
)
)
))
server <- shinyServer(function(input, output) {
state <- sample(state.abb, 3, replace = FALSE)
total <- sample(1000:5000, 15)
claimNumber <- 1:15
data <- data.frame(state, total, claimNumber)
output$stateInput <- renderUI({
selectInput(
inputId = "state",
label = "Select a State:",
choices = levels(data$state)
)
})
output$statePlot <- renderPlot({
hist(data$total[data$state == input$state])
})
})
shinyApp(ui = ui, server = server)
What we're doing is taking the list of unique states available in our data frame and passing those to our selectInput that renders as a dropdown in the UI. From here, we can access whatever value the user has selected through the input$state object. More generally, we can access inputs based on whatever we define the inputId to be (in this particular case, we call it state).
Having grabbed the user input, we can then subset the data frame to only return values that correspond to the user-defined state and, in this case, pass those totals values to a plot that we render as output.