Araê Souza
Araê Souza

Reputation: 79

Cannot use data in shiny after for loop

I'm trying to write a shiny app for pseudonymisation. It needs to receive a CSV file, let the user select which columns need to be removed, and download the data. The problem I cannot solve is why the for loop doesn't work as it does in a normal script.

Here is the code.

UI

library(shiny)

fluidPage(

  titlePanel("Anonimizador"),

  sidebarLayout(
    sidebarPanel(
      fileInput(
        'file_input',
        'Escolha a base de dados para anonimização',
        accept = c(
          'text/csv',
          'text/comma-separated-values',
          '.csv'
        )
      ),
      radioButtons(
        "separador",
        "Separador: ",
        choices = c(";",",",":")
      ),
      radioButtons(
        "encoding",
        "Encoding: ",
        choices = c("UTF-8", "latin1")
      )
    ),

    mainPanel(
      fluidRow(
        dataTableOutput("table_output")
      ),
      hr(),
      fluidRow(
        column(
          6,
          checkboxGroupInput(
            "colunas",
            "Selecione as colunas para anonimizar:",
            choices = NULL
          )
        ),
        column(
          6,
          downloadButton(
            'downloadData',
            'Baixe a base anonimizada'
          )
        )
      )
    )
  )
)

SERVER

library(shiny)
library(dplyr)


shinyServer(function(session, input, output) {

  db <- reactive({
    inFile <- input$file_input

    if (is.null(inFile)) return(NULL)

    db <- read.csv(
      inFile$datapath,
      header = TRUE,
      sep = input$separador,
      encoding = input$encoding
    )

    return(db)
  })

  output$table_output <- renderDataTable({
    db <- db()
    db
  },
    options = list(
      scrollX = TRUE,
      pageLength = 5
    )
  )

  observe({
    updateCheckboxGroupInput(
      session,
      "colunas",
      "Selecione as colunas para anonimizar:",
      choices = names(db())
    )
  })

  db_anonimizado <- reactive({


    db <- db()
    colunas <- names(db[,input$colunas])

    db_novo <- db

    for (i in 1:length(colunas)) {

      unicos <- data.frame(
        original = unique(db[,colunas[i]]),
        novo = 1:nrow(unique(db[,colunas[i]]))
      )

      db_novo <- left_join(db_novo, unicos, by = colunas[i])
    }

    db_novo$unico <- 1:nrow(db_novo)

    nomes_novos <- names(db_novo[,(ncol(db_novo)-length(colunas)): ncol(db_novo)])

    db_novo$indicador_anonimizado <- do.call(
      paste0,
      db_novo[,nomes_novos]
    )

    remove <- c(colunas, nomes_novos)

    db_novo <- db_novo[,-which(names(db_novo) %in% remove)]

    db_novo

  })


  output$downloadData <- downloadHandler(
    filename = function() {
      paste('anonimizada.csv')
    },
    content = function(file) {
      write.csv(
        db_anonimizado(),
        file
      )
    }
  )

})

If anyone could help me I'd be very grateful

Upvotes: 0

Views: 102

Answers (1)

YBS
YBS

Reputation: 21349

You have several issues in your code.

  1. When you select only one column, you need to handle it slightly differently in the for loop.
  2. nrow(unique(db[,colunas[i]])) gives a NULL for me. Perhaps length() is better here.
  3. You needed a +1 in ncol(db_novo)-length(colunas)+1

Full code

library(shiny)

ui <- fluidPage(
  
  titlePanel("Anonimizador"),
  
  sidebarLayout(
    sidebarPanel(
      fileInput(
        'file_input',
        'Escolha a base de dados para anonimização',
        accept = c(
          'text/csv',
          'text/comma-separated-values',
          '.csv'
        )
      ),
      radioButtons(
        "separador",
        "Separador: ",
        choices = c(",",";",":")
      ),
      radioButtons(
        "encoding",
        "Encoding: ",
        choices = c("UTF-8", "latin1")
      )
    ),
    
    mainPanel(
      fluidRow(
        dataTableOutput("table_output"), DTOutput("t1")
      ),
      hr(),
      fluidRow(
        column(
          6,
          checkboxGroupInput(
            "colunas",
            "Selecione as colunas para anonimizar:",
            choices = NULL
          )
        ),
        column(
          6,
          downloadButton(
            'downloadData',
            'Baixe a base anonimizada'
          )
        )
      )
    )
  )
)

library(dplyr)


server <- shinyServer(function(session, input, output) {
  
  db <- reactive({
    inFile <- input$file_input
    
    if (is.null(inFile)) return(NULL)
    
    db <- read.csv(
      inFile$datapath,
      header = TRUE,
      sep = input$separador,
      encoding = input$encoding
    )
    
    return(db)
  })
  
  output$table_output <- renderDataTable({
    db <- db()
    db
  },
  options = list(
    scrollX = TRUE,
    pageLength = 5
  )
  )
  
  observe({
    updateCheckboxGroupInput(
      session,
      "colunas",
      "Selecione as colunas para anonimizar:",
      choices = names(db())
    )
  })
  
  db_anonimizado <- reactive({
    req(input$colunas,db())

    db <- db()
    colunas <- names(db[,input$colunas])

    db_novo <- db
    n <- length(input$colunas)
    
    if (n==1) {
      unicos <- data.frame(
        original = unique(db[,input$colunas]),
        novo1 = 1:length(unique(db[,input$colunas]))
      )
      names(unicos)[1] <- c(sym(input$colunas))
      
      db_novo <- left_join(db_novo, unicos, by = names(unicos)[1])
      lastcol <- ncol(db_novo)
      
      nomes_novos <- c(names(db_novo)[lastcol])
      remove <- c(input$colunas, nomes_novos)
      db_novo$indicador_anonimizado <- db_novo[,c(nomes_novos)]
      
    }else if (n>1) {
      for (i in 1:n) {
        
        unicos <- data.frame(
          original = unique(db[,colunas[i]]),
          novo2 = 1:length(unique(db[,colunas[i]]))
        )
        names(unicos)[1] <- c(sym(colunas[i]))
        
        db_novo <- left_join(db_novo, unicos, by = colunas[i])
      }
      
      nomes_novos <- names(db_novo[,(ncol(db_novo)-length(colunas)+1): ncol(db_novo)])
      remove <- c(colunas, nomes_novos)
      db_novo$indicador_anonimizado <- do.call(
        paste0,
        db_novo[,c(nomes_novos)]
      )
    }
    #print(nomes_novos)
    db_novo$unico <- 1:nrow(db_novo)

    #nomes_novos <- names(db_novo[,(ncol(db_novo)-length(colunas)): ncol(db_novo)])

    # db_novo$indicador_anonimizado <- do.call(
    #   paste0,
    #   db_novo[,c(nomes_novos)]
    # )

    #remove <- c(colunas, nomes_novos)

    db_novo <- db_novo[,-which(names(db_novo) %in% remove)]
    
    db_novo

  })

  output$t1 <- renderDT({
    req(db_anonimizado())
    db_anonimizado()
  })

  output$downloadData <- downloadHandler(
    filename = function() {
      paste('anonimizada.csv')
    },
    content = function(file) {
      write.csv(
        db_anonimizado(),
        file
      )
    }
  )
  
})

shinyApp(ui, server)

Upvotes: 1

Related Questions