Creating dynamic plots in shiny

I'm trying to have a plot render based off of what the user selects for an input and having some trouble. I can get the Input options up fine and the output to render, but it shows all of the data instead of just what the user selects. I think I'm close, but something is a little off. Any guidance here would be awesome, self-taught if you can't tell!

TestDT = data.table(
  Team = c("Oregon", "Villanova", "Utah"),
  "eFG%" = c(".5", ".6", ".4"),
  "TOV%" = c(".3", ".1", ".6"),
  ORBRate = c(".7", ".5", ".6"),
  FTRate = c(".5", ".6", ".4")
)

ggplot(TestDT, aes(x=Team, y=ORBRate)) + geom_point()

ui <- basicPage(
  selectInput("Team", "Select Team",
            c("Oregon", "Villanova", "Utah")),
  plotOutput("teamPlot")
)

server <- function(input, output) {
  output$teamPlot <- renderPlot({
    ggplot(TestDT, aes(x=input$Team,y=ORBRate)) + geom_point()
  })
}

shinyApp(ui,server)

Hi!

It looks like in your code above, when you render the plot, you are not filtering the data by input$Team, thus rendering all points.

To achieve what you describe, you should filter the data, either with sth like dplyr::filter(Team == input$Team) or with subsetting TestDT[TestDT$Team == input$Team, ], or any other filtering strategy you may feel more comfortable with.

You can do this either before or within the ggplot call (in the data argument).

Example using dplyr::filter

library(dplyr)

server <- function(input, output) {
  output$teamPlot <- renderPlot({
    TestDT %>% 
      dplyr::filter(Team == input$Team) %>% 
      ggplot(., aes(x=Team,y=ORBRate)) + geom_point()
  })
}

HTH

That did the trick! Thank you so much. Any suggestions on how to get the average of the entire dataset plotted instead of the average of the filtered data. I tried moving it around, but am not having any success.

output$TeamTest <- renderPlot({
      TestDT1 %>%
        dplyr::filter(Team == input$Team) %>%
        ggplot(.,aes(x=question,y=response)) + labs(title="Offensive Overview", x="Team", y="Four Factors") + 
        stat_summary(fun=mean, geom = "point", shape =24, size=3, color="yellow", fill="yellow") + geom_point()

Sorry for the additional question, but really ppreciate the help

Mmm, not sure if this is related to the previous plot. I guess not. So, if you want the overall mean of your dataset, you should not filter it. Moreover, it seems you are using other variables (question and response) here that were not on the original dataframe.

So, you could do:

output$TeamTest <- renderPlot({
      TestDT1 %>%
        ggplot(.,aes(x=question,y=response)) + labs(title="Offensive Overview", x="Team", y="Four Factors") + 
        stat_summary(fun=mean, geom = "point", shape =24, size=3, color="yellow", fill="yellow") + geom_point()
)}

The "catch" here is that this plot would not be triggered by any input in your app, unless TestDT1 is a reactive expression.
So, if your aim was that, then you should add an observer or a conditional to the input$Team. I cannot be more specific with the information provided so far.

Cheers!

Ok I apologize I was not very clear there. What I am trying to do is get the entire dataset mean added to the same plot that I am putting the filtered out plots as well. For example, if I am plotting each variable for the selected input$Team, I want to have the entire dataset average plotted on the same axis for each variable as well if that makes sense. So it would create 2 points on each

Ah! Ok, so there are a couple of ways of doing that.
Here's one just off the top of my head. Depending on how the rest of your app is set-up this might be or not a good solution :sweat_smile:

  output$teamPlot <- renderPlot({
    TestDT %>% 
      mutate(
        ORBRate = as.numeric(ORBRate), # or change it where you define TestDT
        mean_ORB = mean(ORBRate)
      ) %>% 
      dplyr::filter(Team == input$Team) %>% 
      ggplot(., aes(x = Team, y = ORBRate)) + 
      stat_summary(aes(y = mean_ORB), fun="mean", geom = "point", shape =24, size=3, color="yellow", fill="yellow") +
      geom_point()
  })

Cheers!

Ok that makes sense, really appreciate it. I think I'm super close, but still getting tripped up. In my understanding to plot multiple variables the best way to do that is using pivot longer, but when I do that it makes the summary stat over all of the variables. I want unique values for each so the mean of eFG, TOV, etc. If I mutate before it doesn't allow me to use pivot longer and as a result plots them all on their own axis. Any workarounds on this? It is frustrating and awesome to make progress and get stuck.

Data:

  Team = c("Oregon", "Villanova", "Utah"),
  "eFG" = c(".5", ".6", ".4"),
  "TOV" = c(".3", ".1", ".6"),
  ORBRate = c(".7", ".5", ".6"),
  FTRate = c(".5", ".6", ".4"))

Transform:

  pivot_longer(eFG:FTRate, names_to = "question", values_to = "response") %>%
  mutate(
    response = as.numeric(response),
    mean_response = mean(response))

Plot:

  output$TeamTest <- renderPlot({
      TestDT1 %>%
        dplyr::filter(Team == input$Team) %>%
        ggplot(.,aes(x=question,y=response)) + labs(title="Offensive Overview", x="Team", y="Four Factors") + 
        stat_summary(aes(y = mean_response), fun = "mean", geom = "point", shape=1, size=3, color="magenta", fill="magenta") + geom_point()```

Ha! Ok, this whole question is kinda suffering from moving target syndrome :dart:

In any case, I'm not sure what you're looking for, but here's an attempt to have both by-Team and overall data for each variable. The key here is that you can preprocess your data outside your shiny app (static_table in my example below) and only filter it upon user interactions (better still, you could save your data before and only load it within your shiny session).

TestDT = data.table(
  Team = c("Oregon", "Villanova", "Utah"),
  "eFG%" = c(".5", ".6", ".4"),
  "TOV%" = c(".3", ".1", ".6"),
  ORBRate = c(".7", ".5", ".6"),
  FTRate = c(".5", ".6", ".4")
)

static_table <- 
  left_join(
    TestDT %>% 
      mutate(across(-Team, as.numeric)) %>% 
      pivot_longer(-Team, names_to = "question", values_to = "response") ,
    TestDT %>% 
      mutate(across(-Team, ~mean(as.numeric(.x)))) %>% 
      pivot_longer(-Team, names_to = "question", values_to = "mean_response"),
    by = c("Team", "question")
    )

ui <- basicPage(
  selectInput("Team", "Select Team",
              c("Oregon", "Villanova", "Utah")),
  plotOutput("teamPlot")
)

server <- function(input, output) {
  output$teamPlot <- renderPlot({
    static_table %>% 
      dplyr::filter(Team == input$Team) %>% 
      ggplot(.,aes(x=question,y=response)) + labs(title="Offensive Overview", x="Team", y="Four Factors") + 
      stat_summary(aes(y = mean_response), fun = "mean", geom = "point", shape=1, size=3, color="magenta", fill="magenta") + 
      geom_point()
  })
  
}

shinyApp(ui,server)

Sorry for the slow reply on this one, been busy at work. But you are the man, this comment made me laugh when I saw it haha!! I apologize, I will give this a try and try to make sure I really know what I'm looking for moving forward!