Apricot Apricot - 3 months ago 11
R Question

assigning dynamic variables to reshape idvar

My data frame:

structure(list(NEWSEC = c("A1", "A1", "A1", "A1", "A2", "A2",
"A2"), tiles = structure(c(1L, 2L, 3L, 4L, 1L, 2L, 3L), .Label = c("1st",
"2nd", "3rd", "4th"), class = c("ordered", "factor")), AVG = c(360,
594, 868, 1534, 349, 592, 861)), .Names = c("NEWSEC", "tiles",
"AVG"), row.names = c(NA, 7L), class = "data.frame")


It looks like this:

NEWSEC tiles AVG
1 A1 1st 360
2 A1 2nd 594
3 A1 3rd 868
4 A1 4th 1534
5 A2 1st 349
6 A2 2nd 592
7 A2 3rd 861


When I use reshape function from base R

reshape(df, idvar = "NEWSEC", timevar = "tiles", direction = "wide")


This works perfectly well...but my data frame is generated dynamically through a shiny application input where instead of NEWSEC I could select MARKET or CATEGORY. Normally I assign the input variable to an object and refer the object in my function. Example:

sec <- input$colvar


However, when I try similar approach with reshape it isn't working. My code so far:

reshape(df, idvar = sec, timevar = "tiles", direction = "wide").


I have also tried pasting the variable sec with quotes but didn't work.

reshape(df, idvar = paste(""",sec,""", sep = "), timevar = "tiles", direction = "wide").


I don't know if this is right...but just tried.

Answer

This part of code is correct

sec <- input$colvar
reshape(df, idvar = sec, timevar = "tiles", direction = "wide")

provided that you do this operations within a reactive context (reactive/render* functions) and provided that df already has these two new columns.

However, you dynamically add these two variables to your data frame df, so you have to do it within some reactive/eventReactive function, as for instance:

data <- reactive({
    # let's pretend that this only happens when some conditions are met
    new <- df
    new$Market <- gl(n = 2, k = 4, length = 7, labels = c("Market1", "Market2"))
    new$Category <- gl(n = 2, k = 4, length = 7, labels = c("Cat1", "Cat2"))
    new
  })

Say, now you want to reshape this new dynamic dataframe according to the selected id variable and then render it as a table. To do so you have to use renderTable function and access your new dataframe via data().

output$new <- renderTable({
    # access dynamic data frame "data" via "data()"
    sec <- input$colvar 
    reshape(data(), idvar = sec, timevar = "tiles", direction = "wide")
  })

Full example:

library(shiny)

df <- structure(list(NEWSEC = c("A1", "A1", "A1", "A1", "A2", "A2", 
                          "A2"), tiles = structure(c(1L, 2L, 3L, 4L, 1L, 2L, 3L),
                          .Label = c("1st", "2nd", "3rd", "4th"),
                          class = c("ordered", "factor")), 
                          AVG = c(360,594, 868, 1534, 349, 592, 861)), 
                          .Names = c("NEWSEC", "tiles", "AVG"), 
                          row.names = c(NA, 7L), class = "data.frame")

ui <- fluidPage(
  fluidRow(
    column(4, 
           selectInput("colvar", "Variable:", 
                        choices = c("NEWSEC", "Market", "Category"))
    ),
    column(8, 
           h4("old"), tableOutput("old")
    ),
    h4("new"), tableOutput("new"))
)


server <- function(input, output) {

  # dynamic data frame 
  data <- reactive({
    new <- df
    new$Market <- gl(n = 2, k = 4, length = 7, labels = c("Market1", "Market2"))
    new$Category <- gl(n = 2, k = 4, length = 7, labels = c("Cat1", "Cat2"))
    new
  })

  output$old <- renderTable({
    # access dynamic data frame "data" via "data()"
    data()
  })

  output$new <- renderTable({
    # access dynamic data frame "data" via "data()"
    sec <- input$colvar 
    reshape(data(), idvar = sec, timevar = "tiles", direction = "wide")
  })
}

shinyApp(ui = ui, server = server)