Skip to content

Instantly share code, notes, and snippets.

@psychemedia
Last active May 4, 2024 22:33
Show Gist options
  • Save psychemedia/9737637 to your computer and use it in GitHub Desktop.
Save psychemedia/9737637 to your computer and use it in GitHub Desktop.
How to load desktop CSV file into R/Sshiny app.

Minimal R shiny app demonstrating:

  1. how to upload a CSV file into an R/shiny app
  2. how to automatically populate list selectors based on column headers
  3. how to use optional list selectors
  4. how to populate a list selector with column names of numerical columns only
  5. how to use an action button to trigger an event when you're ready to do so

Download and install:

In RStudio run:

install.packages("shiny")

then

library(shiny)

followed by

runGist(9737637)

We can make this file beautiful and searchable if this error is corrected: It looks like row 2 should actually have 3 columns, instead of 2 in line 1.
fromble,toble,amountify
"London, UK","Cambridge,UK"
"Cambridge,UK","Paris, France",17
"Paris,France","New York,US",24
"Sydney, Australia","Cape Town, South Africa",12
##This should detect and install missing packages before loading them - hopefully!
list.of.packages <- c("shiny","ggmap")
new.packages <- list.of.packages[!(list.of.packages %in% installed.packages()[,"Package"])]
if(length(new.packages)) install.packages(new.packages)
lapply(list.of.packages,function(x){library(x,character.only=TRUE)})
shinyServer(function(input, output) {
#This function is repsonsible for loading in the selected file
filedata <- reactive({
infile <- input$datafile
if (is.null(infile)) {
# User has not uploaded a file yet
return(NULL)
}
read.csv(infile$datapath)
})
#The following set of functions populate the column selectors
output$toCol <- renderUI({
df <-filedata()
if (is.null(df)) return(NULL)
items=names(df)
names(items)=items
selectInput("to", "To:",items)
})
output$fromCol <- renderUI({
df <-filedata()
if (is.null(df)) return(NULL)
items=names(df)
names(items)=items
selectInput("from", "From:",items)
})
#The checkbox selector is used to determine whether we want an optional column
output$amountflag <- renderUI({
df <-filedata()
if (is.null(df)) return(NULL)
checkboxInput("amountflag", "Use values?", FALSE)
})
#If we do want the optional column, this is where it gets created
output$amountCol <- renderUI({
df <-filedata()
if (is.null(df)) return(NULL)
#Let's only show numeric columns
nums <- sapply(df, is.numeric)
items=names(nums[nums])
names(items)=items
selectInput("amount", "Amount:",items)
})
#This previews the CSV data file
output$filetable <- renderTable({
filedata()
})
#This function is the one that is triggered when the action button is pressed
#The function is a geocoder from the ggmap package that uses Google maps geocoder to geocode selected locations
geodata <- reactive({
if (input$getgeo == 0) return(NULL)
df=filedata()
if (is.null(df)) return(NULL)
#The function acts reactively when one of the variables it uses is changed
#If we don't want to trigger when particular variables change, we need to isolate them
isolate({
#Get the CSV file data
dummy=filedata()
#Which from/to columns did the user select?
fr=input$from
to=input$to
#If locations are duplicated in from/to columns, dedupe so we don't geocode same location more than once
locs=data.frame(place=unique(c(as.vector(dummy[[fr]]),as.vector(dummy[[to]]))),stringsAsFactors=F)
#Run the geocoder against each location, then transpose and bind the results into a dataframe
cbind(locs, t(sapply(locs$place,geocode, USE.NAMES=F)))
})
})
#This reactive function is essentially chained on the previous one
geodata2 <- reactive({
if (input$getgeo == 0) return(NULL)
df=filedata()
if (input$amountflag != 0) {
maxval=max(df[input$amount],na.rm=T)
minval=min(df[input$amount],na.rm=T)
df$b8g43bds=10*df[input$amount]/maxval
}
gf=geodata()
df=merge(df,gf,by.x=input$from,by.y='place')
merge(df,gf,by.x=input$to,by.y='place')
})
output$geotable <- renderTable({
if (input$getgeo == 0) return(NULL)
geodata2()
})
})
shinyUI(pageWithSidebar(
headerPanel("CSV File Upload Demo"),
sidebarPanel(
#Selector for file upload
fileInput('datafile', 'Choose CSV file',
accept=c('text/csv', 'text/comma-separated-values,text/plain')),
#These column selectors are dynamically created when the file is loaded
uiOutput("fromCol"),
uiOutput("toCol"),
uiOutput("amountflag"),
#The conditional panel is triggered by the preceding checkbox
conditionalPanel(
condition="input.amountflag==true",
uiOutput("amountCol")
),
#The action button prevents an action firing before we're ready
actionButton("getgeo", "Get geodata")
),
mainPanel(
tableOutput("filetable"),
tableOutput("geotable")
)
))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment