1

I have an .xlsx file with multiple sheets which I am uploading to my Shiny app using fileInput having id "file". My objective is to load a sheet using a string detect, that is if I have 3 sheets in random order named "apple", "orange" and "banana", I would like to load the "apple" sheet using string match from the list of sheets. So far I am not being able to get the list of sheets as I keep running into the error when I try to extract the sheet names using excel_sheets using readxl package-

Warning: Error in : `path` does not exist: ‘C:\Users\AppData\Local\Temp\Rtmp6dWPYS/0b16b05aa5a58cc1d1261369/0.xlsx’

The relevant server code is as follows -

    sheet_names <- reactive({
        if (!is.null(input$file)) {
            return(excel_sheets(path = input$file))
        } else {
            return(NULL)
        }
    })


apple_data <- reactive({
        req(input$file)
        inFile <- input$file
        if(is.null(inFile))
            return(NULL)
        file.rename(inFile$datapath,
                    paste(inFile$datapath, ".xlsx", sep=""))
        p<-read_excel(paste(inFile$datapath, ".xlsx", sep=""), 
    sheet = sheet_names() [str_detect(sheet_names(), regex("(apple)"))]
        

    })

After tweaking around with various functions, I eventually found a way to do it using openxlsx. Sharing the solution below -

wb<- reactive({
        req(input$file)
        inFile<- input$file
        wb<-loadWorkbook(paste(inFile$datapath, ".xlsx", sep=""))
    })
    sheetnames <- reactive({
        req(input$file)
        if (is.null(input$file)) 
            return(NULL)
        
        sheet_names<-wb()$sheet_names
        })

apple_data <- reactive({
        req(input$file)
        inFile <- input$file
        if(is.null(inFile))
            return(NULL)
        file.rename(inFile$datapath,
                    paste(inFile$datapath, ".xlsx", sep=""))
        p<-read_excel(paste(inFile$datapath, ".xlsx", sep=""), 
    sheet = sheet_names() [str_detect(sheet_names(), regex("(apple)"))]
  })
Nil_07
  • 106
  • 1
  • 8

2 Answers2

0

You can try this code -

library(shiny)
library(readxl)

ui <- fluidPage(
  fileInput('file', 'Input'),
  tableOutput('table')
)

server <- function(input, output) {
  apple_data <- reactive({
    req(input$file)
    inFile <- input$file
    if(is.null(inFile))     return(NULL)
    sheetnames <- excel_sheets(path = inFile$datapath)
    read_excel(inFile$datapath, sheet = grep('apple', sheetnames, value = TRUE))
  })
  output$table <- renderTable(apple_data())

}

shinyApp(ui, server)
Ronak Shah
  • 377,200
  • 20
  • 156
  • 213
  • 1
    inFile$datapath will just give the location to the temporary file location and not the actual file location. Check [here](https://stackoverflow.com/questions/46118367/using-shiny-fileinput-to-get-path-only) to know why. – Nil_07 Jun 02 '21 at 17:47
  • That's true but you actually don't need actual file location to read the file. Temporary file location is enough to read the file so `inFile$datapath` works. I just tested my edited answer on one sample excel file and it works. Can you check that now? – Ronak Shah Jun 04 '21 at 02:23
  • It's working for renderTable but for some reason the file is not getting loaded for renderDataTable. Also I don't quite understand why the column headers have "." in place of spaces when we are using read_excel. For example "fruit 1" would become "fruit.1." – Nil_07 Jun 04 '21 at 10:48
  • Also integrating this in my app gives the following error - **Error in : `path` does not exist: ‘C:\Users\ABC\AppData\Local\Temp\RtmpuYW6Cb/b9698217e1e5475119f6db49/0.xlsx’** – Nil_07 Jun 04 '21 at 10:54
  • Well, R doesn't like column names with spaces in them hence it replaces them with a `"."` . In my code I had `sheet =` twice. Maybe that is what was causing an error for you? Can you test this in updated answer? – Ronak Shah Jun 04 '21 at 11:04
0

The issue in the OP's code is that the function sheet_names() is using the logical vector str_detect(sheet_names(), regex("(apple)")) as input. Instead it would be

...
sheet = sheet_names()[str_detect(sheet_names(), regex("(apple)"))])
...
akrun
  • 874,273
  • 37
  • 540
  • 662
  • That's a typographic error as rightly pointed but that would not solve the error as the function sheet_names() does not store the sheet names since the datapath that it looks in is the temporary file location. After scrutinizing, I have found a way to get the sheet names without actually using the datapath of the file updated. Edit 1 - Typographic error has been edited. Edit 2 - Solution has been updated – Nil_07 Jun 02 '21 at 17:39
  • No, this answer wouldn't work for the following reasons. Check [here](https://stackoverflow.com/questions/46118367/using-shiny-fileinput-to-get-path-only) – Nil_07 Jun 02 '21 at 17:45
  • @Nil_07 I was just pointing out an issue that i found in your code. If you think that it was wrong for me to mention or find out and pointing out to you, fine – akrun Jun 02 '21 at 17:47
  • 1
    Hey, I have already cast my vote but I don't have enough reputation to get it reflected. Thanks for the help bud! – Nil_07 Jun 02 '21 at 17:48
  • @Nil_07 it's ok. Sorry, I didn't test your code, but I was thinking that it may be the issue – akrun Jun 02 '21 at 17:53
  • 1
    Yes, that's understandable. :) – Nil_07 Jun 02 '21 at 18:00
  • Hey, I have another open question if you want to check out. It's [here](https://stackoverflow.com/questions/67768707/how-to-download-multiple-editable-datatable-outputs-in-r-shiny-in-one-xlsx-file) – Nil_07 Jun 02 '21 at 18:01
  • And another one [here](https://stackoverflow.com/questions/67811525/r-r-shiny-operator-is-invalid-for-atomic-vectors). It'll be great if you can help me. – Nil_07 Jun 02 '21 at 19:42
  • 1
    @Nil_07 i posted a comment there – akrun Jun 02 '21 at 19:42
  • Thank you so much! Check out the other question since it's a very interesting use case for developers! – Nil_07 Jun 02 '21 at 19:55
  • 1
    @Nil_07 Did that helped you. – akrun Jun 02 '21 at 19:56
  • Yes, it did help me. check comments – Nil_07 Jun 02 '21 at 19:57
  • 1
    done already! I'll use the threads to communicate if I get more such interesting use cases! – Nil_07 Jun 02 '21 at 20:02