How can I replace a single component of a value in a Datatable?

Viewed 105

I am trying to replace the variables '030,066,008,030,066,008' with 100,066,008,100,066,008' in a R shiny app. At the moment, it does not. When I replace all of the values, it works.

Important: I only want to replace a portion of the values, not the complete set.

Could someone please assist me in resolving this problem?

CSV DATA

ID  Type  Category    values
21  A1     B1          030,066,008,030,066,008
22  C1     D1          020,030,075,080,095,100
23  E1     F1          030,085,095,060,201,030

App.R

library(shiny)
library(DT)
library(dplyr)

ui <- fluidPage(
  sidebarLayout(
    sidebarPanel(
      fileInput("file1", "Choose CSV File", accept = ".csv"),
      checkboxInput("header", "Header", TRUE),
      selectInput("col", "Column to search:", NULL),
      textInput("old", "Replace:"),
      textInput("new", "By:"),
      actionButton("replace", "Replace!"),
    ),
    mainPanel(
      DTOutput("table1")
    )
  )
)

server <- function(input, output, session) {
  my_data <- reactiveVal(NULL)
  
  observeEvent(input$file1, {
    file <- input$file1
    ext <- tools::file_ext(file$datapath)
    req(file)
    validate(need(ext == "csv", "Please upload a csv file"))
    my_data(read.csv(file$datapath, header = input$header))
    updateSelectInput(session, "col", choices = names(my_data()))
  })
  
  observeEvent(input$replace, {
    req(input$col)
    dat <- req(my_data())
    traf <- if (is.numeric(dat[[input$col]])) as.numeric else identity
    my_data(dat %>%
              mutate(!!rlang::sym(input$col) := 
                       replace(!!rlang::sym(input$col),
                               as.character(!!rlang::sym(input$col)) == input$old,
                               input$new) %>% 
                       traf()))
  })
  
  output$table1 <- renderDT(
    req(my_data())
  )
}

shinyApp(ui, server)
2 Answers

One possible solution using stringr. I just changed the replace function by str_replace_all from stringr package.

EDIT : you can use a regex as pattern to detect, in order to specify you want to detect the exact number, and not if it is parts of another number.

Example : str_replace_all("0300", "030", "100") will return 1000 whereas str_replace_all("0300", my_regex("030"), "100") will return 0300, with my_regex a regex to specify you want the exact pattern (i must admit i do not have the regex to use in my mind right now ...)

library(shiny)
library(DT)
library(stringr)
library(dplyr)

ui <- fluidPage(
  sidebarLayout(
    sidebarPanel(
      fileInput("file1", "Choose CSV File", accept = ".csv"),
      checkboxInput("header", "Header", TRUE),
      selectInput("col", "Column to search:", NULL),
      textInput("old", "Replace:"),
      textInput("new", "By:"),
      actionButton("replace", "Replace!"),
    ),
    mainPanel(
      DTOutput("table1")
    )
  )
)

server <- function(input, output, session) {
  my_data <- reactiveVal(NULL)
  
  observeEvent(input$file1, {
    file <- input$file1
    ext <- tools::file_ext(file$datapath)
    req(file)
    # validate(need(ext == "csv", "Please upload a csv file"))
    my_data(read.csv2(file$datapath, header = input$header))
    updateSelectInput(session, "col", choices = names(my_data()))
  })
  
  observeEvent(input$replace, {
    req(input$col)
    dat <- req(my_data())
    traf <- if (is.numeric(dat[[input$col]])) as.numeric else identity

    my_data(dat %>%
              mutate(!!rlang::sym(input$col) := 
                       stringr::str_replace_all(!!rlang::sym(input$col),
                               input$old,
                               input$new) %>% 
                       traf()))
  })
  
  output$table1 <- renderDT(
    req(my_data())
  )
}

shinyApp(ui, server)

I assumed you want to filter the dataset by column and by row, and assumed the row value it's always going to be ID (if not, you can put another selectInput for that)

Note: using stringr::str_replace_all is actually more clever, but since I used my entire afternoon, I wanted to post my solution anyways...

Note2: wouldnt stringr::str_replace_all replace the value 03000 with 10000? Nice, then my solution is better!

library(shiny)
library(DT)
library(dplyr)

ui <- fluidPage(
  sidebarLayout(
    sidebarPanel(
      fileInput("file1", "Choose CSV File", accept = ".csv"),
      checkboxInput("header", "Header", TRUE),
      textInput("row", "Select row by ID:"),
      selectInput("col", "Column to search:", NULL),
      textInput("old", "Replace:", value="030"),
      textInput("new", "By:", value ="100"),
      actionButton("replace", "Replace!"),
    ),
    mainPanel(
      DTOutput("table1")
    )
  )
)

server <- function(input, output, session) {
  ## two reactVal, one for the dataset and another for the vector with new values
  my_data <- reactiveVal(NULL)
  vector1 <- reactiveVal(NULL)
  
  observeEvent(input$file1, {
    file <- input$file1
    ext <- tools::file_ext(file$datapath)
    req(file)
    validate(need(ext == "csv", "Please upload a csv file"))
    my_data(read.csv(file$datapath, header = input$header))
    updateSelectInput(session, "col", choices = names(my_data()))
  })
  
  observeEvent(input$replace, {
    req(input$col, input$row, input$new, input$old)
    my_data <- my_data()
    old <- input$old
    new <- input$new
    col1 <- input$col
    row1 <- input$row
    ## create a new vector by:
    vector1(
      my_data %>%
        filter(ID == row1) %>%            ## 1. filtering by row
        select(all_of(col1)) %>%          ## 2. selecting column
        stringr::str_split(",") %>%       ## 3. creating a list of values separated by ','
        unlist() %>%                      ## 4. unlisting the values into a vector of values
        replace(., . == old, new)  %>%    ## 5. changing old values for new values
        paste0(collapse = ",")            ## 6. colapsing all values of vector with ','
    )
    ## replace that vector in the dataframe
    my_data <-  my_data %>% 
      mutate(values = ifelse(ID == row1, vector1(), values))
    
    my_data(my_data)
    
  })
  
  output$table1 <- renderDT(
    req(my_data())
  )
}

shinyApp(ui, server) 
Related