1

I'm really new to R Shiny (starting playing with it today!), but this code isn't working for me... R keeps saying "the data must be given as dataframe." which, as far as I can tell, it is a dataframe (and it says it is when I check with is.data.frame).

# Load packages ----
library(shiny)
library(fmsb)

# Load data ----
industry <- read.csv("data/industry.csv")

# User interface ----
ui <- fluidPage(
  titlePanel("L&D Capabilities 2023"),
  
  sidebarLayout(
    sidebarPanel(
      helpText("Check which L&D capabilities your industry
      has in-house in 2023."),
      
      selectInput("var", 
                  label = "Choose a variable to display",
                  choices = c("Central government", 
                              "Local government",
                              "IT and Telecoms", 
                              "Professional services, law and accountancy", 
                              "Finance, banking and insurance", 
                              "Health", 
                              "Social care/housing association", 
                              "Other charity/voluntary sector", 
                              "Retail", 
                              "Engineering", 
                              "Manufacturing", 
                              "Pharmaceutical", 
                              "Transport", 
                              "Utilities", 
                              "Hospitality", 
                              "Education (HE, FE)", 
                              "Art, media and design", 
                              "Other", 
                              "Consulting"),
                  selected = "Central government"),
    ),
    
    mainPanel(plotOutput("radarPlot"))
  )
)

# Server logic ----
server <- function(input, output) {
  output$radarPlot <- renderPlot({
    data <- switch(input$var, 
                   "Central government" = industry$Centralgov,
                   "Local government" = industry$Localgov,
                   "IT and Telecoms" = industry$IT,
                   "Professional services, law and accountancy" = industry$PS,
                   "Finance, banking and insurance" = industry$Finance,
                   "Health" = industry$Health,
                   "Social care/housing association" = industry$Social,
                   "Other charity/voluntary sector" = industry$Charity,
                   "Retail" = industry$Retail,
                   "Engineering" = industry$Engineering,
                   "Manufacturing" = industry$Manufacturing,
                   "Pharmaceutical" = industry$Pharmaceutical,
                   "Transport" = industry$Transport,
                   "Utilities" = industry$Utilities,
                   "Hospitality" = industry$Hospitality,
                   "Education (HE, FE)" = industry$Education,
                   "Consulting" = industry$Consulting,
                   "Art, media and design" = industry$Art,
                   "Other" = counties$Other)
    
    radarchart(data)
  })
}

# Run app ----
shinyApp(ui, server)

Any ideas what's going on? Or what I'm missing?

Many thanks!

EDIT: here's my data

> dput(industry)
structure(list(Max = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1), Min = c(0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), Centralgov = c(0.6, 
0.18, 0.27, 0.27, 0.27, 0.27, 0.36, 0.3, 0.55, 0.45, 0.1, 0, 
0.1, 0.27, 0.64, 0.09, 0.09, 0.18, 0.27, 0, 0.09, 0.18, 0.25, 
0.29, 0.14), Localgov = c(0.36, 0.5, 0.36, 0.5, 0.42, 0.42, 0.09, 
0.27, 0.36, 0.55, 0.3, 0.36, 0.55, 0.45, 0.73, 0.36, 0.18, 0.45, 
0.64, 0.36, 0.27, 0.18, 0.3, 0.2, 0.6), IT = c(0.73, 0.33, 0.47, 
0.51, 0.38, 0.18, 0.34, 0.38, 0.62, 0.41, 0.19, 0.38, 0.49, 0.41, 
0.62, 0.32, 0.22, 0.38, 0.58, 0.51, 0.33, 0.34, 0.41, 0.15, 0.37
), PS = c(0.73, 0.4, 0.56, 0.6, 0.48, 0.48, 0.29, 0.24, 0.63, 
0.56, 0.29, 0.41, 0.27, 0.36, 0.71, 0.28, 0.16, 0.48, 0.4, 0.52, 
0.36, 0.38, 0.29, 0.25, 0.13), Finance = c(0.9, 0.44, 0.66, 0.66, 
0.61, 0.52, 0.44, 0.5, 0.86, 0.62, 0.32, 0.39, 0.48, 0.59, 0.86, 
0.3, 0.27, 0.5, 0.52, 0.52, 0.57, 0.51, 0.56, 0.33, 0.29), Health = c(0.88, 
0.33, 0.47, 0.65, 0.28, 0.37, 0.33, 0.29, 0.78, 0.47, 0.18, 0.13, 
0.47, 0.5, 0.78, 0.26, 0.16, 0.41, 0.58, 0.5, 0.38, 0.39, 0.33, 
0.13, 0.29), Social = c(0.7, 0.25, 0.5, 0.33, 0.3, 0.2, 0.1, 
0.4, 0.5, 0.2, 0, 0.22, 0, 0.2, 0.4, 0.1, 0.3, 0.1, 0.3, 0.3, 
0.33, 0.3, 0.33, 0, 0.11), Charity = c(0.8, 0.55, 0.62, 0.44, 
0.5, 0.31, 0.08, 0.33, 0.58, 0.5, 0.4, 0.36, 0.33, 0.38, 0.82, 
0.15, 0.08, 0.36, 0.22, 0.42, 0.2, 0.42, 0.18, 0.22, 0.11), Retail = c(0.62, 
0.38, 0.46, 0.27, 0.25, 0.09, 0.08, 0.31, 0.82, 0.46, 0.25, 0.27, 
0.25, 0.54, 0.69, 0.08, 0.17, 0.31, 0.67, 0.5, 0.33, 0.5, 0.38, 
0.18, 0.08), Engineering = c(0.6, 0, 0.4, 0.25, 0.17, 0.17, 0, 
0, 0.33, 0.5, 0.25, 0.33, 0.6, 0.17, 0.33, 0, 0, 0.33, 0.33, 
0.17, 0.17, 0.5, 0.2, 0, 0), Manufacturing = c(0.56, 0.22, 0.35, 
0.42, 0.42, 0.4, 0.24, 0.2, 0.56, 0.41, 0.24, 0.11, 0.21, 0.3, 
0.63, 0.1, 0, 0.25, 0.42, 0.58, 0.21, 0.35, 0.25, 0.33, 0.06), 
    Pharmaceutical = c(0.43, 0.25, 0, 0.71, 0.63, 0.25, 0.13, 
    0.13, 0.63, 0.43, 0, 0, 0, 0, 0.38, 0.25, 0.13, 0.38, 0.38, 
    0.5, 0, 0, 0.33, 0, 0.17), Transport = c(0.77, 0.62, 0.79, 
    0.57, 0.71, 0.64, 0.14, 0.5, 0.79, 0.46, 0.38, 0.21, 0.36, 
    0.38, 0.64, 0.43, 0.29, 0.21, 0.57, 0.64, 0.29, 0.54, 0.57, 
    0.36, 0.15), Utilities = c(1, 0.6, 0.4, 0.33, 0.2, 0.2, 0.6, 
    0.6, 0.8, 0.6, 0.25, 0.2, 0.8, 0.4, 1, 0.4, 0.4, 0.6, 0.4, 
    0.6, 0.2, 0.2, 0.2, 0.2, 0), Hospitality = c(0.67, 0, 0.67, 
    0.4, 0.67, 0.33, 0.33, 0.83, 0.83, 0.2, 0.67, 0.17, 0.2, 
    0.33, 0.83, 0.33, 0.33, 0, 0.67, 1, 0.5, 0.33, 0.33, 0.6, 
    0.33), Education = c(0.87, 0.33, 0.47, 0.53, 0.41, 0.38, 
    0.5, 0.47, 0.65, 0.41, 0.2, 0.31, 0.47, 0.65, 0.53, 0.24, 
    0.29, 0.38, 0.56, 0.41, 0.31, 0.19, 0.38, 0.27, 0.35), Consulting = c(0.67, 
    0.5, 0.67, 1, 0.33, 0.33, 0.17, 0.5, 1, 0.6, 0.33, 0.6, 0.4, 
    0.67, 0.5, 0.17, 0.17, 0.4, 0.6, 0.5, 0.5, 0.33, 0.4, 0.25, 
    0.25), Art = c(1, 0.2, 0.6, 0.5, 0.4, 0.2, 0.2, 0.6, 0.6, 
    0.4, 0.2, 0.2, 0.6, 0.5, 0.5, 0.2, 0.2, 0.2, 0.2, 0.6, 0.4, 
    0.4, 0.4, 0.2, 0.25), Other = c(0.67, 0.57, 0.71, 0.29, 0.57, 
    0.43, 0.14, 0.5, 0.67, 0.29, 0.57, 0.29, 0.43, 0.57, 0.71, 
    0.29, 0.43, 0.29, 0.43, 0.57, 0.71, 0.43, 0.5, 0.6, 0.4)), class = "data.frame", row.names = c("In-person classroom delivery", 
"Strategy and governance", "Stakeholder engagement", "Instructional design", 
"Crafting learning journeys / blended solutions", "Supporting ongoing workplace performance", 
"Facilitating social and collaborative learning", "Understanding learner behaviour", 
"Virtual classroom / webinar delivery", "Digital content development", 
"Performance consulting", "Business acumen", "Marketing and communications", 
"Coaching and mentoring", "Learning management / administration", 
"Analytics / data management", "Evaluating impact", "Technology/infrastructure", 
"Project management", "Leveraging L&D expertise", "Knowledge management", 
"Negotiation, persuasion, and influence", "Learning experience design", 
"Community engagement", "Research capabilities"))
DrBarnett
  • 13
  • 3
  • I'm going to guess that the error is specific to your data. It looks like you're new to SO; welcome to the community! If you want great answers quickly, it's best to make your question reproducible. This includes sample data like the output from `dput()` or `reprex::reprex()`. If your data is proprietary, use a built-in dataset or make some to simulate the problem. Check it out: [making R reproducible questions](https://stackoverflow.com/q/5963269). – Kat Jan 18 '23 at 17:29
  • Okay, I figured I would look at this a bit closer. `fmsb::radarplot` requires a minimum of three variables. So feeding that function one variable will not work. If you were not aware, you also must place the max value of each variable in row 1. You must place the minimum value of each variable in row 2. – Kat Jan 18 '23 at 17:47
  • Hi Kat, thank you so much for coming back to me! I've added my data to the original post above. You'll see it says the structure is a list, but that remains even when I try to change it using ```industry <- data.frame(industry)```. How do I feed the function with more than one variable, please? Many thanks in advance! – DrBarnett Jan 19 '23 at 11:40
  • Pretty much everything in R is actually a _list_. It's typically not noticeable until you start coding dynamic functions and methods. – Kat Jan 19 '23 at 19:21

1 Answers1

0

Update based on Request in Comment

If you want to allow multiple selections, the easiest manner in which to approach this is likely pivoting the data, then filtering for the selected fields. This makes color assignment as easy as assigning it to the column now housing the industry names (in other words, the column names in your current data frame).

The UI remains unchanged from my initial answer. I've added several comments as to what the code is doing. If there is anything that's unclear, let me know.

library(plotly)
library(shiny)
library(tidyverse)

ui2 <- fluidPage(
  titlePanel("With Plotly"),
  sidebarLayout(sidebarPanel(
    helpText("help goes here"),
    selectInput(
      "var", label = "Choose a field to plot", 
      multiple = T,                                       # <<- TRUE now 
      choices = setNames(
        names(industry)[3:21], 
        c("Central government", "Local government", "IT and Telecoms",
          "Professional services, law and accountancy", 
          "Finance, banking and insurance", "Health", 
          "Social care/housing association", "Other charity/voluntary sector", 
          "Retail", "Engineering","Manufacturing", "Pharmaceutical", "Transport",
          "Utilities", "Hospitality", "Education (HE, FE)", "Consulting", 
          "Art, media and design", "Other")), selected = "Central government")
  ), mainPanel(plotlyOutput("radarPlot")))
)

server4 <- function(input, output, session) {
  output$radarPlot <- renderPlotly({ 
    indus2 <- industry %>% rownames_to_column("rn") %>% # rownames to column
      pivot_longer(!rn, names_to = "field")             # pivot all but rownames
    filter(indus2, field %in% input$var) %>%            # filter for selections
      plot_ly(r = ~value, theta = ~rn, color = ~field,  # color by industry
              fill = "toself", type = "scatterpolar", mode = "markers") %>% 
      layout(polar = list(
        angularaxis = list(showticklabels = F),
        radialaxis = list(range = c(0, 1))
      ))
  })
}
# Run app ----
shinyApp(ui2, server4)

enter image description here

enter image description here



Original Answer

Like I mentioned in my comment, radarchart requires at least three variables.

In this solution, I set the plot to only render when there are at least three options selected. I've changed the creation of the dropdown to allow multiple selections (so that three can be selected.

ui <- fluidPage(
  titlePanel("Title"),
  sidebarLayout(sidebarPanel(
    helpText("help goes here"),
    selectInput(
      "var", label = "Choose at least three options to plot", 
      multiple = T, 
      choices = setNames(
          names(industry)[3:21], 
          c("Central government", "Local government", "IT and Telecoms",
            "Professional services, law and accountancy", 
            "Finance, banking and insurance", "Health", 
            "Social care/housing association", "Other charity/voluntary sector", 
            "Retail", "Engineering","Manufacturing", "Pharmaceutical", "Transport", 
            "Utilities", "Hospitality", "Education (HE, FE)", "Consulting", 
            "Art, media and design", "Other")), selected = "Central government")
      ), mainPanel(plotOutput("radarPlot")))
  )

server <- function(input, output, session) {
  output$radarPlot <- renderPlot({
    if(length(input$var) >= 3) {
      radarchart(industry[, input$var])
    }
  })
}

# Run app ----
shinyApp(ui, server)

enter image description here

However, this is not technically accurate since the first row is supposed to be the max value. The second row is supposed to be the min value. (Which is how your data frame is orientated if you transpose it.)

Here's another version of the server. In this version, I've modified the data so that the first and second rows are the max and min.

# add max and min to the top of every column
industry2 <- t(industry) %>% 
  as.data.frame() %>% 
  mutate(max = 1, min = 0) %>% 
  select(max, min, everything()) %>% 
  t() %>% as.data.frame()

server2 <- function(input, output, session) {
  output$radarPlot <- renderPlot({
    if(length(input$var) >= 3) {
      radarchart(industry[, input$var])
    }
  })
}

# Run app ----
shinyApp(ui, server2)

This renders an identical plot to what I pictured for the first version (so I am not sure why the radarchart function calls for this information.)


I'm not sure how attached you are to fmsb::radarchart, but there are a lot of other options: ggplot2, plotly, highcharter, echarts, etc.

Here's an alternative using the Plotly library. In this option, I've set multiple in selectInput to false (based on what you were originally trying to plot). I've set the range so the graphs are comparable. A few other changes are annotated in the comments in the code.

library(plotly)
library(shiny)

ui2 <- fluidPage(
  titlePanel("With Plotly"),
  sidebarLayout(sidebarPanel(
    helpText("help goes here"),
    selectInput(
      "var", label = "Choose a field to plot", 
      multiple = F,      # <<- FALSE now (can remove argument, default is false)
      choices = setNames(
        names(industry)[3:21], 
        c("Central government", "Local government", "IT and Telecoms",
          "Professional services, law and accountancy", 
          "Finance, banking and insurance", "Health", 
          "Social care/housing association", "Other charity/voluntary sector", 
          "Retail", "Engineering","Manufacturing", "Pharmaceutical", "Transport", 
          "Utilities", "Hospitality", "Education (HE, FE)", "Consulting", 
          "Art, media and design", "Other")), selected = "Central government")
  ), mainPanel(plotlyOutput("radarPlot"))) # <<-- plotlyOutput instead of plotOutput
)

server3 <- function(input, output, session) {
  output$radarPlot <- renderPlotly({ # <- render plotly instead of plot
      plot_ly(r = industry[, input$var], theta = rownames(industry),
              fill = "toself", type = "scatterpolar", mode = "markers") %>% 
      layout(
        polar = list(
        angularaxis = list(showticklabels = F),
        radialaxis = list(range = c(0, 1))
      ))
  })
}
# Run app ----
shinyApp(ui2, server3)

I hid the labels, because they overlapped. However, when you hover, you can see the row names.

enter image description here

Kat
  • 15,669
  • 3
  • 18
  • 51
  • Thanks so much Kat, this is great and working for me! Is it possible to overlap multiple industries? When I change 'multiple = F' to 'T' it allows me to select multiple industries but isn't showing the data correctly. It'd also be cool to change the colours of each industry etc. when I have that working. Thanks for all your help! – DrBarnett Mar 17 '23 at 12:53
  • I've edited my answer to show you a method you can use for multiple selections. Let me know if you have any questions. – Kat Mar 18 '23 at 18:50
  • This has worked perfectly, thanks loads Kat!! – DrBarnett Mar 22 '23 at 09:13