Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flexdashboard - Modularise rCharts code

I'm trying to break some code for a dashboard down into modules. I'm having trouble with this rCharts code. I can run it as an app, but ideally I want to split it into UI and server functions so I can keep them in a package.

The code below shows the working code in an app and the broken code as a module. Could anyone point out what I'm doing wrong please?

Thanks

---
title: "Example"
output: 
  flexdashboard::flex_dashboard:
runtime: shiny
---

```{r setup, include=FALSE}
library(flexdashboard)
library(shiny)
library(rCharts)
X <- data.frame(Var1 = rep(1:10, 3),
                Var2 = rep(c("control", "treatment1", "treatment2"), each = 10),
                Freq = abs(rnorm(30, 0, 1))
)
```

Column {data-width=650}
-----------------------------------------------------------------------

### Broken Code as Module

```{r}
ui2 = function(id) {
  ns = NS(id)

  mainPanel(plotOutput("plot1", height = "100%"),
            showOutput(ns("histogram"), "nvd3"))
}

server2 = function(input, output, session) {
      output$histogram <- renderChart2({
        n2 <- nPlot(Freq ~ Var1, group = 'Var2', data = X, type = 'multiBarChart')
        n2$set(width = session$clientData$output_plot1_width)
        n2
      })
}

ui2("example")
callModule(server2, "example")
```

Column {data-width=350}
-----------------------------------------------------------------------

### Working Code as App

```{r}
shinyApp(
  ui = mainPanel(
        plotOutput("plot2", height = "100%"),
        showOutput("histogram", "nvd3")
      ),

  server = function(input, output, session) {
      output$histogram <- renderChart2({
        n2 <- nPlot(Freq ~ Var1, group = 'Var2', data = X, type = 'multiBarChart')
        n2$set(width = session$clientData$output_plot2_width)
        n2
      })
    }
)
```

### Template

```{r}

```

Update in response to @HubertL's reply

The below code, when appended to the main body above illustrates the way flexdashboard can run shiny apps as standalone functions (note the runtime: shiny in the header).

The stand alone functions here can be stored in a library to be called at will, and do not need to be wrapped by shinyApp.

To clarify, the question I'm asking is how CAN I accomplish calling the rCharts plot as a series of standalone UI and server functions, as I can do with normal plots, or if this isn't possible, why not?

Stand Alone Example
======================================================================

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

```{r}
## UI for choosing species
iris_plotUI = function(id) {
  ns = NS(id)

  # User choices for line
  list_species = list(
    "Setosa" = "setosa",
    "Versicolor" = "versicolor",
    "Virginica" = "virginica"
  )

  flowLayout(
    # input: Tube line selection
    selectInput(
      ns("type"),
      label = h3("Select Species:"),
      choices = list_species,
      selected = "setosa"
    )
  )
}

# server module
iris_plot = function(input, output, session) {
  library(MASS)
  library(data.table)

  dt = data.table::copy(iris)
  data.table::setDT(dt)

  iris_filtered = reactive({
    dt[Species == input$type]
  })

  output$scatter = renderPlot({
    plot(iris_filtered()$Petal.Width, 
       iris_filtered()$Petal.Length)
  })

}

# plotting module
iris_plotOutput = function(id) {
  ns = NS(id)

  plotOutput(ns("scatter"))
}

## call inputs in the sidebar
iris_plotUI("ns_iris")
```

Column
-----------------------------------------------------------------------

```{r}
## all server module and plot (plot in main panel) 
callModule(iris_plot, "ns_iris")
iris_plotOutput("ns_iris")
```

WRT to the naming conventions, this has been clarified in the blog post's comments. The message:

It's a bit unclear to me, do the suffixes UI, Input, Output affect behavior or is that a suggested naming convention?

has been answered by one of the authors:

Just a suggested naming convention, they don't affect anything.

like image 811
Akhil Nair Avatar asked Nov 08 '22 12:11

Akhil Nair


1 Answers

There are 2 small problems with your code:

1. The naming of the module functions doesn't follow the documentation you are referring to

A module’s UI function should be given a name that is suffixed with Input, Output, or UI

and

Module server functions should be named like their corresponding module UI functions, but without the Input/Output/UI suffix

Here I renamed them myUI() and my():

myUI = function(id) {
        ns = NS(id)
        mainPanel(plotOutput("plot1", height = "100%"),
                  showOutput(ns("histogram"), "nvd3"))
}

my = function(input, output, session) {
        output$histogram <- renderChart2({
                n2 <- nPlot(Freq ~ Var1, group = 'Var2', data = X, type = 'multiBarChart')
                n2$set(width = session$clientData$output_plot1_width)
                n2
        })
}

2. The way you call the the module server functions like if they were stand-alone

Instead they have to be called by ui() and server() which are themselves called by shinyApp().

ui <- fluidPage(
  myUI("example")
)

server <- function(input, output, session) {
  callModule(my, "example")
}

shinyApp(ui, server)
like image 98
HubertL Avatar answered Nov 15 '22 06:11

HubertL