Search code examples
rshinyk-meansflexdashboard

How to take userinput in flexdashboard shiny as number of cluster to run kmeans in r?


I am new to shiny/flexdashboard and so far have been able to render plots and filter dataframe by using values from selectInput with help of req(input$user_input_value) .

ISSUE: To run kmeans I am taking user input for number of clusters which I am not able to code it in reactive format and getting error: object of type closure is not subsettable.

```{r setup, include=FALSE}
library(flexdashboard)
library(shiny)
library(tidyverse)
library(tidytext)
library(scales)
library(glue)
library(widyr)
library(factoextra)
```

df

                               1            2           3            4
Angola               -0.08260540  0.034325891 -0.02013353 -0.014063951
Armenia              -0.06613693 -0.044308626 -0.13230387 -0.024534033
Azerbaijan           -0.07562365 -0.003670707  0.05886792 -0.219660410
Bahrain              -0.08275891  0.035843793 -0.02280102 -0.008044934
Bangladesh           -0.08306371  0.032998297 -0.02634819 -0.017627316
Bosnia & Herzegovina -0.06303898 -0.050781511 -0.15183954  0.016794674

(Note: I have placed the csv file in github & mentioned its link below. For kmeans the character column should be used as rownames which represents country here.)

UPDATED df CREATION STEP

svd_dimen_all_wide <- read.csv(url("https://raw.githubusercontent.com/johnsnow09/covid19-df_stack-code/main/svd_dimen_all_wide.csv"))

svd_dimen_all_wide <- as.data.frame(svd_dimen_all_wide)

rownames(svd_dimen_all_wide) <- svd_dimen_all_wide$X

svd_dimen_all_wide <- svd_dimen_all_wide[,2:ncol(svd_dimen_all_wide)]

flexdashboard

---
title: "UN Country Votes"
output: 
  flexdashboard::flex_dashboard:
    orientation: columns
    vertical_layout: fill
    theme: space
runtime: shiny
---

```{r setup, include=FALSE}
library(flexdashboard)
library(shiny)
library(tidyverse)
library(tidytext)
library(scales)
library(glue)
library(widyr)
library(factoextra)
Page NAme 
=====================================



Inputs {.sidebar}
-----------------------------------------------------------------------


```{r}
  selectInput("number_of_clusters", label = h3("Number of Clusters"), 
      choices = c(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15) , 
                selected = 6)
```


Column {data-width=1000}
-----------------------------------------------------------------------

```{r include=FALSE}
set.seed(123)

km.res <- reactive({
  
      # req(input$number_of_clusters)                
  
      kmeans(svd_dimen_all_wide, as.numeric(input$number_of_clusters), nstart = 25)
    })

      df_with_cluster <- cbind(svd_dimen_all_wide, cluster = km.res$cluster)

      df_with_cluster <- rownames_to_column(df_with_cluster, "country")

      df_with_cluster <- df_with_cluster %>% 
       select(country, cluster, everything())
```

UPDATED ATTEMPT:


renderPrint({
  df_with_cluster <- cbind(svd_dimen_all_wide, cluster = km.res()$cluster)
  
  df_with_cluster <- rownames_to_column(df_with_cluster, "country")

  df_with_cluster <- df_with_cluster %>%
                      select(country, cluster, everything())
  
  head(df_with_cluster)
})
### Comparison of Countries on Yes% of Bi Words

```{r}
renderPlot({
  world_data %>%
  left_join((df_with_cluster %>%
               mutate(country_code = countrycode(country, "country.name", "iso2c"))
             ),
            by = c("country_code")) %>%
  filter(!is.na(cluster)) %>%
  ggplot(aes(x = long, y = lat, group = group,
             fill = as.factor(cluster))) +
  geom_polygon() +
  theme_map() +
  scale_fill_discrete() +
  labs(fill = "cluster",
       title = "World Clusters based on UN voting",
       caption = "created by ViSa") +
  theme(plot.title = element_text(face = "bold", size = 16))
}) 
```

Solution

  • The problem is in a reactive chunk. The reactive expression km.res uses an input number of clusters, runs a model, and saves the output. (and let's end the code chunk here).

    Next, decide what do you want to do with the output?

    • to print the result, use renderPrint
    • to show as a plot, use renderPlot,
    • to show as a table, user renderTable, etc.

    Now Let's print the output of the model with renderPrint() the output can be accessed by calling the expression’s name followed by parenthesis, e.g., km.res()

       Column {data-width=1000}
        -----------------------------------------------------------------------
        
        ```{r include=FALSE}
        
        km.res <- reactive({
          
              req(input$number_of_clusters)
          
              set.seed(123)
          
              kmeans(svd_dimen_all_wide, as.numeric(input$number_of_clusters), nstart = 25)
            })
         ```
    
    
    
    ###
    
    ```{r model}
    renderPrint({
    
    df_with_cluster <- cbind(svd_dimen_all_wide, cluster = km.res()$cluster)
    head(df_with_cluster)
    
    })
    ```
    

    Here is my blog post very relevant to this problem https://towardsdatascience.com/build-an-interactive-machine-learning-model-with-shiny-and-flexdashboard-6d76f59a37f9?sk=922526470699966c3f47b24843404a15