2

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

Phil
  • 7,287
  • 3
  • 36
  • 66
Wade Schuette
  • 1,455
  • 1
  • 8
  • 9
  • I thought maybe the server was only getting the column name and didn't know what the dataframe name was so I tried things like paste("dfx$", input$xcol) instead of input$xcol but that doesn't work either, – Wade Schuette Jun 17 '21 at 18:55
  • 1
    (1) where is `ggplot2` here? You're calling `plot`, which is likely to be base R graphics, not [tag:ggplot2]. (2) Don't use the [tag:rstudio] tag unless you have an issue with the IDE of RStudio; problems with plots developed within the IDE are not relevant unless they work outside of RStudio (e.g., Rterm) but not within the IDE. – r2evans Jun 17 '21 at 18:59
  • 1
    Sorry, I'll stick to very limited tags then. I'm just not sure whether i have a problem with R or with Rstudio, or with plot/ggplot, or with Shiny!!!! As to the wrong title of the post, i had started the post with ggplot but then thought I"d try something simpler to see if ithe problem persisted. I tried multiple plots and ggplots and got the title wrong on this pass. by the way I get the same result when using ggplot instead of plot. gg <- ggplot(df, aes( x = input$xcol , y = input$ycol )) + geom_point() plot(gg) – Wade Schuette Jun 17 '21 at 19:05
  • you can't use `$` with string column names. See https://stackoverflow.com/questions/18222286/dynamically-select-data-frame-columns-using-and-a-character-value. In general you can't just `paste()` strings as code and expect them to work. You would need to parse and evaluate the string (but there are usually better ways to do that) – MrFlick Jun 17 '21 at 19:06
  • MrFlick I just read that stack overflow prior post and am totally lost. Do you think you could answer my original question? What am I doing wrong and how should I have written the code so it will do what I obviously intend it to do? – Wade Schuette Jun 17 '21 at 19:11
  • I found that prior stack overflow prior post confused more than helped. . I'm too lost to point vaguely to a lot of theory and words, I just want one very specific piece of help. Is what I'm doing possible? Can shiny run a plot or ggplot against a data frame? And if so, instead of "Plot(input$xcol" what should I have used so that the right column of the right dataframe is communicated to the plot function? A pointer to an example of shiny doing same that works would be sufficient. – Wade Schuette Jun 17 '21 at 19:22

2 Answers2

5

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()
MrFlick
  • 195,160
  • 17
  • 277
  • 295
  • 1
    MrFlick, Bless you!!! THAT is exactly what I needed. I confirmed both solutions work ( plot and ggplot ). Now I can complete my work task and later go back and learn what the referenced prior post and df[[ ]] and even stranger ".data[[ ]]" are all about. I managed to punt my way this far without ever encountering "[[ ]]" or ".data". – Wade Schuette Jun 17 '21 at 19:38
  • 1
    I found a nice post for newbies on double square brackets in R. https://davetang.org/muse/2013/08/16/double-square-brackets-in-r/ – Wade Schuette Jun 17 '21 at 20:27
0

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)
Wade Schuette
  • 1,455
  • 1
  • 8
  • 9