最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to format the input of Shiny updated numericInput but not change the actual value? - Stack Overflow

programmeradmin2浏览0评论

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 ponents
shinyApp(ui, server)

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 ponents
shinyApp(ui, server)
Share Improve this question asked Apr 12, 2019 at 3:15 wwwwww 39.2k12 gold badges52 silver badges92 bronze badges 4
  • I would suggest filing a GH issue to Rstudio's shiny repo to ask for a format argument to numericInput() and updateNumericInput(). – Phil Commented Apr 12, 2019 at 17:51
  • @Phil Thanks for your ment. This is something we can do, but I would like to wait for a while making sure I did not miss any solutions. – www Commented Apr 12, 2019 at 17:58
  • 1 @Phil : with my (limited) understanding of the underlying input type=„number“, I don’t think this is really possible because input$C corresponds to the value and that’s all this widget really has, ie there is no format property and if one would use eg pattern to restrict to two decimals, then the value and input$C will be affected likewise and you don’t have the full precision value anymore. I think you have to store it separately, see eg Maurits‘ answer. – RolandASc Commented Apr 17, 2019 at 17:01
  • 1 @RolandASc this is why I believe it should be a feature request to the Shiny team at RStudio – Phil Commented Apr 17, 2019 at 17:15
Add a ment  | 

3 Answers 3

Reset to default 5

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 ponents
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.


A partial update

For what it's worth, here's an inplete 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 ponents
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

  1. changing numbers A, B through numericInput will correctly calculate (and display) the full precision and rounded numbers for C in the textOutputs.
  2. changing number C through numericInput will also correctly display the full precision number (which is equal to the rounded) in the textOutputs.

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 ponents
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 ponents
shinyApp(ui, server)

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论
ok 不同模板 switch ($forum['model']) { /*case '0': include _include(APP_PATH . 'view/htm/read.htm'); break;*/ default: include _include(theme_load('read', $fid)); break; } } break; case '10': // 主题外链 / thread external link http_location(htmlspecialchars_decode(trim($thread['description']))); break; case '11': // 单页 / single page $attachlist = array(); $imagelist = array(); $thread['filelist'] = array(); $threadlist = NULL; $thread['files'] > 0 and list($attachlist, $imagelist, $thread['filelist']) = well_attach_find_by_tid($tid); $data = data_read_cache($tid); empty($data) and message(-1, lang('data_malformation')); $tidlist = $forum['threads'] ? page_find_by_fid($fid, $page, $pagesize) : NULL; if ($tidlist) { $tidarr = arrlist_values($tidlist, 'tid'); $threadlist = well_thread_find($tidarr, $pagesize); // 按之前tidlist排序 $threadlist = array2_sort_key($threadlist, $tidlist, 'tid'); } $allowpost = forum_access_user($fid, $gid, 'allowpost'); $allowupdate = forum_access_mod($fid, $gid, 'allowupdate'); $allowdelete = forum_access_mod($fid, $gid, 'allowdelete'); $access = array('allowpost' => $allowpost, 'allowupdate' => $allowupdate, 'allowdelete' => $allowdelete); $header['title'] = $thread['subject']; $header['mobile_link'] = $thread['url']; $header['keywords'] = $thread['keyword'] ? $thread['keyword'] : $thread['subject']; $header['description'] = $thread['description'] ? $thread['description'] : $thread['brief']; $_SESSION['fid'] = $fid; if ($ajax) { empty($conf['api_on']) and message(0, lang('closed')); $apilist['header'] = $header; $apilist['extra'] = $extra; $apilist['access'] = $access; $apilist['thread'] = well_thread_safe_info($thread); $apilist['thread_data'] = $data; $apilist['forum'] = $forum; $apilist['imagelist'] = $imagelist; $apilist['filelist'] = $thread['filelist']; $apilist['threadlist'] = $threadlist; message(0, $apilist); } else { include _include(theme_load('single_page', $fid)); } break; default: message(-1, lang('data_malformation')); break; } ?>