install.packages("flexdashboard")
6 Creating Data Dashboards
In data science and analytics, a dashboard is a visual display of information – often including charts, tables, and summary metrics – that consolidates data into an interactive, at-a-glance view. Dashboards serve as powerful tools for data communication, enabling users to monitor key performance indicators (KPIs), explore trends, and make informed decisions quickly. They are especially prevalent in business analytics, where companies rely on dashboards to share data insights across teams and drive strategic decisions. In fact, the vast majority of businesses use dashboards as a primary channel for communicating data insights; without dashboards, it would be almost impossible for many organizations to share data reports with all who need them. By presenting data in a visual and interactive format, dashboards help bridge the gap between data and decision-makers, allowing even non-technical users to grasp complex information intuitively.
Dashboards are not only crucial in corporate settings – they also play an important role in the public sector and open data initiatives. Governments and institutions use public-facing dashboards to share data with citizens, increasing transparency and accountability. For example, city governments might publish dashboards on budgets or environmental metrics to allow the public to see what is happening and to initiate informed conversations or actions. Research has highlighted that dashboards can connect governments with the public, helping to create transparency and foster trust. As such, well-designed dashboards become an important means of communicating and interacting with the public on data-driven issues, enabling broader audiences to engage with data in a meaningful way. Whether in a business or public context, dashboards turn raw data into accessible information stories, making them essential for modern data-driven decision making.
Beyond their communicative value, dashboards offer practical advantages. They provide timely data access – often updating in real-time or on a regular schedule – so that users are always looking at the latest information. They enable enhanced decision-making by highlighting trends and anomalies that might be missed in static reports. They can also improve efficiency by consolidating multiple reports or analysis views into a single interface. In summary, a dashboard serves as a single source of truth for a particular analysis or operational area, where users can interact with visuals and filters to answer their questions on the fly. By combining clarity, interactivity, and timeliness, dashboards have become indispensable in both business intelligence and public data communication.
6.1 Flexdashboard
Flexdashboard is an R package that makes it easy to create interactive dashboards using R Markdown. With flexdashboard, you can publish a group of related data visualizations as a dashboard – either as a static web page or an interactive Shiny app. Flexdashboard supports a wide variety of components, including htmlwidgets (R bindings to JavaScript libraries), base R or ggplot2 graphics, interactive tables, value boxes, gauges, and text annotations. It features flexible layouts (rows, columns, and tabsets) that intelligently adapt to fill the browser screen and even adjust for mobile devices. You can also incorporate Shiny to drive live data or user inputs in the dashboard. In short, flexdashboard brings together R Markdown reporting and Shiny interactivity for easy yet powerful dashboard creation.
Example of a flexdashboard with multiple components (heatmap and table). Flexdashboard allows assembling various charts and outputs into a responsive dashboard layout.
Key features of flexdashboard include:
-
R Markdown workflow: You write an R Markdown document and use the
flexdashboard::flex_dashboard
format to generate the dashboard. This keeps development simple and reproducible (mixing text, code, and results). - Rich components: Flexdashboard supports interactive visualizations via htmlwidgets, static plots from base R or ggplot2, data tables (with sorting/filtering), and special elements like value boxes (for key metrics) and gauges (for KPI meters).
- Flexible layouts: You can arrange components using rows and columns specified by section headers. The layout uses a CSS flexbox mechanism to automatically resize charts to fill the browser and even stacks into a single column on small screens (for mobile).
- Storyboards: In addition to typical grid layouts, flexdashboard offers a storyboard mode for presenting a sequence of charts with accompanying commentary in a step-by-step narrative style.
-
Optional Shiny interactivity: Flexdashboards can be static (purely viewer-side HTML/JS) or, if you specify
runtime: shiny
, they become dynamic Shiny apps where readers can input parameters and see results update live.
To get started, install the flexdashboard package from CRAN if you haven’t already:
This provides the flex_dashboard
output format for R Markdown. In RStudio, you can create a new Flexdashboard document by going to File > New File > R Markdown… > From Template > Flex Dashboard. This will open a template .Rmd
file with the necessary YAML header and structure. (If not using RStudio, you can use the rmarkdown::draft
function with the "flex_dashboard"
template to scaffold a new dashboard file.)
Creating a new Flex Dashboard document from RStudio’s template menu.
The top of your R Markdown should include YAML like this, which specifies the flexdashboard format and any options:
---
title: "Your Dashboard Title"
output:
flexdashboard::flex_dashboard:
orientation: columns # or rows
vertical_layout: fill # or scroll
storyboard: false # set true for storyboard layout
---
Here we set the overall layout orientation (columns vs. rows), and whether the dashboard should fill the page vertically or scroll (more on this below). With that in place, you structure the content of the dashboard using headings and code chunks.
6.2 Layout
Dashboards are organized into sections using headings. Flexdashboard uses the heading levels to define rows, columns, and chart panels:
-
Level 1 headings (
#
) define Pages (for multi-page dashboards, each becomes a top-level navigation tab). -
Level 2 headings (
##
) define Columns by default (or entire Rows iforientation: rows
is set globally or for that page). -
Level 3 headings (
###
) define individual chart sections within a column or row.
By default, flexdashboard assumes a column-oriented layout: each Level 2 heading starts a new column, and charts (Level 3) under it stack vertically within that column. You can also opt for a row-oriented layout by setting orientation: rows
(in YAML or for a specific page), in which case Level 2 headings create new rows, and charts under them distribute into columns within that row.
In addition, the vertical layout mode controls how charts fill the page vertically. The default vertical_layout: fill
causes the dashboard to fill the browser height – charts will expand/shrink vertically to fit the screen without scrolling. This is ideal if you have one or two charts stacked and want to use all available space. Alternatively, vertical_layout: scroll
will keep each chart at its natural height (as determined by its figure size), and allow the page to scroll if the content exceeds the screen. Scrolling layout is better when you have many components vertically and prefer not to squish them into one view.
Let’s look at a few common layout patterns:
Chart Stack (Fill)
This is the simplest layout: a single column with charts stacked vertically, filling the page. For example, two charts one above the other can be defined like so:
output:
flexdashboard::flex_dashboard:
vertical_layout: fill
---
### Chart 1
::: {.cell}
```{.r .cell-code}
<code to produce chart 1>
```
:::
### Chart 2
::: {.cell}
```{.r .cell-code}
<code to produce chart 2>
```
:::
With vertical_layout: fill
, these two charts will split the available vertical space in the browser roughly equally (unless one is given extra height explicitly). You could make one chart taller by adding a data-height
attribute on its section header, which adjusts the relative height allocation:contentReferenceoaicite:24. For instance, ### Chart 1 {data-height=500}
would allot more height to Chart 1 relative to Chart 2 in the fill layout.
Chart Stack (Scrolling)
If you have multiple charts stacked, a fill layout might cram them into a tight space. Using a scrolling layout lets each chart keep its natural height and simply adds a scrollbar for the page. For example:
output:
flexdashboard::flex_dashboard:
vertical_layout: scroll
---
### Chart A
::: {.cell}
```{.r .cell-code}
<chart A code>
:::
Chart B
<chart B code>
Chart C
<chart C code>
Here we have three charts in one column. With `vertical_layout: scroll`, each chart will be rendered at its default height (e.g. 480px tall by default):contentReference[oaicite:25]{index=25}, and the browser window will scroll to show all charts:contentReference[oaicite:26]{index=26}. This layout can easily accommodate many charts vertically (though if you have too many, you might consider breaking into multiple pages or using tabsets for better navigation:contentReference[oaicite:27]{index=27}).
### Focal Chart (Top)
Sometimes you want one visualization to stand out with more space, and supporting charts to be smaller. Flexdashboard allows **mixing rows and columns with custom sizes**. For example, a “Focal Chart Top” layout might have a large chart spanning the full width on the first row, and a second row with two smaller charts below it:contentReference[oaicite:28]{index=28}:
```yaml
---
output:
flexdashboard::flex_dashboard:
orientation: rows
---
Row {data-height=650}
-------------------------------------
### Big Chart (Top)
::: {.cell}
```{.r .cell-code}
# code for big chart
:::
6.3 Row
Chart 2
# code
Chart 3
# code
In the above, we explicitly set the first **Row** to 650px height and the second row to 350px (using `data-height` on the row headers):contentReference[oaicite:29]{index=29}. The first row contains a single **Big Chart** that gets the larger portion of vertical space (about 65% of the page), while the second row contains two charts side by side (since in a row-oriented layout, multiple Level 3 sections in the same row header will form columns in that row). This way, **Chart 2** and **Chart 3** share the bottom part of the screen, and the top chart remains the focal point.
### Focal Chart (Left)
You can also emphasize a chart by giving it more horizontal space. To create a **multi-column layout** with one wider column for a focal chart and a second narrower column for others, use Level 2 headings to start each column and specify `data-width` attributes. For example, here we split three charts across two columns, making the first column 60% width and the second 40%:
```yaml
output: flexdashboard::flex_dashboard
---
Column {data-width=600}
-------------------------------------
### Chart 1 (Main)
::: {.cell}
```{.r .cell-code}
# <code for main chart>
:::
6.4 Column
Chart 2
# <code>
Chart 3
# <code>
The above yields **Chart 1** in a left column that is 600px wide vs. a right column of 400px (total 1000px base, so roughly 60/40 split):contentReference[oaicite:30]{index=30}. Charts 2 and 3 stack in the right column. This is an example of a **“Focal Chart Left”** layout:contentReference[oaicite:31]{index=31} – one prominent chart on one side, with supporting charts on the other side.
### Tabsets
If you have several components that don't all need to be visible at once, you can organize them into **tabs**. Flexdashboard allows you to convert any column or row into a **tabset** by adding the `{.tabset}` attribute to its heading:contentReference[oaicite:32]{index=32}. Each Level 3 section under that heading will become a separate tab panel.
For instance, suppose you have one column that should show either Chart X or Chart Y (as two tabs). You can do:
```yaml
output: flexdashboard::flex_dashboard
---
Column
-------------------------------------
### Chart A
::: {.cell}
```{.r .cell-code}
# <code for chart A>
:::
6.5 Column
Chart X
# <code for chart X>
Chart Y
# <code for chart Y>
In this layout, the dashboard has two columns: the left column (no special classes) always shows **Chart A**, and the right column is a tabset that toggles between **Chart X** and **Chart Y**:contentReference[oaicite:33]{index=33}. Only one of X or Y is visible at a time, with tabs to switch. Tabsets are useful when you have multiple related visualizations but want to save space or avoid clutter by layering them in the same area:contentReference[oaicite:34]{index=34}. You can also apply tabsets at the row level (group entire rows into tabs similarly), and you can add the `.tabset-fade` class for a fading animation when switching tabs:contentReference[oaicite:35]{index=35}.
## Components
A flexdashboard can include any output you can generate from R, but there are a few special **components** worth noting:
- **Base R and ggplot2** graphics: Any plots produced by R code chunks will be included in the dashboard panels. These are static images (PNG/SVG) unless made interactive via a widget.
- **htmlwidgets**: These are R packages that bind JavaScript libraries (like Leaflet maps, Plotly plots, DT tables, etc.) and produce interactive web visuals. They work great in flexdashboard because they can automatically resize to fill their container:contentReference[oaicite:36]{index=36}:contentReference[oaicite:37]{index=37}.
- **Tables**: You can simply print a data frame or use packages like **DT** for interactive tables. Flexdashboard will include them, with scrolling or pagination as needed (and special behavior on mobile to ensure usability).
- **Value Boxes**: These display a big numeric value with a caption (and icon/color) to highlight key metrics.
- **Gauges**: These show a dial or meter representation of a value within a range.
- **Text and Markdown**: You can include narrative text, headers, lists, etc., in your dashboard sections to provide context or commentary.
Let's dive a bit deeper into **Value Boxes** and **Gauges** since they are unique to dashboard-style presentations:
### Value Boxes
A **value box** is a compact box that highlights a single value along with a label and an icon. They’re great for presenting KPIs or summary statistics (like "Total Sales: 1.2M" or "Conversion Rate: 5%"). In flexdashboard, you create one with the `valueBox()` function inside an R code chunk. For example:
::: {.cell}
```{.r .cell-code}
valueBox(45, title = "Articles per Day", icon = "fa-pencil")
:::
This would display a value box showing 45 and the caption “Articles per Day,” with a pencil icon. By default, value boxes are styled in a neutral color (or “primary” theme color). You can customize the color or make it conditional. For instance, you might use color = "warning"
or "success"
, or even a conditional expression:
spam <- 5
valueBox(spam, title = "Spam per Day", icon = "fa-trash",
color = ifelse(spam > 10, "warning", "primary"))
In this example, the color will be “primary” (blue) since spam is 5 (low), but if it exceeded 10 it would turn “warning” (often yellow/orange). The set of built-in color names includes primary, info, success, warning, danger, corresponding to Bootstrap theme colors. You can also use any custom CSS color code if needed.
Value boxes can include an icon on the right side. Flexdashboard supports icons from Font Awesome, Ionicons, and Bootstrap Glyphicons – you specify them by prefixing the icon name with fa-
, ion-
, or glyphicon-
respectively. For example, "fa-comments"
for a comment icon or "ion-social-twitter"
for a Twitter bird. (Note: not all icons from these sets are free or available by default, so some icons might not render if they require pro licenses.)
You can also make a value box into a hyperlink – for instance, if clicking the value should navigate to another page or section with more details. Use the href
argument to specify a page anchor (e.g., href="#details"
to link to a subsection titled “Details”).
Gauges
A gauge displays a numeric value on a semicircular meter, with zones indicating ranges (like red/yellow/green zones for bad/medium/good). In flexdashboard, you create gauges with the gauge()
function. The simplest usage is:
gauge(value = 37.4, min = 0, max = 50)
This will draw a gauge showing 37.4 on a 0–50 scale. By default the gauge will be a single color (the theme’s “success” color, typically green). You can define colored sectors for different ranges using gaugeSectors()
. For example:
In this case:
- Green (“success”) for values 41–50,
- Yellow (“warning”) for 21–40,
- Red (“danger”) for 0–20.
The gauge needle will point at 37.4, which falls in the warning (yellow) zone in this configuration. You can also add a symbol
argument (e.g., %
or $
) to append a unit to the displayed value.
Gauges, like value boxes, can use href
to link to more details, and in Shiny contexts should be rendered via renderGauge()
so they update dynamically (similar to using renderValueBox()
for value boxes in Shiny).
6.6 Sizing and Styling
By default, flexdashboard charts are sized automatically to fill the layout. If you do nothing special, the relative size of each chart is determined by the knitr figure dimensions (which default to 6 inches by 4.8 inches, i.e. 576x460 pixels). In a fill layout, vertically stacked charts will each take an equal share of the height (unless you adjust with data-height). In a scrolling layout, each chart’s height is just its figure height (so you may see more whitespace if figures are smaller, but you can scroll).
Flexdashboard allows fine control of sizing using header attributes:
-
data-height
anddata-width
can be applied to rows, columns, or individual chart sections to adjust their size relative to siblings. These aren’t absolute pixel sizes but weighted proportions in the flexbox layout. For example, if two charts are in one column and one hasdata-height="2"
and the otherdata-height="1"
, the first will be twice as tall as the second. - The YAML global
orientation
andvertical_layout
we discussed earlier also play a role in how widths/heights are allocated.
Example – Emphasizing a Chart: Suppose we want the first chart in a column to take more space. We could do:
### Sales Over Time {data-height=600}
::: {.cell}
```{.r .cell-code}
# <code for a big timeseries plot>
```
:::
### Breakdown by Region {data-height=300}
::: {.cell}
```{.r .cell-code}
# <code for smaller plot>
```
:::
This ensures the first chart gets a taller area than the second. If using fill layout, these numbers are treated as relative weights:contentReferenceoaicite:50. In scrolling layout, the data-height
on an individual chart actually sets a fixed pixel height (since scrolling mode otherwise uses each chart’s knitr fig height). You can experiment with these to get a pleasing arrangement.
There are other styling options too: - You can remove the default 8px padding around charts by adding a .no-padding
class to the section, or set a custom padding with data-padding=NN
:contentReferenceoaicite:51. - Flexdashboard includes several built-in themes (like cerulean, journal, flatly, etc. from Bootswatch) which you can set in the YAML (theme: united
, for example):contentReferenceoaicite:52:contentReferenceoaicite:53. The default theme is a modified Bootstrap “cosmo” theme:contentReferenceoaicite:54. Themes mainly affect the navigation bar and background styling. - You can add custom CSS via the css:
option in YAML if deeper styling customizations are needed:contentReferenceoaicite:55 (for example, to tweak font sizes or colors of specific elements).
6.7 Multiple Pages
For larger dashboards, you can split content into multiple pages. Each page will get its own tab in the navigation bar. To define a page, use a Level 1 heading (#
) in the R Markdown. For example:
Page 1 =====================
## Section ...
### Chart ...
Page 2 =====================
## Section ...
### Chart ...
Each #
heading (Page 1, Page 2) creates a new page tab in the navbar. This is useful to organize content into logical groups (e.g., an Overview page and a Details page, or different subject areas).
All pages in a flexdashboard share the same R session (if using Shiny, all pages are part of one app). By default, pages are shown as separate top-level tabs, but if you have many pages you can group them into a dropdown menu by using the data-navmenu="Menu Name"
attribute on some page headers. For example, Page 3 {data-navmenu="Other Metrics"}
would put Page 3 under a “Other Metrics” menu instead of as a standalone tab. You can even assign icons to page tabs via data-icon
attributes if desired.
If needed, you can hide a page from the navbar (perhaps it’s only linked to internally) by adding the .hidden
class to the page header.
All of these options let you create a multi-page dashboard that is still contained in a single R Markdown document.
6.8 Storyboards
Flexdashboard’s storyboard layout is an alternative to the grid layout, ideal for presenting a sequence of charts with commentary, like slides in a presentation. In a storyboard, each Level 3 section (###
) becomes a frame in a horizontal scrolling sequence (like slides), and you can include descriptive text alongside the frames.
To use a storyboard, you have two approaches:
-
Entire dashboard as a storyboard: In the YAML, set
storyboard: true
. Then every###
section on that page becomes a frame in the storyboard. The section title serves as the navigation caption for that frame (so typically, your section titles in a storyboard might be longer descriptions). -
Storyboard page in a multi-page dashboard: If you want one page to be a storyboard and others to be normal layout, do not use the global YAML option. Instead, add the class
{.storyboard}
to the Level 1 heading of the page you want as a storyboard. For example:Analysis {.storyboard} ====================
would make the “Analysis” page use storyboard layout, while other pages remain standard.
In a storyboard, frames are navigated via arrows or by clicking the frame titles. You simply create consecutive ###
sections. For example:
---
output: flexdashboard::flex_dashboard:
storyboard: true
---
### Frame 1: Overview
::: {.cell}
```{.r .cell-code}
# <code for visualization 1>
```
:::
### Frame 2: Details
::: {.cell}
```{.r .cell-code}
# <code for visualization 2>
```
:::
This would produce two frames, “Frame 1: Overview” and “Frame 2: Details,” that the reader can flip through. The content is presented one frame at a time, with a visual index of frame titles.
Commentary
Often you will want to include explanatory text alongside each frame in a storyboard (e.g., bullet points or interpretation of the chart). Flexdashboard allows adding a commentary sidebar to each frame. To do this, within a frame’s section, separate the main content and the commentary with a horizontal rule ***
(three asterisks on a line):contentReferenceoaicite:61. Anything after the ***
in that section will appear as commentary text to the right of the visualization.
For example:
### Frame 2: Revenue Breakdown {data-commentary-width=400}
::: {.cell}
```{.r .cell-code}
# <plot code>
:::
This chart shows revenue by product category. Notice that Category A has the highest share…
Here, the plot will appear on the left (in the frame), and the text after the `***` will appear in a sidebar on the right. We even set `data-commentary-width=400` to make the sidebar 400px wide (the default is 300px):contentReference[oaicite:62]{index=62}:contentReference[oaicite:63]{index=63}. You can adjust that per frame. This is a great way to ensure your audience not only sees the visuals but also understands the key points on each storyboard frame.
Storyboards can be combined with other pages, and you can always include static text sections in any layout. Flexdashboard is quite flexible in mixing narrative and visual components.
## Other Dashboard Solutions in R
Flexdashboard is a convenient way to build dashboards with R Markdown, but it's not the only approach. R users also commonly build dashboards using **Shiny** with the **shinydashboard** package. Both have their place:
- **flexdashboard**: uses the R Markdown document paradigm. It’s *very easy to get started* (write R Markdown, knit to a dashboard) and supports both static and Shiny-powered modes:contentReference[oaicite:64]{index=64}. Layout is handled by flexbox, and you don't need to write HTML or extensive R code for UI. However, complex interactive logic beyond basic inputs may require Shiny code embedded in the Rmd.
- **shinydashboard**: is an R package that extends Shiny, providing a dashboard-themed UI (with a sidebar, boxes, etc.). You build the UI with R code (not Markdown) and server logic with Shiny. This gives you more fine-grained control and the ability to create fully dynamic apps, but it’s a bit more involved to develop (not as "one-click" as flexdashboard):contentReference[oaicite:65]{index=65}. Shinydashboard uses a Bootstrap grid layout and is inherently dynamic (there is no static HTML mode, since it's a Shiny app by definition):contentReference[oaicite:66]{index=66}.
In short, **flexdashboard vs. shinydashboard**: the former is simpler and works for both static reports and light interactivity, the latter is for full Shiny applications with a dashboard style. In fact, the official Shiny documentation notes that *“You have two package options for building Shiny dashboards – flexdashboard and shinydashboard.”*:contentReference[oaicite:67]{index=67}
Looking forward, **Quarto** (the successor to R Markdown for multi-language publishing) has introduced its own dashboard features as of Quarto v1.4 (late 2023):contentReference[oaicite:68]{index=68}. Quarto dashboards are not an exact drop-in replacement for flexdashboard, but they aim to provide similar capabilities in a more unified way for R, Python, etc. If you transition to Quarto in the future, you can check the Quarto documentation for the new dashboard syntax. For now, if you're working in R Markdown, **flexdashboard remains the go-to solution for quick dashboards**, especially when you want a mix of narration and visualization in a single document:contentReference[oaicite:69]{index=69}:contentReference[oaicite:70]{index=70}.
## Conclusion
Flexdashboard enables R users to create attractive, responsive dashboards with minimal effort by writing R Markdown. In this chapter, we saw how to set up a flexdashboard, include various components, and arrange them in different layouts (using rows, columns, tabsets, or storyboards). We also discussed how to highlight key metrics with value boxes and gauges, and how to extend a dashboard across multiple pages or frames. Flexdashboard’s integration with Shiny allows adding interactivity when needed, while still keeping things simple for static presentations.
As a quick recap, flexdashboard allows you to:
- **Use R Markdown** to generate a dashboard from your analyses:contentReference[oaicite:71]{index=71}.
- **Combine diverse components** (interactive charts, static plots, tables, text, etc.) into a coherent dashboard:contentReference[oaicite:72]{index=72}.
- **Customize layout** easily with markdown headers for rows/columns and flexible sizing options:contentReference[oaicite:73]{index=73}.
- **Add interactivity** by incorporating Shiny runtime for inputs/reactivity, when desired:contentReference[oaicite:74]{index=74}.
**Getting your hands dirty:** As an exercise, you might create a flexdashboard for an **investment firm’s board**, comparing economic indicators. For example, build a dynamic dashboard showcasing **GDP and Foreign Direct Investment (FDI)** trends since 1995 for a country of interest (say, France). You could have an overview page with time-series plots of GDP and FDI, and another page with deeper dives (perhaps comparisons to other countries or percentage of GDP, etc.). Using flexdashboard, arrange these visuals side by side with value boxes highlighting key values (e.g., latest GDP) and maybe a gauge showing progress toward a target. This will give the board of directors an interactive way to explore the data. (Hint: Relevant data is available in the chapter’s GitHub repository, and an example solution dashboard is provided by the course instructors for reference.) With flexdashboard, you can assemble this presentation quickly and even deploy it as a standalone HTML or an interactive app.
:::{#quarto-navigation-envelope .hidden}
[The Essentials of R]{.hidden .quarto-markdown-envelope-contents render-id="cXVhcnRvLWludC1zaWRlYmFyLXRpdGxl"}
[The Essentials of R]{.hidden .quarto-markdown-envelope-contents render-id="cXVhcnRvLWludC1uYXZiYXItdGl0bGU="}
[<span class='chapter-number'>7</span> <span class='chapter-title'>Automating Data Collection with APIs</span>]{.hidden .quarto-markdown-envelope-contents render-id="cXVhcnRvLWludC1uZXh0"}
[<span class='chapter-number'>5</span> <span class='chapter-title'>Creating Beautiful Visuals</span>]{.hidden .quarto-markdown-envelope-contents render-id="cXVhcnRvLWludC1wcmV2"}
[Motivation]{.hidden .quarto-markdown-envelope-contents render-id="cXVhcnRvLWludC1zaWRlYmFyOi9pbmRleC5odG1sTW90aXZhdGlvbg=="}
[<span class='chapter-number'>1</span> <span class='chapter-title'>Introduction</span>]{.hidden .quarto-markdown-envelope-contents render-id="cXVhcnRvLWludC1zaWRlYmFyOi8wMS1pbnRyb2R1Y3Rpb24uaHRtbDxzcGFuLWNsYXNzPSdjaGFwdGVyLW51bWJlcic+MTwvc3Bhbj4tLTxzcGFuLWNsYXNzPSdjaGFwdGVyLXRpdGxlJz5JbnRyb2R1Y3Rpb248L3NwYW4+"}
[<span class='chapter-number'>2</span> <span class='chapter-title'>R for the impatient</span>]{.hidden .quarto-markdown-envelope-contents render-id="cXVhcnRvLWludC1zaWRlYmFyOi8wMi1mb3ItdGhlLWltcGF0aWVudC5odG1sPHNwYW4tY2xhc3M9J2NoYXB0ZXItbnVtYmVyJz4yPC9zcGFuPi0tPHNwYW4tY2xhc3M9J2NoYXB0ZXItdGl0bGUnPlItZm9yLXRoZS1pbXBhdGllbnQ8L3NwYW4+"}
[<span class='chapter-number'>3</span> <span class='chapter-title'>A Toolkit: RStudio, Markdown, Github, Zotero</span>]{.hidden .quarto-markdown-envelope-contents render-id="cXVhcnRvLWludC1zaWRlYmFyOi8wMy1tYXJrZG93bi1naXRodWIuaHRtbDxzcGFuLWNsYXNzPSdjaGFwdGVyLW51bWJlcic+Mzwvc3Bhbj4tLTxzcGFuLWNsYXNzPSdjaGFwdGVyLXRpdGxlJz5BLVRvb2xraXQ6LVJTdHVkaW8sLU1hcmtkb3duLC1HaXRodWIsLVpvdGVybzwvc3Bhbj4="}
[<span class='chapter-number'>4</span> <span class='chapter-title'>Data Wrangling</span>]{.hidden .quarto-markdown-envelope-contents render-id="cXVhcnRvLWludC1zaWRlYmFyOi8wNC1kYXRhLXdyYW5nbGluZy5odG1sPHNwYW4tY2xhc3M9J2NoYXB0ZXItbnVtYmVyJz40PC9zcGFuPi0tPHNwYW4tY2xhc3M9J2NoYXB0ZXItdGl0bGUnPkRhdGEtV3JhbmdsaW5nPC9zcGFuPg=="}
[<span class='chapter-number'>5</span> <span class='chapter-title'>Creating Beautiful Visuals</span>]{.hidden .quarto-markdown-envelope-contents render-id="cXVhcnRvLWludC1zaWRlYmFyOi8wNS12aXN1YWxzLmh0bWw8c3Bhbi1jbGFzcz0nY2hhcHRlci1udW1iZXInPjU8L3NwYW4+LS08c3Bhbi1jbGFzcz0nY2hhcHRlci10aXRsZSc+Q3JlYXRpbmctQmVhdXRpZnVsLVZpc3VhbHM8L3NwYW4+"}
[<span class='chapter-number'>6</span> <span class='chapter-title'>Creating Data Dashboards</span>]{.hidden .quarto-markdown-envelope-contents render-id="cXVhcnRvLWludC1zaWRlYmFyOi8wNi1kYXNoYm9hcmRzLmh0bWw8c3Bhbi1jbGFzcz0nY2hhcHRlci1udW1iZXInPjY8L3NwYW4+LS08c3Bhbi1jbGFzcz0nY2hhcHRlci10aXRsZSc+Q3JlYXRpbmctRGF0YS1EYXNoYm9hcmRzPC9zcGFuPg=="}
[<span class='chapter-number'>7</span> <span class='chapter-title'>Automating Data Collection with APIs</span>]{.hidden .quarto-markdown-envelope-contents render-id="cXVhcnRvLWludC1zaWRlYmFyOi8wNy1hcGkuaHRtbDxzcGFuLWNsYXNzPSdjaGFwdGVyLW51bWJlcic+Nzwvc3Bhbj4tLTxzcGFuLWNsYXNzPSdjaGFwdGVyLXRpdGxlJz5BdXRvbWF0aW5nLURhdGEtQ29sbGVjdGlvbi13aXRoLUFQSXM8L3NwYW4+"}
[<span class='chapter-number'>8</span> <span class='chapter-title'>Debugging: Strategies, Tools, and Best Practices</span>]{.hidden .quarto-markdown-envelope-contents render-id="cXVhcnRvLWludC1zaWRlYmFyOi8wOC1kZWJ1Z2dpbmcuaHRtbDxzcGFuLWNsYXNzPSdjaGFwdGVyLW51bWJlcic+ODwvc3Bhbj4tLTxzcGFuLWNsYXNzPSdjaGFwdGVyLXRpdGxlJz5EZWJ1Z2dpbmc6LVN0cmF0ZWdpZXMsLVRvb2xzLC1hbmQtQmVzdC1QcmFjdGljZXM8L3NwYW4+"}
[<span class='chapter-number'>9</span> <span class='chapter-title'>Conclusion</span>]{.hidden .quarto-markdown-envelope-contents render-id="cXVhcnRvLWludC1zaWRlYmFyOi9jb25jbHVzaW9uLmh0bWw8c3Bhbi1jbGFzcz0nY2hhcHRlci1udW1iZXInPjk8L3NwYW4+LS08c3Bhbi1jbGFzcz0nY2hhcHRlci10aXRsZSc+Q29uY2x1c2lvbjwvc3Bhbj4="}
[<span class='chapter-number'>10</span> <span class='chapter-title'>Summary</span>]{.hidden .quarto-markdown-envelope-contents render-id="cXVhcnRvLWludC1zaWRlYmFyOi9zdW1tYXJ5Lmh0bWw8c3Bhbi1jbGFzcz0nY2hhcHRlci1udW1iZXInPjEwPC9zcGFuPi0tPHNwYW4tY2xhc3M9J2NoYXB0ZXItdGl0bGUnPlN1bW1hcnk8L3NwYW4+"}
[References]{.hidden .quarto-markdown-envelope-contents render-id="cXVhcnRvLWludC1zaWRlYmFyOi9yZWZlcmVuY2VzLmh0bWxSZWZlcmVuY2Vz"}
[<span class='chapter-number'>6</span> <span class='chapter-title'>Creating Data Dashboards</span>]{.hidden .quarto-markdown-envelope-contents render-id="cXVhcnRvLWJyZWFkY3J1bWJzLTxzcGFuLWNsYXNzPSdjaGFwdGVyLW51bWJlcic+Njwvc3Bhbj4tLTxzcGFuLWNsYXNzPSdjaGFwdGVyLXRpdGxlJz5DcmVhdGluZy1EYXRhLURhc2hib2FyZHM8L3NwYW4+"}
:::
:::{#quarto-meta-markdown .hidden}
[[6]{.chapter-number} [Creating Data Dashboards]{.chapter-title} – The Essentials of R]{.hidden .quarto-markdown-envelope-contents render-id="cXVhcnRvLW1ldGF0aXRsZQ=="}
[[6]{.chapter-number} [Creating Data Dashboards]{.chapter-title} – The Essentials of R]{.hidden .quarto-markdown-envelope-contents render-id="cXVhcnRvLXR3aXR0ZXJjYXJkdGl0bGU="}
[[6]{.chapter-number} [Creating Data Dashboards]{.chapter-title} – The Essentials of R]{.hidden .quarto-markdown-envelope-contents render-id="cXVhcnRvLW9nY2FyZHRpdGxl"}
[The Essentials of R]{.hidden .quarto-markdown-envelope-contents render-id="cXVhcnRvLW1ldGFzaXRlbmFtZQ=="}
[]{.hidden .quarto-markdown-envelope-contents render-id="cXVhcnRvLXR3aXR0ZXJjYXJkZGVzYw=="}
[]{.hidden .quarto-markdown-envelope-contents render-id="cXVhcnRvLW9nY2FyZGRkZXNj"}
:::
<!-- -->
::: {.quarto-embedded-source-code}
```````````````````{.markdown shortcodes="false"}
# Creating Data Dashboards
```{r, include=FALSE}
knitr::opts_chunk$set(echo = TRUE, eval = FALSE)
In data science and analytics, a dashboard is a visual display of information – often including charts, tables, and summary metrics – that consolidates data into an interactive, at-a-glance view. Dashboards serve as powerful tools for data communication, enabling users to monitor key performance indicators (KPIs), explore trends, and make informed decisions quickly. They are especially prevalent in business analytics, where companies rely on dashboards to share data insights across teams and drive strategic decisions. In fact, the vast majority of businesses use dashboards as a primary channel for communicating data insights; without dashboards, it would be almost impossible for many organizations to share data reports with all who need them. By presenting data in a visual and interactive format, dashboards help bridge the gap between data and decision-makers, allowing even non-technical users to grasp complex information intuitively.
Dashboards are not only crucial in corporate settings – they also play an important role in the public sector and open data initiatives. Governments and institutions use public-facing dashboards to share data with citizens, increasing transparency and accountability. For example, city governments might publish dashboards on budgets or environmental metrics to allow the public to see what is happening and to initiate informed conversations or actions. Research has highlighted that dashboards can connect governments with the public, helping to create transparency and foster trust. As such, well-designed dashboards become an important means of communicating and interacting with the public on data-driven issues, enabling broader audiences to engage with data in a meaningful way. Whether in a business or public context, dashboards turn raw data into accessible information stories, making them essential for modern data-driven decision making.
Beyond their communicative value, dashboards offer practical advantages. They provide timely data access – often updating in real-time or on a regular schedule – so that users are always looking at the latest information. They enable enhanced decision-making by highlighting trends and anomalies that might be missed in static reports. They can also improve efficiency by consolidating multiple reports or analysis views into a single interface. In summary, a dashboard serves as a single source of truth for a particular analysis or operational area, where users can interact with visuals and filters to answer their questions on the fly. By combining clarity, interactivity, and timeliness, dashboards have become indispensable in both business intelligence and public data communication.
6.9 Flexdashboard
Flexdashboard is an R package that makes it easy to create interactive dashboards using R Markdown. With flexdashboard, you can publish a group of related data visualizations as a dashboard – either as a static web page or an interactive Shiny app. Flexdashboard supports a wide variety of components, including htmlwidgets (R bindings to JavaScript libraries), base R or ggplot2 graphics, interactive tables, value boxes, gauges, and text annotations. It features flexible layouts (rows, columns, and tabsets) that intelligently adapt to fill the browser screen and even adjust for mobile devices. You can also incorporate Shiny to drive live data or user inputs in the dashboard. In short, flexdashboard brings together R Markdown reporting and Shiny interactivity for easy yet powerful dashboard creation.
Example of a flexdashboard with multiple components (heatmap and table). Flexdashboard allows assembling various charts and outputs into a responsive dashboard layout.
Key features of flexdashboard include:
-
R Markdown workflow: You write an R Markdown document and use the
flexdashboard::flex_dashboard
format to generate the dashboard. This keeps development simple and reproducible (mixing text, code, and results). - Rich components: Flexdashboard supports interactive visualizations via htmlwidgets, static plots from base R or ggplot2, data tables (with sorting/filtering), and special elements like value boxes (for key metrics) and gauges (for KPI meters).
- Flexible layouts: You can arrange components using rows and columns specified by section headers. The layout uses a CSS flexbox mechanism to automatically resize charts to fill the browser and even stacks into a single column on small screens (for mobile).
- Storyboards: In addition to typical grid layouts, flexdashboard offers a storyboard mode for presenting a sequence of charts with accompanying commentary in a step-by-step narrative style.
-
Optional Shiny interactivity: Flexdashboards can be static (purely viewer-side HTML/JS) or, if you specify
runtime: shiny
, they become dynamic Shiny apps where readers can input parameters and see results update live.
To get started, install the flexdashboard package from CRAN if you haven’t already:
quarto-executable-code-5450563D
install.packages("flexdashboard")
This provides the flex_dashboard
output format for R Markdown. In RStudio, you can create a new Flexdashboard document by going to File > New File > R Markdown… > From Template > Flex Dashboard. This will open a template .Rmd
file with the necessary YAML header and structure. (If not using RStudio, you can use the rmarkdown::draft
function with the "flex_dashboard"
template to scaffold a new dashboard file.)
Creating a new Flex Dashboard document from RStudio’s template menu.
The top of your R Markdown should include YAML like this, which specifies the flexdashboard format and any options:
---
title: "Your Dashboard Title"
output:
flexdashboard::flex_dashboard:
orientation: columns # or rows
vertical_layout: fill # or scroll
storyboard: false # set true for storyboard layout
---
Here we set the overall layout orientation (columns vs. rows), and whether the dashboard should fill the page vertically or scroll (more on this below). With that in place, you structure the content of the dashboard using headings and code chunks.
6.10 Layout
Dashboards are organized into sections using headings. Flexdashboard uses the heading levels to define rows, columns, and chart panels:
-
Level 1 headings (
#
) define Pages (for multi-page dashboards, each becomes a top-level navigation tab). -
Level 2 headings (
##
) define Columns by default (or entire Rows iforientation: rows
is set globally or for that page). -
Level 3 headings (
###
) define individual chart sections within a column or row.
By default, flexdashboard assumes a column-oriented layout: each Level 2 heading starts a new column, and charts (Level 3) under it stack vertically within that column. You can also opt for a row-oriented layout by setting orientation: rows
(in YAML or for a specific page), in which case Level 2 headings create new rows, and charts under them distribute into columns within that row.
In addition, the vertical layout mode controls how charts fill the page vertically. The default vertical_layout: fill
causes the dashboard to fill the browser height – charts will expand/shrink vertically to fit the screen without scrolling. This is ideal if you have one or two charts stacked and want to use all available space. Alternatively, vertical_layout: scroll
will keep each chart at its natural height (as determined by its figure size), and allow the page to scroll if the content exceeds the screen. Scrolling layout is better when you have many components vertically and prefer not to squish them into one view.
Let’s look at a few common layout patterns:
Chart Stack (Fill)
This is the simplest layout: a single column with charts stacked vertically, filling the page. For example, two charts one above the other can be defined like so:
output:
flexdashboard::flex_dashboard:
vertical_layout: fill
---
### Chart 1
quarto-executable-code-5450563D
```r
<code to produce chart 1>
```
### Chart 2
quarto-executable-code-5450563D
```r
<code to produce chart 2>
```
With vertical_layout: fill
, these two charts will split the available vertical space in the browser roughly equally (unless one is given extra height explicitly). You could make one chart taller by adding a data-height
attribute on its section header, which adjusts the relative height allocation:contentReferenceoaicite:24. For instance, ### Chart 1 {data-height=500}
would allot more height to Chart 1 relative to Chart 2 in the fill layout.
Chart Stack (Scrolling)
If you have multiple charts stacked, a fill layout might cram them into a tight space. Using a scrolling layout lets each chart keep its natural height and simply adds a scrollbar for the page. For example:
output:
flexdashboard::flex_dashboard:
vertical_layout: scroll
---
### Chart A
quarto-executable-code-5450563D
```r
<chart A code>
Chart B
quarto-executable-code-5450563D
<chart B code>
Chart C
quarto-executable-code-5450563D
<chart C code>
Here we have three charts in one column. With `vertical_layout: scroll`, each chart will be rendered at its default height (e.g. 480px tall by default):contentReference[oaicite:25]{index=25}, and the browser window will scroll to show all charts:contentReference[oaicite:26]{index=26}. This layout can easily accommodate many charts vertically (though if you have too many, you might consider breaking into multiple pages or using tabsets for better navigation:contentReference[oaicite:27]{index=27}).
### Focal Chart (Top)
Sometimes you want one visualization to stand out with more space, and supporting charts to be smaller. Flexdashboard allows **mixing rows and columns with custom sizes**. For example, a “Focal Chart Top” layout might have a large chart spanning the full width on the first row, and a second row with two smaller charts below it:contentReference[oaicite:28]{index=28}:
```yaml
---
output:
flexdashboard::flex_dashboard:
orientation: rows
---
Row {data-height=650}
-------------------------------------
### Big Chart (Top)
quarto-executable-code-5450563D
```r
# code for big chart
6.11 Row
Chart 2
quarto-executable-code-5450563D
# code
Chart 3
quarto-executable-code-5450563D
# code
In the above, we explicitly set the first **Row** to 650px height and the second row to 350px (using `data-height` on the row headers):contentReference[oaicite:29]{index=29}. The first row contains a single **Big Chart** that gets the larger portion of vertical space (about 65% of the page), while the second row contains two charts side by side (since in a row-oriented layout, multiple Level 3 sections in the same row header will form columns in that row). This way, **Chart 2** and **Chart 3** share the bottom part of the screen, and the top chart remains the focal point.
### Focal Chart (Left)
You can also emphasize a chart by giving it more horizontal space. To create a **multi-column layout** with one wider column for a focal chart and a second narrower column for others, use Level 2 headings to start each column and specify `data-width` attributes. For example, here we split three charts across two columns, making the first column 60% width and the second 40%:
```yaml
output: flexdashboard::flex_dashboard
---
Column {data-width=600}
-------------------------------------
### Chart 1 (Main)
quarto-executable-code-5450563D
```r
# <code for main chart>
6.12 Column
Chart 2
quarto-executable-code-5450563D
# <code>
Chart 3
quarto-executable-code-5450563D
# <code>
The above yields **Chart 1** in a left column that is 600px wide vs. a right column of 400px (total 1000px base, so roughly 60/40 split):contentReference[oaicite:30]{index=30}. Charts 2 and 3 stack in the right column. This is an example of a **“Focal Chart Left”** layout:contentReference[oaicite:31]{index=31} – one prominent chart on one side, with supporting charts on the other side.
### Tabsets
If you have several components that don't all need to be visible at once, you can organize them into **tabs**. Flexdashboard allows you to convert any column or row into a **tabset** by adding the `{.tabset}` attribute to its heading:contentReference[oaicite:32]{index=32}. Each Level 3 section under that heading will become a separate tab panel.
For instance, suppose you have one column that should show either Chart X or Chart Y (as two tabs). You can do:
```yaml
output: flexdashboard::flex_dashboard
---
Column
-------------------------------------
### Chart A
quarto-executable-code-5450563D
```r
# <code for chart A>
6.13 Column
Chart X
quarto-executable-code-5450563D
# <code for chart X>
Chart Y
quarto-executable-code-5450563D
# <code for chart Y>
In this layout, the dashboard has two columns: the left column (no special classes) always shows **Chart A**, and the right column is a tabset that toggles between **Chart X** and **Chart Y**:contentReference[oaicite:33]{index=33}. Only one of X or Y is visible at a time, with tabs to switch. Tabsets are useful when you have multiple related visualizations but want to save space or avoid clutter by layering them in the same area:contentReference[oaicite:34]{index=34}. You can also apply tabsets at the row level (group entire rows into tabs similarly), and you can add the `.tabset-fade` class for a fading animation when switching tabs:contentReference[oaicite:35]{index=35}.
## Components
A flexdashboard can include any output you can generate from R, but there are a few special **components** worth noting:
- **Base R and ggplot2** graphics: Any plots produced by R code chunks will be included in the dashboard panels. These are static images (PNG/SVG) unless made interactive via a widget.
- **htmlwidgets**: These are R packages that bind JavaScript libraries (like Leaflet maps, Plotly plots, DT tables, etc.) and produce interactive web visuals. They work great in flexdashboard because they can automatically resize to fill their container:contentReference[oaicite:36]{index=36}:contentReference[oaicite:37]{index=37}.
- **Tables**: You can simply print a data frame or use packages like **DT** for interactive tables. Flexdashboard will include them, with scrolling or pagination as needed (and special behavior on mobile to ensure usability).
- **Value Boxes**: These display a big numeric value with a caption (and icon/color) to highlight key metrics.
- **Gauges**: These show a dial or meter representation of a value within a range.
- **Text and Markdown**: You can include narrative text, headers, lists, etc., in your dashboard sections to provide context or commentary.
Let's dive a bit deeper into **Value Boxes** and **Gauges** since they are unique to dashboard-style presentations:
### Value Boxes
A **value box** is a compact box that highlights a single value along with a label and an icon. They’re great for presenting KPIs or summary statistics (like "Total Sales: 1.2M" or "Conversion Rate: 5%"). In flexdashboard, you create one with the `valueBox()` function inside an R code chunk. For example:
quarto-executable-code-5450563D
```r
valueBox(45, title = "Articles per Day", icon = "fa-pencil")
This would display a value box showing 45 and the caption “Articles per Day,” with a pencil icon. By default, value boxes are styled in a neutral color (or “primary” theme color). You can customize the color or make it conditional. For instance, you might use color = "warning"
or "success"
, or even a conditional expression:
quarto-executable-code-5450563D
spam <- 5
valueBox(spam, title = "Spam per Day", icon = "fa-trash",
color = ifelse(spam > 10, "warning", "primary"))
In this example, the color will be “primary” (blue) since spam is 5 (low), but if it exceeded 10 it would turn “warning” (often yellow/orange). The set of built-in color names includes primary, info, success, warning, danger, corresponding to Bootstrap theme colors. You can also use any custom CSS color code if needed.
Value boxes can include an icon on the right side. Flexdashboard supports icons from Font Awesome, Ionicons, and Bootstrap Glyphicons – you specify them by prefixing the icon name with fa-
, ion-
, or glyphicon-
respectively. For example, "fa-comments"
for a comment icon or "ion-social-twitter"
for a Twitter bird. (Note: not all icons from these sets are free or available by default, so some icons might not render if they require pro licenses.)
You can also make a value box into a hyperlink – for instance, if clicking the value should navigate to another page or section with more details. Use the href
argument to specify a page anchor (e.g., href="#details"
to link to a subsection titled “Details”).
Gauges
A gauge displays a numeric value on a semicircular meter, with zones indicating ranges (like red/yellow/green zones for bad/medium/good). In flexdashboard, you create gauges with the gauge()
function. The simplest usage is:
quarto-executable-code-5450563D
gauge(value = 37.4, min = 0, max = 50)
This will draw a gauge showing 37.4 on a 0–50 scale. By default the gauge will be a single color (the theme’s “success” color, typically green). You can define colored sectors for different ranges using gaugeSectors()
. For example:
quarto-executable-code-5450563D
gauge(37.4, min = 0, max = 50,
sectors = gaugeSectors(success = c(41, 50), warning = c(21, 40), danger = c(0, 20)))
In this case:
- Green (“success”) for values 41–50,
- Yellow (“warning”) for 21–40,
- Red (“danger”) for 0–20.
The gauge needle will point at 37.4, which falls in the warning (yellow) zone in this configuration. You can also add a symbol
argument (e.g., %
or $
) to append a unit to the displayed value.
Gauges, like value boxes, can use href
to link to more details, and in Shiny contexts should be rendered via renderGauge()
so they update dynamically (similar to using renderValueBox()
for value boxes in Shiny).
6.14 Sizing and Styling
By default, flexdashboard charts are sized automatically to fill the layout. If you do nothing special, the relative size of each chart is determined by the knitr figure dimensions (which default to 6 inches by 4.8 inches, i.e. 576x460 pixels). In a fill layout, vertically stacked charts will each take an equal share of the height (unless you adjust with data-height). In a scrolling layout, each chart’s height is just its figure height (so you may see more whitespace if figures are smaller, but you can scroll).
Flexdashboard allows fine control of sizing using header attributes:
-
data-height
anddata-width
can be applied to rows, columns, or individual chart sections to adjust their size relative to siblings. These aren’t absolute pixel sizes but weighted proportions in the flexbox layout. For example, if two charts are in one column and one hasdata-height="2"
and the otherdata-height="1"
, the first will be twice as tall as the second. - The YAML global
orientation
andvertical_layout
we discussed earlier also play a role in how widths/heights are allocated.
Example – Emphasizing a Chart: Suppose we want the first chart in a column to take more space. We could do:
### Sales Over Time {data-height=600}
quarto-executable-code-5450563D
```r
# <code for a big timeseries plot>
```
### Breakdown by Region {data-height=300}
quarto-executable-code-5450563D
```r
# <code for smaller plot>
```
This ensures the first chart gets a taller area than the second. If using fill layout, these numbers are treated as relative weights:contentReferenceoaicite:50. In scrolling layout, the data-height
on an individual chart actually sets a fixed pixel height (since scrolling mode otherwise uses each chart’s knitr fig height). You can experiment with these to get a pleasing arrangement.
There are other styling options too: - You can remove the default 8px padding around charts by adding a .no-padding
class to the section, or set a custom padding with data-padding=NN
:contentReferenceoaicite:51. - Flexdashboard includes several built-in themes (like cerulean, journal, flatly, etc. from Bootswatch) which you can set in the YAML (theme: united
, for example):contentReferenceoaicite:52:contentReferenceoaicite:53. The default theme is a modified Bootstrap “cosmo” theme:contentReferenceoaicite:54. Themes mainly affect the navigation bar and background styling. - You can add custom CSS via the css:
option in YAML if deeper styling customizations are needed:contentReferenceoaicite:55 (for example, to tweak font sizes or colors of specific elements).
6.15 Multiple Pages
For larger dashboards, you can split content into multiple pages. Each page will get its own tab in the navigation bar. To define a page, use a Level 1 heading (#
) in the R Markdown. For example:
Page 1 =====================
## Section ...
### Chart ...
Page 2 =====================
## Section ...
### Chart ...
Each #
heading (Page 1, Page 2) creates a new page tab in the navbar. This is useful to organize content into logical groups (e.g., an Overview page and a Details page, or different subject areas).
All pages in a flexdashboard share the same R session (if using Shiny, all pages are part of one app). By default, pages are shown as separate top-level tabs, but if you have many pages you can group them into a dropdown menu by using the data-navmenu="Menu Name"
attribute on some page headers. For example, Page 3 {data-navmenu="Other Metrics"}
would put Page 3 under a “Other Metrics” menu instead of as a standalone tab. You can even assign icons to page tabs via data-icon
attributes if desired.
If needed, you can hide a page from the navbar (perhaps it’s only linked to internally) by adding the .hidden
class to the page header.
All of these options let you create a multi-page dashboard that is still contained in a single R Markdown document.
6.16 Storyboards
Flexdashboard’s storyboard layout is an alternative to the grid layout, ideal for presenting a sequence of charts with commentary, like slides in a presentation. In a storyboard, each Level 3 section (###
) becomes a frame in a horizontal scrolling sequence (like slides), and you can include descriptive text alongside the frames.
To use a storyboard, you have two approaches:
-
Entire dashboard as a storyboard: In the YAML, set
storyboard: true
. Then every###
section on that page becomes a frame in the storyboard. The section title serves as the navigation caption for that frame (so typically, your section titles in a storyboard might be longer descriptions). -
Storyboard page in a multi-page dashboard: If you want one page to be a storyboard and others to be normal layout, do not use the global YAML option. Instead, add the class
{.storyboard}
to the Level 1 heading of the page you want as a storyboard. For example:Analysis {.storyboard} ====================
would make the “Analysis” page use storyboard layout, while other pages remain standard.
In a storyboard, frames are navigated via arrows or by clicking the frame titles. You simply create consecutive ###
sections. For example:
---
output: flexdashboard::flex_dashboard:
storyboard: true
---
### Frame 1: Overview
quarto-executable-code-5450563D
```r
# <code for visualization 1>
```
### Frame 2: Details
quarto-executable-code-5450563D
```r
# <code for visualization 2>
```
This would produce two frames, “Frame 1: Overview” and “Frame 2: Details,” that the reader can flip through. The content is presented one frame at a time, with a visual index of frame titles.
Commentary
Often you will want to include explanatory text alongside each frame in a storyboard (e.g., bullet points or interpretation of the chart). Flexdashboard allows adding a commentary sidebar to each frame. To do this, within a frame’s section, separate the main content and the commentary with a horizontal rule ***
(three asterisks on a line):contentReferenceoaicite:61. Anything after the ***
in that section will appear as commentary text to the right of the visualization.
For example:
### Frame 2: Revenue Breakdown {data-commentary-width=400}
quarto-executable-code-5450563D
```r
# <plot code>
This chart shows revenue by product category. Notice that Category A has the highest share…
Here, the plot will appear on the left (in the frame), and the text after the `***` will appear in a sidebar on the right. We even set `data-commentary-width=400` to make the sidebar 400px wide (the default is 300px):contentReference[oaicite:62]{index=62}:contentReference[oaicite:63]{index=63}. You can adjust that per frame. This is a great way to ensure your audience not only sees the visuals but also understands the key points on each storyboard frame.
Storyboards can be combined with other pages, and you can always include static text sections in any layout. Flexdashboard is quite flexible in mixing narrative and visual components.
## Other Dashboard Solutions in R
Flexdashboard is a convenient way to build dashboards with R Markdown, but it's not the only approach. R users also commonly build dashboards using **Shiny** with the **shinydashboard** package. Both have their place:
- **flexdashboard**: uses the R Markdown document paradigm. It’s *very easy to get started* (write R Markdown, knit to a dashboard) and supports both static and Shiny-powered modes:contentReference[oaicite:64]{index=64}. Layout is handled by flexbox, and you don't need to write HTML or extensive R code for UI. However, complex interactive logic beyond basic inputs may require Shiny code embedded in the Rmd.
- **shinydashboard**: is an R package that extends Shiny, providing a dashboard-themed UI (with a sidebar, boxes, etc.). You build the UI with R code (not Markdown) and server logic with Shiny. This gives you more fine-grained control and the ability to create fully dynamic apps, but it’s a bit more involved to develop (not as "one-click" as flexdashboard):contentReference[oaicite:65]{index=65}. Shinydashboard uses a Bootstrap grid layout and is inherently dynamic (there is no static HTML mode, since it's a Shiny app by definition):contentReference[oaicite:66]{index=66}.
In short, **flexdashboard vs. shinydashboard**: the former is simpler and works for both static reports and light interactivity, the latter is for full Shiny applications with a dashboard style. In fact, the official Shiny documentation notes that *“You have two package options for building Shiny dashboards – flexdashboard and shinydashboard.”*:contentReference[oaicite:67]{index=67}
Looking forward, **Quarto** (the successor to R Markdown for multi-language publishing) has introduced its own dashboard features as of Quarto v1.4 (late 2023):contentReference[oaicite:68]{index=68}. Quarto dashboards are not an exact drop-in replacement for flexdashboard, but they aim to provide similar capabilities in a more unified way for R, Python, etc. If you transition to Quarto in the future, you can check the Quarto documentation for the new dashboard syntax. For now, if you're working in R Markdown, **flexdashboard remains the go-to solution for quick dashboards**, especially when you want a mix of narration and visualization in a single document:contentReference[oaicite:69]{index=69}:contentReference[oaicite:70]{index=70}.
## Conclusion
Flexdashboard enables R users to create attractive, responsive dashboards with minimal effort by writing R Markdown. In this chapter, we saw how to set up a flexdashboard, include various components, and arrange them in different layouts (using rows, columns, tabsets, or storyboards). We also discussed how to highlight key metrics with value boxes and gauges, and how to extend a dashboard across multiple pages or frames. Flexdashboard’s integration with Shiny allows adding interactivity when needed, while still keeping things simple for static presentations.
As a quick recap, flexdashboard allows you to:
- **Use R Markdown** to generate a dashboard from your analyses:contentReference[oaicite:71]{index=71}.
- **Combine diverse components** (interactive charts, static plots, tables, text, etc.) into a coherent dashboard:contentReference[oaicite:72]{index=72}.
- **Customize layout** easily with markdown headers for rows/columns and flexible sizing options:contentReference[oaicite:73]{index=73}.
- **Add interactivity** by incorporating Shiny runtime for inputs/reactivity, when desired:contentReference[oaicite:74]{index=74}.
**Getting your hands dirty:** As an exercise, you might create a flexdashboard for an **investment firm’s board**, comparing economic indicators. For example, build a dynamic dashboard showcasing **GDP and Foreign Direct Investment (FDI)** trends since 1995 for a country of interest (say, France). You could have an overview page with time-series plots of GDP and FDI, and another page with deeper dives (perhaps comparisons to other countries or percentage of GDP, etc.). Using flexdashboard, arrange these visuals side by side with value boxes highlighting key values (e.g., latest GDP) and maybe a gauge showing progress toward a target. This will give the board of directors an interactive way to explore the data. (Hint: Relevant data is available in the chapter’s GitHub repository, and an example solution dashboard is provided by the course instructors for reference.) With flexdashboard, you can assemble this presentation quickly and even deploy it as a standalone HTML or an interactive app.
:::