boshek
boshek

Reputation: 4406

Inputting results of a correlation on ggplot2 figure in shiny

I am trying to display the results of a correlation on a ggplot2 figure within a shiny app. I am using the iris dataset for this example. Specifically I want the correlation of the two variables being called by the x and y inputs. And I can figure out exactly what I am doing wrong. I keep getting the error:

Warning: Error in cor.test.default: not enough finite observations

However, I know that this is not the case when I try evaluating the relationship outside the shiny app:

cor.test(iris$Sepal.Width, iris$Petal.Width, alternative = "two.sided", method="spearman")

I've wrapped my cor.test call within a reactive function and I am trying to display an element using geom_text. Below are both my ui.R and server.R code.

Can anyone spot what I am doing wrong here?

ui.R

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


dataset <- iris

shinyUI(pageWithSidebar(

  headerPanel("Iris Data Explore"),

  sidebarPanel(

    selectInput('x', 'X', names(dataset), names(dataset)[[2]]),
    selectInput('y', 'Y', names(dataset), names(dataset)[[4]]),
    selectInput('species', 'Species', levels(dataset$Species), "virginica"),
    selectInput('color', 'Color', c('None', names(dataset))),

    checkboxInput('smooth', 'Smooth'),
    checkboxInput('line', 'Line')
  ),

  mainPanel(
    plotOutput('plot')
  )
))

server.R

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


shinyServer(function(input, output) {

  dataset <- reactive({
    filter(iris,Species==input$species)
  })

  cordf <- reactive({
    cor.test(as.numeric(input$x), as.numeric(input$y), alternative = "two.sided", method="spearman")
  })

  output$plot <- renderPlot({

    p <- ggplot(dataset(), aes_string(x=paste0("`",input$x,"`"),
                                      y=paste0("`",input$y,"`")
                                      )) + 
      geom_point() +
      geom_text(data=cordf(), aes(x=mean(input$x), y=mean(input$y), label=paste0(cordf$estimate))) +
      ggtitle(paste0(input$species))

    if (input$color != 'None')
      p <- p + aes_string(color=input$color)


    if (input$smooth)
      p <- p + geom_smooth(aes(group=1))
    if (input$line)
      p <- p + geom_line(aes(group=1), colour='seagreen')

    print(p)

  }, height=500)

})

Upvotes: 0

Views: 870

Answers (1)

fishtank
fishtank

Reputation: 3728

Problem is that dataset is not even defined in your function cordf(), hence the error "not enough finite observation".

The other problem is you can't just do mean(input$x) since input$x is just some string like Sepal.Length. I also think you want annotate rather than geom_text.

The modified server.R is below. I am not familiar with shiny so not sure if the way it is done is best practice.

server.R

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


shinyServer(function(input, output) {

  dataset <- reactive({
    filter(iris,Species==input$species)
  })

  cordf <- reactive({
    dataset<-dataset();
    cor.test(as.numeric(dataset[,input$x]), as.numeric(dataset[,input$y]), alternative = "two.sided", method="spearman")
  })

  output$plot <- renderPlot({
    dataset<-dataset()
    p <- ggplot(dataset, aes_string(x=paste0("`",input$x,"`"),
                                      y=paste0("`",input$y,"`")
                                      )) +
      geom_point() +
      annotate("text", x=mean(dataset[,input$x]),y=mean(dataset[,input$y]), label=cordf()$estimate) +
      ggtitle(paste0(input$species))

    if (input$color != 'None')
      p <- p + aes_string(color=input$color)


    if (input$smooth)
      p <- p + geom_smooth(aes(group=1))
    if (input$line)
      p <- p + geom_line(aes(group=1), colour='seagreen')

    print(p)

  }, height=500)

})

Upvotes: 1

Related Questions