In the following example, the numberInput
"Number C" is calculated and updated as "Number A" divided "Number B". When the result is an infinite decimal, this leads to a number with lots of digits to "Number C". I would like to round the infinite decimal to the second or third the digits, making the appearance easier to read for "Number C". In the same time, however, I don't want to apply the round
function to num_C
because in the real world I want to apply "Number C" for other calculation and I want to use the number as is. In other words, I want to find a way to format the number's appearance but not the acutal value, like format a cell in an Excel spreadsheet to show only limited digits but not change the acutal value. Is this possible to do in Shiny?
library(shiny)
# Define UI
ui <- fluidPage(
numericInput(inputId = "A", "Number A", value = 2),
numericInput(inputId = "B", "Number B", value = 3),
numericInput(inputId = "C", "Number C [A/B]", value = 1)
)
# Server logic
server <- function(input, output, session){
observe({
req(input$A, input$B)
num_C <- input$A/input$B
updateNumericInput(
inputId = "C",
session = session,
value = num_C
)
})
}
# Complete app with UI and server components
shinyApp(ui, server)
You could use a reactive
expression for num_C
library(shiny)
# Define UI
ui <- fluidPage(
numericInput(inputId = "A", "Number A", value = 2),
numericInput(inputId = "B", "Number B", value = 3),
numericInput(inputId = "C", "Number C [A/B]", value = 1)
)
# Server logic
server <- function(input, output, session){
num_C <- reactive({
req(input$A, input$B)
input$A / input$B
})
observe(
updateNumericInput(
inputId = "C",
session = session,
value = format(num_C(), digits = 2))
)
}
# Complete app with UI and server components
shinyApp(ui, server)
num_C()
will then return the "un-rounded" value, whereas we use the rounded value format(num_C(), digits = 2)
in updateNumericInput
.
For what it's worth, here's an incomplete update
library(shiny)
# Define UI
ui <- fluidPage(
numericInput(inputId = "A", "Number A", value = 2),
numericInput(inputId = "B", "Number B", value = 3),
numericInput(inputId = "C", "Number C [A/B]", value = 1),
textOutput("value"),
textOutput("rounded_value")
)
# Server logic
server <- function(input, output, session){
num_C <- reactiveValues(
value = NULL,
rounded_value = NULL
)
observeEvent(input$A | input$B, {
num_C$value <- input$A / input$B
num_C$rounded_value <- round(num_C$value, 1)
})
observeEvent(input$C, {
num_C$value <- input$C
num_C$rounded_value <- input$C
})
output$value <- renderText(
sprintf("Number C = %f", num_C$value)
)
output$rounded_value <- renderText(
sprintf("Number C (rounded) = %f", num_C$rounded_value)
)
}
# Complete app with UI and server components
shinyApp(ui, server)
The idea is to use reactiveValues
to track the full precision and rounded value of number C. This works in as far as
numericInput
will correctly calculate (and display) the full precision and rounded numbers for C in the textOutput
s.numericInput
will also correctly display the full precision number (which is equal to the rounded) in the textOutput
s.However, I've been unsuccessful with using updateNumericInput
to update the value for C with the rounded number when numbers A and B were changed.
To be continued...
Simpliest thing to do would be to count how long input$C
is and apply a rounding figure - while saving the true value as a dummy variable:
library(shiny)
#this counts the decimal places of a value
decimalplaces <- function(x) {
if ((x %% 1) != 0) {
nchar(strsplit(sub('0+$', '', as.character(x)), ".", fixed=TRUE)[[1]][[2]])
} else {
return(0)
}
}
# Define UI
ui <- fluidPage(
numericInput(inputId = "A", "Number A", value = 2),
numericInput(inputId = "B", "Number B", value = 3),
numericInput(inputId = "C", "Number C [A/B]", value = 1)
)
# Server logic
server <- function(input, output, session){
num_C <- reactiveValues(
value = NULL
)
observeEvent(input$A|input$B,{
num_C$value <- input$A/input$B
updateNumericInput(
inputId = "C",
session = session,
value = round(num_C$value,2)
)
})
observeEvent(input$C, {
#identify if num_C is greater than 2 dc
if(decimalplaces(input$C)>2){
num_C$value <- input$C
}
updateNumericInput(
inputId = "C",
session = session,
value = round(num_C$value,2)
)
})
#check that everything is working correctly.
observeEvent( input$A|input$B|input$C,{
print(paste0(num_C$value," ", input$C))
})
}
# Complete app with UI and server components
shinyApp(ui, server)
thanks to @Maurits Evers for the majority of the code.
I just changed the code of Maurits a little bit by adding a flag
and an observeEvent
for the value <- reactiveValue()
that holds the actual value. Now, "C" will always show the rounded value, but value
will store the actual.
I hope this is useful...
library(shiny)
# Define UI
ui <- fluidPage(
numericInput(inputId = "A", "Number A", value = 2),
numericInput(inputId = "B", "Number B", value = 2),
numericInput(inputId = "C", "Number C [A/B]", value = 1),
textOutput("value"),
textOutput("rounded_value")
)
# Server logic
server <- function(input, output, session){
value <- reactiveVal(1)
rounded_value <- reactiveVal()
flag <- reactiveVal(T)
observeEvent(input$A | input$B, {
value(input$A / input$B)
rounded_value(round(value(), 2))
})
observeEvent(input$C, {
if(flag()){
value(input$C)
rounded_value(round(input$C, 2))
}else{
flag(T)
}
})
observeEvent(value(),{
flag(F)
updateNumericInput(session, "C", value = rounded_value())
})
output$value <- renderText(
sprintf("Number C = %f", value())
)
output$rounded_value <- renderText(
sprintf("Number C (rounded) = %f", rounded_value())
)
}
# Complete app with UI and server components
shinyApp(ui, server)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With