1

I am building a Shiny dashboard that will allow me to select certain data from my postgresql database. I am new to shiny and postgresql so I appreciate your input on this. I am aiming at having a dynamic input from User, say click to select a name, a type, then the location for a certain data. And that the user can select it from a 3 selectinput widgets. The process of selecting the items will allow query of the data in the database. Lets say I have 7 names, 2 types and 3 locations.. so selecting a name, then a type, then a location will give me a part of the data. This is what my initial code looks like, but it does not give me any data showing up. I checked the connection and its working, it just doesn't can not find the data I am looking for plotting and displaying so I get an empty dashboard with no table or plot. Any idea how to go about this?


library(shiny)
library(shinydashboard)
library(RColorBrewer)
library(leaflet)
library(dplyr)
library(ggplot2)
library(tidyverse)
library(fpp)
library(plotly)
library(sp)
library(RPostgreSQL)
library(DBI)
library(pool)

#####


pool <- dbPool(drv = dbDriver("PostgreSQL", max.con = 100), user = "user", password = "pswd", host = "localhost", port = 5432, dbname = "people", idleTimeout = 3600000)

##list of people names
All<-tbl(pool, "table")
All%>%group_by(name)
names_All<- dbGetQuery(pool, "SELECT name FROM table GROUP BY name") ## list of names another way
type_grouped<- dbGetQuery(pool, "SELECT type FROM table GROUP BY type")
loc_grouped<- dbGetQuery(pool, "SELECT location FROM table GROUP BY location") 

####

ui <- fluidPage(
  sidebarLayout(
    sidebarPanel(
      selectInput(
        inputId = "name",
        label = " name",
        choices = names_All,
        selected = 1,
      ),
      selectInput(
        inputId = "type",
        label = " type",
        choices = type_grouped,
        selected = 1,
  
      ),
      selectInput(
        inputId = "location",
        label = " location",
        choices = loc_grouped,
        selected = 1,
      )
    ),
    mainPanel(
      tabsetPanel(
        tabPanel("graph", plotOutput("plot")),
        tabPanel("Table", dataTableOutput("table"))
      )
    )
)
)

server <- function(input, output, session) {

  selectedData <- reactive({
    req(input$name)
    req(input$type)
    req(input$location)
    query <- glue::glue_sql(
      "SELECT * FROM table
       WHERE name IN ({name*})
       AND type IN ({type*})
       AND location IN ({location*});",
      name = input$name,
      type = input$type,
      location=input$location,
      .con = pool)
    outp <- as.data.frame(dbGetQuery(pool, query))
    outp

  })

   
  output$table <- DT::renderDataTable({
    DT::datatable(  data = selectedData(),
                   options = list(pageLength = 14),
                    rownames = FALSE)
  
  
  output$plot <- renderPlot({
    ggplot( data = selectedData(), aes(x = date, y = name )) + geom_point()
  })
  
}

shinyApp(ui = ui, server = server)

App running result

second error imgae

rains
  • 23
  • 6
  • When you state `names_All<- dbGetQuery(pool, "SELECT name FROM table GROUP BY name") ` where is table defined? Also, you have a typo: `req(inputname)` should be `req(input$name)` – YBS Dec 31 '20 at 05:38
  • Your SQL is not correct as you have two `WHERE` clauses which should have raised an error. Check console for messages. – Parfait Dec 31 '20 at 05:44
  • @ YBS The table is the name of my table in the database 'people' specified in pool. So I don't have to declare it as a variable. Thanks for the note on the typo, I must have accidently delete it while typing in, but its all corrected now still no data. @Parfait its also a typo I just fixed it and still no data showing. – rains Dec 31 '20 at 06:21
  • Please [**edit**](https://stackoverflow.com/posts/65517000/edit) your post with actual code and not typos. We need to see *how* you fixed it. Also, post any errors that output to console. – Parfait Dec 31 '20 at 15:17
  • @Parfait thanks for pointing out I can edit the post. I had no idea I can do that, I fixed the typos. And re-run the code, nothing happened I get an empty table and plot. The selector choices are working though as I can see the options. But that does not change the data I want to select from the database. I attached the image in the edited post in the App running result link above. – rains Dec 31 '20 at 15:47

1 Answers1

1

Consider integrating a submit button to trigger processing of server code via an eventReactive call. This even helps user understand the flow of form controls and processing. Also, right now you use SQL's IN redundantly since input choices are only single values. But use multiple=TRUE argument in selectInput() to adjust that (with note to user).

User Interface

ui <- fluidPage(
  sidebarLayout(
    sidebarPanel(
      selectInput(
        inputId = "name",
        label = " name",
        choices = names_All,
        selected = 1
      ),
      selectInput(
        inputId = "type",
        label = " type",
        choices = type_grouped,
        selected = 1  
      ),
      selectInput(
        inputId = "location",
        label = " location",
        choices = loc_grouped,
        selected = 1
      ),
      actionButton("submit", "Submit")        # NEW SUBMIT BUTTON
    ),
    mainPanel(
      tabsetPanel(
        tabPanel("graph", plotOutput("plot")),
        tabPanel("Table", dataTableOutput("table"))
      )
    )
  )
)

Server Function

server <- function(input, output, session) {

  name_pick <- reactive({ req(input$name) })
  type_pick <- reactive({ req(input$type) })
  location_pick <- reactive({ req(input$location) }) 

  selectedData <- eventReactive(input$submit, { # INITIATE ON submit
    query <- "SELECT *                        
              FROM table
              WHERE name = ?name
                AND type = ?type
                AND location = ?location;"

    stmt <- DBI::sqlInterpolate(pool, 
                                query,
                                name = name_pick(),
                                type = type_pick(),
                                location = location_pick())

    outp <- dbGetQuery(pool, stmt)
  })

  output$table <- DT::renderDataTable({
    DT::datatable(data = selectedData(),
                  options = list(pageLength = 14),
                  rownames = FALSE)
  })

  output$plot <- renderPlot({
    ggplot(data = selectedData(), aes(x = date, y = name )) + 
       geom_point()
  })
  
}

Also, try avoiding SELECT * and explicitly define needed table and graph columns in specific order to control output of your Shiny result. Plus, it helps with readability and maintainability of code.

Parfait
  • 104,375
  • 17
  • 94
  • 125
  • Thank you Parfait. I managed to edit my code as per your comment. I can see changes happening the console when I click submit. However, I got this error, ***Warning: Error in eval: attempt to apply non-function***. Also just double checking, I think there is a missing bracket the line below outp after }) _)_ I was only able to run it after adding this one. Finally, the reason I am using SELECT *, is because I want all the column names , when I tried typing it in I got a syntax error. If I shall provide them all, would using ***SELECT name, etc FROM table*** work ? – rains Jan 01 '21 at 02:53
  • Actually there should not be an extra closing parentheses since I had an extra opening. Please try again with my edit and describe any error or undesired results not simply *it worked* or *it did not work*. Syntax error may be due to column names with spaces or special characters. Enclose such column names with double quotes using all lowercase. – Parfait Jan 01 '21 at 14:04
  • I have copied your code and use it as is. I got the above error attached as image in the post. I had to adjust location = location(), to **location = location_pick ()**, but kept the rest the same as your code. Let me know what you think. – rains Jan 01 '21 at 15:36
  • Error derives in UI section. See edits removing unneeded commas with small server fct fix. – Parfait Jan 01 '21 at 17:01
  • Thanks, I did the edits. Now I am getting this error message **Error:'data' must be 2-dimensional (e.g. data frame or matrix)** , where can I convert my table from the database to a data frame? – rains Jan 02 '21 at 01:24
  • Just noticed your `renderDataTable` did not properly separate from `renderPlot`. I edit with proper closing. – Parfait Jan 02 '21 at 02:53
  • I tried the edits you suggested. Here is the error I got when I clicked on submit **Error in eval: attempt to apply non-function**. – rains Jan 02 '21 at 10:12
  • Hmmm...testing code here, my R Shiny app powered by an SQLite database works great. [See my code](https://pastebin.com/zp3pRJM8). However, I did not use `pool` or `glue::glue_sql` but regular connection and `sqlInterpolate`. And my `ggplot` has more aesthetics. My guess is carefully test the `glue` query works on its own outside the Shiny app. – Parfait Jan 02 '21 at 21:24
  • Thank you for the link. I think the syntax between SQLite and postgresql to query databases is slightly different based on reading about it online since I don't use it. Would you know of any example using multiple selector inputs to query a postgresql database?? – rains Jan 03 '21 at 14:55
  • Both interface with R's `DBI`. Again, your ui does not select multiple inputs but one choice per dropdown so your SQL can use `=` instead of `IN`. Try replacing `glue` with `sqlInterpolate`. See edit. Also, try regular connection object instead of `pool`. – Parfait Jan 03 '21 at 19:48
  • Thank you @Parfait! You are a Gem. It worked like magic after I made the last changes you suggested. I am super thankful! – rains Jan 04 '21 at 14:31