2

I tried to use flexdashboard to make interactive vizualisation of word embeddings results, but I don’t get the logic behind the use of shiny modules.

In my Rmd dashboard, after loading the needed libraries, I first load the 3 models I want to deal with:

---
title: "Embedding Explorer"
output: 
  flexdashboard::flex_dashboard:
    orientation: rows
    vertical_layout: fill
    runtime: shiny
---

```{r setup, include=FALSE}
library(flexdashboard)
library(wordVectors)
library(plotly)
library(shiny)
library(shinyjs)
```

```{r global, include=FALSE}
model_1 = wordVectors::read.vectors('./models/word_embeddings_1.bin')
model_2 = wordVectors::read.vectors('./models/word_embeddings_2.bin')
model_3 = wordVectors::read.vectors('./models/word_embeddings_3.bin')
```

Then I would like each component of my dashboard to load a specific module. In the sidebar for instance, I want to display a selectInput object to select one of the models. To do so, I have coded a R script module Models.R:

# UI function
selectModelInput <- function(id) {
  ns <- NS(id)
  tagList(
  selectInput(ns("target_model"),label="Target model",c("gloVe","Word2Vec","Fasttext"))
)
}

# Server function
selectModel <- function(input, output,session) {
   observeEvent(input$target_model,{
     if (input$target_model=="gloVe"){
       model = model_1
    }else if (input$target_model=="Word2Vec"){
      model = model_2
    }else if (input$target_model=="Fasttext"){
      model = model_3
    }
output$model <- model #add an output element
    })
}

Thus, I call this module in my Rmd file:

```{r sidepanel}
# include the module
source("./modules/Models.R")

# call the module
selectModelInput("mod")
model <- callModule(selectModel,"mod") #add model in variable

renderText("Vocabulary size:")
renderPrint(nrow(model))
renderText("Embeddings dim:")
renderPrint(ncol(model))

```

Doing so, I have an error message stating that ‘model’ object does not exist. Maybe the problem is that the module doesn’t have access to the model_x from the global part? Or do I miss something allowing to save the ‘model’ object somewhere? By the way, I don’t really understand the call module behavior (especially, what is the role of the id argument "mod" or whatever?).

I precise that I have already developed a classical Shiny app which works perfectly (server / ui, no modules used), but I want to make the vizualisation more "professional"...

Thanks for any help!

UPDATE: By curiosity, I have printed the "model" output:

selectModelInput("mod")
model <- callModule(selectModel,"mod")
renderPrint(model)

And this is the result:

<Observer>
  Public:
.autoDestroy: TRUE
.autoDestroyHandle: function () 
.createContext: function () 
.ctx: environment
.destroyed: FALSE
.domain: session_proxy
.execCount: 2
.func: function (...) 
.invalidateCallbacks: list
.label: observeEvent(input$target_model)
.onDomainEnded: function () 
.onResume: function () 
.prevId: 13
.priority: 0
.suspended: FALSE
clone: function (deep = FALSE) 
destroy: function () 
initialize: function (observerFunc, label, suspended = FALSE, priority =  0, 
onInvalidate: function (callback) 
resume: function () 
run: function () 
self: Observer, R6
setAutoDestroy: function (autoDestroy) 
setPriority: function (priority = 0) 
suspend: function () 

It seems that 'model' variable is not what is expected (ie model_1, model_2 or model_3)... Why?

Tau
  • 173
  • 1
  • 8

1 Answers1

0

The problem is that the environment inside the module is basically treated like it would be in a function. Consider the following code

fun <- function(x) {
  result <- x + 1
  result ## return the result
}

fun(2)

result
#> Error: object 'result' not found

This above issue can be resolved by saving the return value of the function in a variable

res <- fun(2)
res
#> 3

You need to apply the same logic to your modules: everything that comes out of the module has to be returned by the module-server-function, which is selectModel in your case.

model <- callModule(selectModel,"mod")

If that where not the case, the namespacing would make no sense at all since several modules would write to the same variable at the same time.

Regading your more general question "What does callModule do?". Basically it makes it so all input- and output-ids are prefixed. That means that if input$target_model is used inside a module with id mod, this will actually get input[["mod-target_model"]]. You can think of this as creating a "folder" for your input and output ids which makes sure your ids do not collide with one another. In this analogy, mod would be the folder name and target_model would be a file inside that folder.

Gregor de Cillia
  • 7,397
  • 1
  • 26
  • 43
  • Thanks for your answer, it is much more clearer to me. Nonetheless I still have an issue: the "model" variable is not the xpected model (model_x). I think my selectMoedl function is not correct, but I don't see why. I have added an output variable like this: `output$model <- model` within the observeEvent (see my updated code), but I get 2 errors: `$defineOutput: Unexpected VectorSpaceModel output for mod-model` and `Reading objects from shinyoutput object not allowed` – Tau Jan 08 '19 at 13:12
  • PS: I was wondering: does my selectModel function know what model_1, 2 or 3 are (defined in the global variables section of Rmd)? Could it be the problem? – Tau Jan 08 '19 at 13:26