8
votes

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)
3
I wonder if there might be a potential javascript solution for this.ichbinallen
Please see this or this related question for a js solution.ismirsehregal

3 Answers

5
votes

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!

2
votes

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))
      })
    }
  )
}
2
votes

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")
})