Wade Schuette
Wade Schuette

Reputation: 1473

Why does the same ggplot work direct but fail in Shiny?

When I create a tiny dataframe and run both a direct plot to the PLOT tab in RStudio, followed by an attempt to run the same concept in Shiny, the direct plot works and the Shiny plot comes out blank with the error message:

Warning in xy.coords(x, y, xlabel, ylabel, log) :
  NAs introduced by coercion

What am I doing wrong?

I based this code attempt on reading on the web and a prior answer here in Stack Overflow so it's close, but I'm missing some implicit conversion or something. I just want to use Shiny to plot two columns of a data frame.

 library(shiny)

dfx <- data.frame(xx=c(1,2,3,4,5),
                  yy=c(2,4,6,8,10))


plot(dfx$xx, dfx$yy, xlim=c(0,6), ylim=c(0,10))

# the result in PLOTS in RStudio is a 5 point rising line graph as expected.

ui <- fluidPage(
  headerPanel('my first shiny app'),
  sidebarPanel(
    selectInput('xcol', 'X Variable', names(dfx)),
    selectInput('ycol', 'Y Variable', names(dfx))
  ),
  mainPanel(
    plotOutput('plot1')
  )
)

server <- function(input, output) {
  output$plot1 <- renderPlot({
    plot(input$xcol, input$ycol, xlim=c(0,6), ylim=c(0,10))
  })
}

shinyApp(ui = ui, server = server)

# the result of this in shiny is a blank graph

Upvotes: 3

Views: 360

Answers (2)

Wade Schuette
Wade Schuette

Reputation: 1473

So aside from the double square brackets notation solution mentioned above, which works, and explained here davetang.org/muse/2013/08/16/double-square-brackets-in-r –
I want to document that there is also a solution using "reactive", such as the following, where the "reactive" function dynamically looks up the value described by the column name text field, and then (don't forget!) the "variables" so defined (Xvalues, Yvalues) are treated as if they are functions (which they end up being) so the syntax requires putting "()" after them when using them.. The following works:

 library(shiny)

df <- data.frame(xx=c(1,2,3,4,5),
                 yy=c(2,4,6,4,2))

# the result in PLOTS in RStudio is a 5 point rising line graph as expected.

ui <- fluidPage(
  headerPanel('my first shiny app'),
  sidebarPanel(
    selectInput('xcol', 'X Variable', names(df)),
    selectInput('ycol', 'Y Variable', names(df))
  ),
  mainPanel(
    plotOutput('plot1')
  )
)

server <- function(input, output) {

  Xvalues <- reactive({ df[,input$xcol] })
  Yvalues <- reactive({ df[,input$ycol] })
  output$plot1 <- renderPlot({
      plot(Xvalues(), Yvalues(), xlim=c(0,6), ylim=c(0,10))
  })

}

shinyApp(ui = ui, server = server)

One example I found is explained for newbies here

https://campus.datacamp.com/courses/case-studies-building-web-applications-with-shiny-in-r/shiny-review?ex=12

which states:

Reactive contexts

Reactive values are special constructs in Shiny; they are not seen anywhere else in R programming. As such, they cannot be used in just any R code, reactive values can only be accessed within a reactive context.

This is the reason why any variable that depends on a reactive value must be created using the reactive() function, otherwise you will get an error. The shiny server itself is not a reactive context, but the reactive() function, the observe() function, and all render*() functions are.

An example provided in the "Shiny from RStudio" tutorial at https://shiny.rstudio.com/tutorial/ In the downloadable content's first case, in the file "app.R" they used "reactive" this way but I didn't understand what it was doing, which is slightly obscured by using reactive to process TWO data column vectors at once! This runs.

 # 01-kmeans-app 

palette(c("#E41A1C", "#377EB8", "#4DAF4A", "#984EA3",
  "#FF7F00", "#FFFF33", "#A65628", "#F781BF", "#999999"))

library(shiny)

ui <- fluidPage(
  headerPanel('Iris k-means clustering'),
  sidebarPanel(
    selectInput('xcol', 'X Variable', names(iris)),
    selectInput('ycol', 'Y Variable', names(iris),
      selected = names(iris)[[2]]),
    numericInput('clusters', 'Cluster count', 3,
      min = 1, max = 9)
  ),
  mainPanel(
    plotOutput('plot1')
  )
)

server <- function(input, output) {

  selectedData <- reactive({
    iris[, c(input$xcol, input$ycol)]
  })

  clusters <- reactive({
    kmeans(selectedData(), input$clusters)
  })

  output$plot1 <- renderPlot({
    par(mar = c(5.1, 4.1, 0, 1))
    plot(selectedData(),
         col = clusters()$cluster,
         pch = 20, cex = 3)
    points(clusters()$centers, pch = 4, cex = 4, lwd = 4)
  })

}

shinyApp(ui = ui, server = server)

Upvotes: 0

MrFlick
MrFlick

Reputation: 206506

In shiny, input$xcol is just a string that's returned from the UI. So if you use those values, it's like calling

plot("xx", "yy", xlim=c(0,6), ylim=c(0,10))

which returns the same error you get in Shiny.

If you want to get the values from your data.frame, you need to do dfx[[input$xcol]]. So try

plot(dfx[[input$xcol]], dfx[[input$ycol]], xlim=c(0,6), ylim=c(0,10))

Of course plot() is the base R plotting command. If you did want to use ggplot, you'd use something like

ggplot(dfx) +
  aes(.data[[input$xcol]], .data[[input$ycol]]) + 
  geom_point()

Upvotes: 5

Related Questions