How do I create a dataframe from merging csv files and then create a shiny app based on it?

Viewed 141

I have a question which may be stupid, but I just wanted to create my first R shiny app. I was thinking of writing a code in which 2 separate csv files would be read and then combined into a single dataframe. I need to add a couple columns in each dataframe before combining them, as shown in the code. So I thought I could manipulate the data outside of the ui and server and then create the app which would allow the user to select what they want to be plotted on each axis. The first part of the code outside the shiny part works fine and I get the desired combined dataframe. However, when I run the code the dataframe does not seem to be created and as such I end up with an empty interface.

Any help would be greatly appreciated! Attached I have a picture of the columns in one of the csv files, the second csv file is similar.

shop1.csv

library(tidyverse)
library(shiny)

twofiles<-c("shop1.csv","shop2.csv")

shop_list<-lapply(twofiles, read.csv, header=TRUE, sep=",")

shop_list<- lapply(seq_along(shop_list), function(i){

df <- shop_list[[i]]
df<-transform(df,ratio1=price_apples/price_pears)
df<-transform(df,ratio2=price_apples/price_cherries)
df<-transform(df,datano=i)
})

finaldata <- do.call(rbind, shop_list)
finaldata$datano <- factor(finaldata$datano)


ui<-fluidPage(

titlePanel("Shops plots"),

sidebarMenu(

selectInput(inputId = "x", label = "Select x-axis:",
            choices = c("Year"="year","Hour"="hour"), selected="year"),

selectInput(inputId = "y", label = "Select y-axis:",
            choices = c("Ratio 1"="ratio1","Ratio 2"="ratio2"),selected="ratio1"),

mainPanel(
  plotOutput("plot")
)
)
)


server<-function(input, output) {


output$plot <-renderPlot({

ggplot(finaldata, aes(x=input$x, y=input$y, group=datano, color = datano)) +
  geom_line()

})
}

shinyApp(ui=ui, server=server)
2 Answers

Too long for comments:

Here is the example code with the mtcars dataset:

You have to use aes_string not aes in ggplot.

Dataframe manipulation including loading etc.. should be done server side.

One more thing is that group=datano and color=datano may prone to the problem also. Try here yourdataframe$datano

library(shiny)
library(dplyr)
library(ggplot2)

ui<-fluidPage(
  
  titlePanel("XXX"),
  
  sidebarMenu(
    
    selectInput(inputId = "x", label = "Select x-axis:",
                choices = c("mpg"="mpg","disp"="disp"), selected="mpg"),
    
    selectInput(inputId = "y", label = "Select y-axis:",
                choices = c("hp"="hp","drat"="drat"),selected="hp"),
    
    mainPanel(
      plotOutput("plot")
    )
  )
)

server<-function(input, output,session) {
  
  output$plot <-renderPlot({
    
    ggplot(finaldata, aes_string(x=input$x, y=input$y, group=mtcars$cyl, color = mtcars$cyl)) +
      geom_line()
    
  })
}

shinyApp(ui=ui, server=server)

enter image description here

I think the problem you're having has nothing to do with the frame, but with programmatic use of ggplot2. In general, look up ggplot2 and quasiquotation and you'll find yourself in a quagmire of NSE (non-standard evaluation) mechanisms that you thought you'd never need (or never knew you would need, to be honest).

I can replicate some non-workingness with this simple non-shiny example.

library(ggplot2)
input <- list(x = "mpg", y = "disp")

This produces the wrong chart, just a single point:

ggplot(mtcars, aes(x=input$x, y=input$y)) + geom_point()

But if you switch to this, it should work:

ggplot(mtcars, aes(x=!!sym(input$x), y=!!sym(input$y))) + geom_point()

That is, using !!sym(input$x) instead of just input$x (and for anything else you will be placing within aes(...).

If you're curious, the older (soft-deprecated) solution would have been to use aes_string, which still works (but I don't know for how long):

ggplot(mtcars, aes_string(x=input$x, y=input$y)) + geom_point()

Side note:

  • I think it'd be a bit more direct (and code-golf simpler) to read in your data as:

    twofiles <- setNames(nm = c("shop1.csv","shop2.csv"))
    shop_list <- lapply(twofiles, read.csv, header=TRUE, sep=",")
    finaldata <- transform(
      dplyr::bind_rows(shop_list, .id = "datano"),
      ratio1 = price_apples/price_pears,
      ratio2 = price_apples/price_cherries,
      datano = factor(datano)
    )
    

    Though since you're already pulling in all of tidyverse, you might as well switch to the dplyr-methods ... not that it buys you a lot here.

Related