0

My situation is the following that I import a csv dataset from IMDB into my small Shiny app. It contains in the respective columns the values for runtime, IMDB-Rating, gross, votes, Meta-Score Rating etc...

I have in the UI-section a selectInput where the user can select the available columns as mentioned above.

In the Server-Section (before my output$graph <- renderPlot(...)) I want to describe/implement that the outputPlot changes depending on the selected column. I tried to solve it using observeEvent like this...

  observeEvent(~get(input$type) == "Meta-Score", {ratings <- moviesdb$Meta_score})
  observeEvent(~get(input$type) == "IMDB-Rating", {ratings <- moviesdb$IMDB_Rating})
  etc...

using the global operator <<- and even using some type of switch-case logic:

   x <- reactive(~get(input$type))
   y <- NULL
   test <- switch(c(x),
                  "Meta-Score" = {(ratings <- moviesdb$Meta_score)},
                  "IMDB-Rating" = {(ratings <- moviesdb$IMDB_Rating)},
                  "Film-Laufzeit" = {(ratings <- moviesdb$Runtime)})

I really appreciate any help/hints/tips or even mock-up code on how to solve this problem! Since yesterday I am googling but I just dont find any solution or question which seems to be similar to what I want to achieve.

Example Code:

library(shiny)
library(ggplot2)

moviesdb <- read.csv("imdb_top_1000.csv", header=TRUE)
moviesdb <- na.omit(moviesdb) #remove NA from data set

ui <- fluidPage(
  
  selectInput(
    inputId = "type",
    label = "choose type",
    choices = c("Meta-Score", "Votes"),
    selected = "Meta-Score",
    multiple = FALSE,
    selectize = TRUE,
    width = NULL,
    size = NULL
  ), 
  
  sliderInput(inputId = "num", label = "sample size", value = 500, min = 0, max = 800, step = 10), 
  plotOutput("distribution"),
  
)


server <- function(input, output) {
  
  ratings <- moviesdb$Meta_score
  # x <- reactive(~get(input$type))
  # y <- NULL
  # test <- switch(c(x),
  #                "Meta-Score" = {(ratings <- moviesdb$Meta_score)},
  #               "Votes" = {(ratings <- moviesdb$No_of_Votes)},
  # y

  # observeEvent(ratings, {
  #   print(paste0("You have chosen: ", ratings))
  # })

  
  output$distribution <- renderPlot(
    {
      
      filmratingssample <- (sample(ratings, input$num, replace = FALSE, prob = NULL))
      mean_films <- mean(filmratingssample)
      films <- data.frame(dnorm(filmratingssample, mean = mean_films, sd = 1, log = FALSE))
      
      ggplot(data = films) + aes(x=filmratingssample) +
        geom_histogram(aes(y=..density..), col = "white", binwidth=1)
      
      
      
    })

}

shinyApp(ui = ui, server = server)

Dataset from here

Data looks as followed:

Year    Runtime Meta_score  No_of_Votes Gross
1994    142 min 85,00   2343110 28,341,469
1972    175 min 84,00   1620367 134,966,411
2008    152 min 75,00   2303232 534,858,444
profshiny
  • 3
  • 2
  • Could you share the full code or some simple example that we can run? If you input is `input$type`, just use the switch on that and then get it from the reactive data as necessary e.g. `my_reactive_data()[[input$selected_column]]`? Also, avoid using `<<-` in R code or assigning global variables in any programming paradigm. There is always a better way. – NelsonGon Jan 12 '22 at 21:17
  • Please edit the question and add a simple `ui` and `server`. – NelsonGon Jan 12 '22 at 21:34
  • 1
    @NelsonGon: Hey Nelson, thank you for your message: I added the example code – profshiny Jan 12 '22 at 21:36
  • What do you want to do in the plot part ie how do you want to use `test` in `plot`? – NelsonGon Jan 12 '22 at 21:45
  • The variable `test` and `ratings` refer to the same thing (preferably I just want to use ratings). `ratings` should change to use `moviesdb$Meta_score` or `moviesdb$No_of_Votes` depending on the value of the dropdown menu and then use the data from the respective colum for the plot. I want to use this `ratings` variable as the basis for further calculations in the output$distribution part (eg pick a random sample, calculate the mean etc). – profshiny Jan 12 '22 at 21:54
  • See my edited answer below, I have no data to test. maybe you can dump a `head` of the data in the question for testing. – NelsonGon Jan 12 '22 at 22:03
  • Thank you very much for your time and patience! I attached a little bit of the data. I tried to implement and adjust your code but I interestingly get the error: "cannot take a sample larger than the population when 'replace = FALSE'" even though the dataset is big enough. – profshiny Jan 12 '22 at 22:15
  • Done below, works for me. Just change the column names to your own e.g. Metascore in my answer to the equivalent in your data and no problem, I love answering `shiny` questions. I get issues with `binwidth` for `Votes`. – NelsonGon Jan 12 '22 at 22:24
  • 1
    Yes it works great. If you remove it or use bins=30 instead of binwidth it looks beautiful :) I probably just used a too small value :) – profshiny Jan 12 '22 at 22:38

1 Answers1

1

We can do:

ui <- fluidPage(
  fileInput("movies_db", "Movie DB"),
  
  selectInput(
    inputId = "type",
    label = "choose type",
    choices = c("Meta-Score", "Votes"),
    selected = "Meta-Score",
    multiple = FALSE,
    selectize = TRUE,
    width = NULL,
    size = NULL
  ), 
  
  sliderInput(inputId = "num", label = "sample size", value = 500, min = 0, max = 800, step = 10), 
  plotOutput("distribution"),
  
)


server <- function(input, output) {
  
  ratings_data <- reactive(
    {
      df<-na.omit(read.csv(req(input$movies_db$datapath), header=TRUE))
      
     df 
      
    }  
  )
  
  
  
  output$distribution <- renderPlot(
    {
      ratings <- switch(input$type,
                         "Meta-Score" = ratings_data()[["Metascore"]],
                         "Votes" = ratings_data()[["Votes"]])
      
      filmratingssample <- (sample(ratings, 
                                   req(input$num),
                                   replace = FALSE, prob = NULL))
      mean_films <- mean(filmratingssample)
      films <- data.frame(dnorm(filmratingssample, mean = mean_films, sd = 1, log = FALSE))
      
      ggplot(data = films) + aes(x=filmratingssample) +
        geom_histogram(aes(y=..density..), col = "white", binwidth=1)
      
      
      
    })
  
}

shinyApp(ui = ui, server = server)


Result

enter image description here

NOTE:

I tested on data at https://raw.githubusercontent.com/peetck/IMDB-Top1000-Movies/master/IMDB-Movie-Data.csv

NelsonGon
  • 13,015
  • 7
  • 27
  • 57
  • 1
    Thank you so much for this solution and your time! I appreciate it a lot. All the best to you! – profshiny Jan 12 '22 at 22:32
  • I tried to use my original input `(moviesdb <- read.csv("imdb_top_1000.csv", header=TRUE) moviesdb <- na.omit(moviesdb) #remove NA from data set` but even with adjusting the code and column names etc I cannot get it to work. Do you have an idea what could be the reason / solution? Error is "Warning: Error in writeImpl: Text to be written must be a length-one character vector" – profshiny Jan 12 '22 at 22:58
  • I am not sure, use full file path for the read? Also, no need to wrap code in braces. As for your warning, it's not related to that line. You have probably made an error somewhere in UI elements. See https://stackoverflow.com/questions/58608109/text-to-be-written-must-be-a-length-one-character-vector @profshiny – NelsonGon Jan 13 '22 at 06:57