Class Meeting 24 (10) DashR: Layouts and Styling Dashboards

This lecture is 100% complete.

24.1 Today’s Agenda (10 mins)

  • Announcements:
    • New thing: I wil post the repl.it for each class here
    • Today’s code
  • Part 1: Recap of multi-level callbacks [10 mins]

  • Part 2: Restructuring the dash app [15 mins]
    • Moving plot functions to dash_functions.R
    • Moving components to dash_components.R
    • Using source(path/to/file.R) to load objects
  • Part 3: Layouts in Dash [45 mins]
    • Header
    • Sidebar
    • Multi-column layouts
    • Link to layout templates (by Matthew)
  • Part 4: Looking ahead [5 mins]

24.2 Part 1: Recap of multi-level callbacks [10 mins]

Recap:

  • clickData
  • ggplotly(p) %>% layout(clickmode = 'event+select')
  • ...+ scale_color_manual(name = 'Continent', values = continent_colors) + ...
  • Callbacks:
app$callback(
    #update figure of gap-graph
    output=list(id = 'gap-graph', property='figure'),
    #based on values of year, continent, y-axis components
    params=list(input(id = 'y-axis', property='value'),
                            input(id = 'yaxis-type', property='value')),
    #this translates your list of params into function arguments
    function(yaxis_value, yaxis_scale) {
        make_plot(yaxis_value, yaxis_scale)
    })

####NEW: updates our second graph using linked interactivity
app$callback(output = list(id = 'gap-graph-country', property = 'figure'),
             params = list(input(id='y-axis', property='value'),
                           # Here's where we check for graph interactions!
                           input(id='gap-graph', property='clickData')),
            function(yaxis_value, clickData) {
                 # clickData contains $x, $y and $customdata
                 # you can't access these by gapminder column name!
                 country_name = clickData$points[[1]]$customdata
                 make_country_graph(country_name, yaxis_value)
            })

24.3 Part 2: Restructuring the dash app [15 mins]

Live demo:

  • suppressPackageStartupMessages(library(plotly))
  • suppressPackageStartupMessages(library(tidyverse))
  • Delete htmlIframe(... that we added for empty spacing, we’ll learn a better way today!
  • Comment out callbacks (for faster reloading) and set debug=TRUE
  • Move functions to a new file called dash_functions.R (optional)
  • Move components to a new file called dash_components.R (optional)
  • At the top of your main app, source the two files above:
source('dash_functions.R')
source('dash_components.R')
  • Just like we created Dash components and stored them as variables, let’s also create layout elements and store them as variables:
## Specify App layout

app$layout(
    htmlDiv(
        list(
            heading_title,
            heading_subtitle,
            #selection components
            htmlLabel('Select y-axis metric:'),
            yaxisDropdown,
            htmlLabel('Select y scale : '),
            logbutton,
            #graph
            graph,
            graph_country,
            sources
        )
    )
)

to:

## Specify layout elements

div_header <- htmlDiv(
  list(heading_title,
       heading_subtitle
  )
)

div_sidebar <- htmlDiv(
  list(htmlLabel('Select y-axis metric:'),
       htmlBr(),
       yaxisDropdown,
       htmlLabel('Select y scale : '),
       htmlBr(),
       logbutton,
       sources
  )
)

div_main <- htmlDiv(
  list(graph,
       graph_country
  )
)

## Specify App layout

app$layout(
  div_header,
    htmlDiv(
      list(
        div_side_bar,
        div_main
      )
    )
)

24.4 Part 3: Layouts and styles in Dash [45 mins]

24.4.1 Styles

## Add this property after your list of components
style = list(
            backgroundColor = '#337DFF', ## COLOUR OF YOUR CHOICE
            textAlign = 'center',
            color = 'white',
            margin = 5,
            marginTop = 0
            )

Run your app, make sure everything still works - you should notice your header is now a different colour and centered on the page.

  • Add styles to your sidebar:
style = list('background-color' = '#BBCFF1',
                         'padding' = 10)

Here is a handy title of useful CSS properties:

CSS property Dash style What does it do ?
color color Sets the text color for elements
margin-top marginTop
margin-bottom marginBottom
margin margin Sets the amount of space outside a block element (in pixels)
text-align textAlign [Aligns text left, right, center or justify] (https://www.w3schools.com/cssref/pr_text_text-align.ASP)

Outside of this, there are hundreds of properties you could control to set every pixel where you want it to be - we will not fuss with such minutiae here! For your apps, you are welcome to be as creative as you like. If you have questions about how to do specific things, post on the Discussions repo as an issue and I’ll try and get to it.

24.4.2 Diving deeper into htmlDivs

Whiteboard sketch of what’s going on…

24.4.3 Flexbox

Let’s quickly do a whirlwhind tour of the flexbox options that we will most likely use.

The first thing to understand is that the flexbox “system” has properties for the “flex container” and the “flex items” within a flex container. The images from CSS-Tricks below illustrate the differences nicely.

First, here’s the container:

And the items within the container:

To use the flexbox layout system in Dash, the first thing you need to do is attach the 'flex' = 'display' property on a parent htmlDiv container.

Here is how to do it:

Start with a layout:

## Specify App layout

app$layout(
    htmlDiv(
      list(
        # Div1 : for say, a sidebar
        # Div2 : for the main content     
      )
    )
)

to:

## Specify App layout

app$layout(
    htmlDiv(
      list(
        # Div1 : for say, a sidebar
        # Div2 : for the main content     
      ), style = list('display' = 'flex')
    )
)

There are many additional properties we could specify using the style property in Dash.

In fact, it is also possible to set style properties for individual elements (divs) in a parent container. To do this, simply attach the style = list() to the appropriate div.

For example, let’s say we wanted to make sure the sidebar took up at least 30% of the width in our container. We would need to add 'flex-basis' = '30%' as a style property to the “item” inside a container.

style = list('flex-basis' = '30%'),

A through guide to the flexbox may be useful if you want to explore options.

Here are the (most important) flex properties summarized in a table for you:

Flex property (Dash syntax) Container or Item? What does it do ?
‘display’ = ‘flex’ Container Creates flexbox div
‘flex-wrap’ = ‘wrap’ Container Controls whether elements wrap if window size is reduced
‘justify-content’ = ‘center’ Container Justifies items within a container
‘flex-basis’ = ‘20%’ Item Defines the default size of an element before the remaining space is distributed.

24.4.4 Other layout examples

Feel free to explore one of the layouts from this repo created by Matthew as a starting point for your project apps.

24.4.5 Final app

For full participation marks today, in your repository you should have a functioning app with all the elements (including restructuring the app) we discussed today in class.

24.5 Part 4: Looking ahead [5 mins]

Here are three examples of deployed dashboards look like in R once layouts have been applied to them. These were done by former students:

24.5.1 Before next class

Heroku ID: ## YOUR ID HERE