34

For a new project I want to try the new flexdasboard package. I am thinking of a lay out in which the column and row orientation is somehow combined.

The layout I am thinking of is something like this:

enter image description here

If I change this code:

---
title: "Focal Chart (Left)"
output: flexdashboard::flex_dashboard
---

Column {data-width=600}
-------------------------------------

### Chart 1

```{r}
```

Column {data-width=400}
-------------------------------------

### Chart 2

```{r}
```   

### Chart 3

```{r}
```

into this:

---
title: "Focal Chart (Left)"
output: flexdashboard::flex_dashboard
---

Column {data-width=600}
-------------------------------------

### Chart 1

```{r}
```

Column {data-width=400}
-------------------------------------

Row {data-width=400}
-------------------------------------

### Chart 2

```{r}
```   

### Chart 3

```{r}
```   

Row {data-width=400}
-------------------------------------

### Chart 4

```{r}
```

(ofcourse) this doesn't work, but I haven't figured out the right way. Does anyone have an idea?

Tyler Rinker
  • 108,132
  • 65
  • 322
  • 519
rdatasculptor
  • 8,112
  • 14
  • 56
  • 81

4 Answers4

45

This does not seem possible using basic rows and columns, but can be achieved by using a sidebar to hold the content of the left hand panel. This will change the formatting of the left panel compared to the others, but its appearance can then be adusted to your liking by editing the css. Note that you can alter the width of the side bar using the data-width option e.g. {.sidebar data-width=300}

---
title: "Focal Chart"
output: 
  flexdashboard::flex_dashboard:
    orientation: rows
---

Column {.sidebar data-width=500}
-------------------------------------
### Chart 1
```{r}
```

Row {data-height=350}
-------------------------------------
### Chart 2
```{r}
```

### Chart 3
```{r}
```   

Row {data-height=650}
-------------------------------------
### Chart 4
```{r}
```

Which gives...

enter image description here

The appearance of the side bar can then be edited to your liking. For example:

To

  1. change the background color of the side panel to white (if you want it to match the other panels),
  2. align the top edge with the other panels, and
  3. add borders left and bottom to match the other panels:

edit the css style sheet for .section.sidebar to

.section.sidebar {
  top: 61px;
  border-bottom: 10px solid #ececec;
  border-left: 10px solid #ececec;
  background-color: rgba(255, 255, 255, 1);
}

To change the padding, use the data-padding option in flexdashboard markdown:

Column {.sidebar data-width=500 data-padding=10}

Now, it looks like this:

enter image description here

dww
  • 30,425
  • 5
  • 68
  • 111
  • Any way to keep the side bar layout controls and have the layout you provided? – Tyler Rinker Apr 22 '16 at 18:44
  • @TylerRinker Meaning you want to put shiny controls in the sidebar that looks like a panel, or you want to add a second sidebar (that looks more like a sidebar) to this layout? – dww Apr 22 '16 at 19:21
  • 1
    From the documentation "adding the {.sidebar} attribute to a column, which indicates that it should be laid out flush to the left... Sidebars always appear on the left no matter where they are defined within the flow of the document.", Which explains why adding more than one sidebar will always cause them to overlay eachother. – dww Apr 22 '16 at 23:02
  • For reference, I'd like to record that `data-width=500` in the sidebar didn't work for me, but instead `style='max-width: 500px;'` did. – Pablo Bernabeu Jun 09 '20 at 14:46
7

What you really need is the fillCol and fillRow functions. Take a look at this: http://shiny.rstudio.com/articles/gadget-ui.html#fillrowfillcol

sanyi14ka
  • 809
  • 9
  • 14
  • 1
    Can `fillCol` and `fillRow` be used in Flexdashboard? – Deqing Jun 25 '17 at 04:27
  • 1
    Yes, you can use it in Flexdashboard. – sanyi14ka Jun 26 '17 at 10:26
  • 3
    @sanyi14ka can you give an example ? – statquant Aug 05 '17 at 12:14
  • I can confirm fillCol/fillRow can be used. I am limited in the number of characters in the comment, so I can't fit a reproducable code, but here's a straw-man of what I tried: ` fillRow(fillCol(renderPlotly({...plot goes here...})), fillCol(renderPlotly({... plot goes here...}), renderGauge({... gauge goes here...})))` – Nikolay Nenov Jul 10 '18 at 17:34
7

I composed this flexdashboard example from what I found in the Shiny+flex site in RStudio using fillCol:

enter image description here

---
title: "Fill Layout"
output: 
  flexdashboard::flex_dashboard:
    orientation: columns
runtime: shiny
---

# Info {.sidebar data-width=350}

When you mix multiple Shiny inputs and/or outputs within a flexdashboard panel it’s good practice to have them fill the bounds of their container in the same way that other flexdashboard components like plots and htmlwidgets do. This is possible using the Shiny `fillRow` and `fillCol` layout functions.

For those familiar with Shiny here are further details on how this example works:

1. The container is laid out using the `fillCol` function, which establishes a single column layout with flexible row heights.

2. Flexible height behavior is defined via `flex = c(NA, 1)`. The `NA` applies to the first component (the input panel) and says to not give it flexible height (i.e. allow it to occupy it’s natural height). The `1` applies to the second component (the plot) and says that it should have flexible height (i.e. occupy all remaining height in the container).

3. The call to `plotOutput` includes `height = "100%"` to ensure that the plot takes advantage of the height allocated to it by the `fillCol` flexible layout.

4. Finally, note that unlike the simpler layout examples above this examples uses an explicit  `plotOutput` / `renderPlot` pairing rather than just a standalone `renderPlot`. This is so that the plot can be included in a more sophisticated layout scheme (i.e. one more like traditional ui.R layout).

# Use fillCol

```{r}
fillCol(height = 600, flex = c(NA, 1), 
  inputPanel(
    selectInput("region", "Region:", choices = colnames(WorldPhones))
  ),
  plotOutput("phonePlot", height = "100%")
)

output$phonePlot <- renderPlot({
  barplot(WorldPhones[,input$region]*1000, 
          ylab = "Number of Telephones", xlab = "Year")
})
```
f0nzie
  • 1,086
  • 14
  • 17
3

An alternative approach can be to use absolutepanels from shiny. Instead of trying to find a grid arrangement to fit all the pieces on screen, use an absolutepanel with folding buttons to selectively choose which boxes appear at a given time. This allows the user to choose which plots and information they want presented. The idea evolved from the superzip app https://shiny.rstudio.com/gallery/superzip-example.html, but works well in flexdashboard.

In the example below, plots can be made to appear or be hidden when the page loads. Click the buttons to make them appear or go away. This has been very useful when mixing leaflet with plots, to avoid drowning the map with plots (where as before plots were limited due to drowning issues).

enter image description here

enter image description here

---
  title: "Demo"
  output:
    flexdashboard::flex_dashboard:
      orientation: columns
      vertical_layout: fill
  ---


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

  ```

  Column {data-width=400}
  --------------------------------
  ### Planet Earth

  ```{r}

  library(leaflet)
  m = leaflet() %>% addTiles()
  m  # a map with the default OSM tile layer


  ```


  ```{r}
  #plot setup
  mtcars$am[which(mtcars$am == 0)] <- 'Automatic'
  mtcars$am[which(mtcars$am == 1)] <- 'Manual'
  mtcars$am <- as.factor(mtcars$am)

  p <- plot_ly(mtcars, x = ~wt, y = ~hp, z = ~qsec, color = ~am, colors = c('#BF382A', '#0C4B8E')) %>%
    add_markers() %>%
    layout(scene = list(xaxis = list(title = 'Weight'),
                       yaxis = list(title = 'Gross horsepower'),
                       zaxis = list(title = '1/4 mile time')))


  set.seed(100)
  d <- diamonds[sample(nrow(diamonds), 1000), ]


  ##########################
  absolutePanel(id = "controls", class = "panel panel-default", fixed = TRUE,
                draggable = TRUE, top = 70, left = "auto", right = 20, bottom = "auto",
                width = '30%', height = 'auto', 
                style = "overflow-y:scroll; max-height: 1000px; opacity: 0.9; style = z-index: 400",

              h4(strong("Plot Explorer")),

      HTML('<button data-toggle="collapse" data-target="#box1" class="btn-block btn-primary">dot plot</button>'),
      tags$div(id = 'box1', class="collapse in",

        plot_ly(d, x = ~carat, y = ~price, color = ~carat,
          size = ~carat, text = ~paste("Clarity: ", clarity)) %>% layout(height=200)

              ),

   HTML('<button data-toggle="collapse" data-target="#box2" class="btn-block btn-warning">histogram</button>'),
      tags$div(id = 'box2', class="collapse",

         plot_ly(x = rnorm(500), type = "histogram", name = "Histogram") %>% layout(height=200)
      ),


           HTML('<button data-toggle="collapse" data-target="#box3" class="btn-block btn-danger">spinny thing</button>'),
      tags$div(id = 'box3', class="collapse in",

          p %>% layout(height=200)
      )

   )

  ```
pdbentley
  • 430
  • 4
  • 9