FlexDashboards for Clinical and Translational Research

Photo by Luke Chesser on Unsplash

Key Points

  • This monograph provides a roadmap to create a FlexDashboard for Clinical and Translational Research

  • The purpose of a Dashboard is to present data in a way that enhances its interpretation

  • There are many excellent tutorials on using the package Flexdashboard to create a dashboard; however, in this monograph we aim to highlight a few pearls that we have learned along the way that we hope you’ll find useful

  • What we will show you next is the code we used to create the following Flexdashboard

  • Click here to see the interactive Dashboard

  • Of note, the data here is completely fabricated, any relation to real subjects is completely coincidental

  • Skill Level: Intermediate

    • Assumption made by this post is that readers will have basic familiarity with R

Load Packages

  • We will be making use of the following packages
library(flexdashboard)
library(RCurl)
library(REDCapR)
library(httr)
library(tidyverse)
library(knitr)
library(plotly)
library(readxl)
library(scales)
library(cowplot)

Overview of the Format of Flexdashboard

  • The Flexdashboard package is built around RMarkdown
  • To start, you can open a new RMarkdown by:

File -> New File -> RMarkdown

  • Then go to “From Template” on the left hand column
    • If you have installed Flexdashboard then Flexdashboard will be in the window that opens
    • Once you have selected Flexdashboard a new RMarkdown will open
    • What is specific here is the YAML
      • The content between the three dashes in beginning of the RMarkdown

Flexdashboard YAML

  • This is the YAML for the Flexdashboard

title: “Untitled”
output:
flexdashboard::flex_dashboard:
orientation: columns
vertical_layout: fill

Flexdashboard content

  • Then after the YAML, the Flexdashboard template is quite basic
  • It is broken down into three basic sections, which are designated by either hashtags or dashes

Key Structure of FLEXDASHBOARD

  • # Page (Level 1 Header)
  • ## Column vs. Tabset (Level 2 Header)
  • ### Individual Data Visualizations (Level 3 Header)

Level 1 or The “Page” designation

  • This can either be marked by a single # or by a double line ============ under the corresponding text

The Column vs. Tabset

  • This can be designed by two #s (##) or a single dash line ———– under the text

The Individual Data Visualizations

  • Marked by three #s (###)

As example, using our dashboard above, we broke the first Page “Registry Overview” down into three graphs using the following structure

Here’s an example of what that code looks like to generate the data in the Flexdashboard

To start, let’s load the data we used

  • This is a fabricated dataset, but has many features that resemble an actual rare disease cohort dataset.
dt <- data.frame(record_id = 1:500,
                 age_at_dx = sample(50:95, size = 500, replace = TRUE),
                 man_clinstage = sample(1:5, size = 500, replace = TRUE, prob = c(0.39, 0.2, 0.01, 0.25, 0.15)),
                 man_pathstage = sample(1:6, size = 500, replace = TRUE, prob = c(0.37, 0.2, 0.03, 0.15, 0.1, 0.15)),
                 overall_survival = sample(1:3000, size = 500, replace = TRUE),
                 subject_status = sample(0:1, size = 500, replace = TRUE))

View Dataset

dt %>% 
  kable %>% 
  kableExtra::kable_styling(bootstrap_options = c("hover","striped"),
                            fixed_thead = T) %>% 
  kableExtra::scroll_box(height = "400px",
                         width = "100%")
record_id age_at_dx man_clinstage man_pathstage overall_survival subject_status
1 82 2 2 2455 0
2 56 4 2 772 1
3 84 1 2 1525 1
4 55 1 2 86 1
5 61 1 1 2589 0
6 77 5 2 2934 1
7 95 4 6 525 1
8 69 5 1 463 1
9 95 4 5 2736 1
10 67 2 6 429 0
11 73 4 4 2783 0
12 90 5 2 2349 1
13 69 4 6 2557 0
14 70 2 1 2878 0
15 86 4 1 574 1
16 52 4 6 795 1
17 89 1 4 1637 1
18 74 1 6 694 0
19 79 1 4 519 0
20 84 2 2 420 0
21 69 1 2 1818 0
22 78 5 1 102 1
23 86 4 1 528 1
24 57 1 4 1841 1
25 80 4 2 1991 1
26 69 1 2 1609 1
27 89 5 6 347 0
28 64 1 1 392 1
29 82 1 4 109 1
30 63 1 5 2425 0
31 62 1 6 2860 0
32 72 2 5 1903 1
33 69 2 1 2925 0
34 85 4 1 2644 1
35 71 5 5 1497 0
36 95 1 1 1229 0
37 70 1 4 2204 0
38 64 4 4 2358 0
39 83 1 2 2837 0
40 87 1 2 1848 1
41 63 1 2 289 1
42 55 5 6 1689 0
43 53 1 2 2418 1
44 50 2 5 1834 0
45 88 1 1 2424 1
46 81 2 1 834 0
47 58 1 5 891 0
48 82 4 1 200 1
49 73 2 6 2513 0
50 62 5 6 1084 0
51 66 1 1 1147 0
52 81 1 1 106 0
53 78 1 5 2912 1
54 89 5 2 498 0
55 73 4 5 2496 0
56 56 4 1 2510 0
57 92 1 1 294 1
58 81 1 1 1368 0
59 60 1 5 1568 1
60 68 2 4 1033 0
61 74 1 1 905 1
62 89 5 5 1801 1
63 57 1 1 990 0
64 68 4 4 48 0
65 87 1 6 382 1
66 52 2 2 1738 1
67 68 4 1 937 1
68 85 4 2 2736 0
69 73 1 1 769 0
70 91 4 1 2133 0
71 66 2 1 2013 0
72 87 4 1 237 1
73 81 5 1 543 0
74 78 1 1 1452 0
75 87 4 4 176 0
76 87 2 6 1601 0
77 57 5 1 1639 1
78 94 1 1 1812 1
79 65 4 1 99 0
80 95 4 1 994 1
81 51 1 1 2090 1
82 71 5 1 2388 1
83 73 1 1 2798 0
84 85 4 1 1448 0
85 72 5 4 505 0
86 52 4 1 2614 0
87 81 5 1 2779 0
88 79 5 1 485 0
89 59 3 6 2344 0
90 69 1 5 2437 0
91 54 2 2 516 0
92 66 2 1 1258 0
93 64 1 2 1915 0
94 86 1 2 328 1
95 93 2 6 1758 1
96 84 1 4 1763 0
97 76 1 1 2817 1
98 66 4 4 388 0
99 80 5 1 768 1
100 92 2 1 1150 0
101 63 1 2 524 0
102 69 5 1 1486 1
103 87 4 1 1609 1
104 54 4 5 1171 0
105 75 1 1 1216 1
106 87 1 6 2517 1
107 51 4 6 1702 0
108 50 1 4 2985 1
109 80 1 1 1201 0
110 57 4 1 2575 0
111 74 2 2 1448 1
112 73 1 5 1806 1
113 71 4 1 556 0
114 76 1 1 278 1
115 82 1 2 2904 0
116 88 5 1 2999 0
117 94 2 5 2605 0
118 58 4 1 1542 0
119 64 2 6 946 1
120 53 4 2 336 1
121 53 4 6 1789 1
122 72 4 6 407 0
123 61 1 2 1235 0
124 79 5 1 2260 0
125 81 5 4 721 1
126 93 1 4 2034 0
127 78 5 6 673 0
128 67 1 1 161 1
129 84 1 1 182 0
130 50 2 1 1135 0
131 51 1 6 1439 1
132 58 5 4 1385 1
133 87 1 6 2382 0
134 80 2 2 48 0
135 77 4 6 1422 0
136 92 1 2 1855 1
137 51 4 2 2402 0
138 88 4 2 1083 0
139 72 1 2 491 0
140 93 2 1 1808 1
141 84 1 1 1750 0
142 82 1 6 70 1
143 53 5 4 199 0
144 73 2 1 2500 0
145 70 4 6 2872 0
146 81 1 5 1110 1
147 58 2 4 1307 1
148 72 5 1 328 0
149 63 1 2 2523 1
150 69 2 4 2118 0
151 82 5 1 2601 0
152 65 1 6 1918 0
153 64 1 1 320 0
154 83 4 1 765 0
155 81 1 3 1064 1
156 75 1 1 792 0
157 75 4 2 2750 0
158 62 2 2 1496 1
159 55 4 1 296 0
160 53 1 1 1882 0
161 78 2 2 168 1
162 72 2 2 648 0
163 82 1 1 2197 0
164 85 1 5 1973 0
165 71 5 6 2837 0
166 85 4 1 158 1
167 71 2 1 2660 0
168 85 5 6 1545 1
169 61 2 1 1435 1
170 53 2 1 249 1
171 82 2 1 2858 1
172 51 1 4 420 1
173 90 5 4 406 0
174 85 1 5 2897 0
175 57 4 6 261 1
176 63 5 4 1298 1
177 79 2 1 2812 1
178 50 1 6 2485 1
179 83 4 1 208 1
180 55 5 1 1375 1
181 51 5 5 283 1
182 77 1 2 44 0
183 67 1 1 1177 1
184 74 1 4 139 0
185 73 2 6 2213 0
186 81 4 1 930 1
187 67 4 6 2736 1
188 86 1 6 1933 0
189 92 5 1 1851 0
190 87 2 1 871 0
191 84 5 2 2819 1
192 72 5 6 157 1
193 67 1 2 101 1
194 77 1 1 2241 0
195 92 4 1 209 1
196 86 2 1 2919 1
197 78 1 2 1031 1
198 71 2 2 1163 1
199 73 4 1 1129 1
200 86 5 1 1826 1
201 84 2 5 2137 1
202 68 2 6 2445 0
203 70 1 4 2903 0
204 88 4 1 2162 1
205 56 2 2 968 1
206 81 4 6 2603 0
207 84 1 2 2124 0
208 82 2 1 1016 1
209 60 1 5 266 0
210 88 1 4 546 1
211 83 1 6 1250 1
212 92 5 1 300 0
213 66 2 1 1511 0
214 89 4 2 1502 1
215 59 5 1 2909 1
216 92 2 2 2928 0
217 70 2 6 878 1
218 56 2 1 828 1
219 84 1 6 602 1
220 64 4 5 902 0
221 56 3 2 530 1
222 85 2 6 661 0
223 56 2 1 2424 1
224 70 3 4 1724 0
225 54 4 4 1685 1
226 57 5 4 1095 1
227 92 1 1 2425 0
228 94 5 1 1785 0
229 70 4 2 1421 0
230 54 1 2 2767 0
231 67 5 4 919 1
232 62 1 1 1624 0
233 89 4 2 442 0
234 78 1 2 2536 0
235 84 4 2 1378 1
236 93 1 4 1921 0
237 63 4 5 1050 0
238 88 5 5 1235 0
239 81 1 1 1712 0
240 66 1 1 77 1
241 62 2 1 2857 1
242 61 1 2 1298 0
243 91 2 4 90 1
244 88 4 1 2149 0
245 53 1 1 358 1
246 68 1 1 1616 0
247 70 1 1 1193 0
248 72 2 1 321 0
249 63 2 1 451 1
250 57 1 5 357 0
251 74 5 2 662 1
252 75 1 4 823 0
253 81 1 1 2518 1
254 87 4 6 703 1
255 52 5 5 2742 0
256 65 4 4 295 1
257 70 2 1 508 0
258 76 2 2 1509 0
259 69 1 2 108 1
260 77 4 1 1589 0
261 84 4 1 341 0
262 52 2 2 1407 0
263 71 4 4 2863 0
264 92 1 2 1659 0
265 71 1 1 586 0
266 92 5 4 1583 1
267 67 1 1 203 0
268 52 5 2 1818 1
269 76 4 1 2269 0
270 94 5 6 2269 1
271 83 1 1 2846 0
272 61 1 1 1969 1
273 66 1 2 849 0
274 61 5 1 1487 0
275 73 2 2 1175 1
276 81 1 6 934 1
277 50 1 5 2229 0
278 83 1 1 1879 0
279 51 2 1 478 1
280 54 5 5 742 0
281 82 4 1 2394 0
282 75 1 1 2630 1
283 67 1 1 2781 0
284 63 4 5 1918 1
285 74 4 1 2651 1
286 72 5 6 199 1
287 57 2 1 2813 1
288 92 1 1 2008 0
289 62 1 6 672 0
290 83 2 1 2609 1
291 62 1 6 2539 0
292 64 1 3 1863 1
293 74 1 4 150 0
294 64 1 4 397 1
295 61 2 1 2070 1
296 72 1 5 242 0
297 74 2 1 2732 1
298 71 2 4 1017 0
299 93 5 4 1530 0
300 92 4 5 2123 0
301 83 2 1 2342 0
302 91 5 4 2092 1
303 80 1 6 1725 0
304 91 4 2 1263 1
305 79 5 5 1757 1
306 77 4 2 1821 0
307 87 4 4 644 1
308 82 4 5 1862 1
309 69 2 2 2465 0
310 89 1 1 2170 0
311 84 1 5 2557 1
312 50 5 1 1984 0
313 93 5 2 2320 0
314 74 1 2 2360 0
315 59 4 1 869 0
316 93 4 1 2136 1
317 94 4 1 2944 0
318 64 5 2 2311 1
319 84 5 4 2045 0
320 55 5 2 1528 0
321 56 2 1 309 0
322 86 2 6 2770 0
323 65 1 1 1913 1
324 55 3 2 403 0
325 73 2 2 870 1
326 87 1 1 2976 0
327 74 1 6 1463 0
328 55 1 2 1939 0
329 67 2 5 1887 0
330 90 4 1 1888 1
331 95 2 2 824 1
332 59 1 1 2197 0
333 65 5 2 344 1
334 60 5 6 2984 1
335 61 5 2 1747 0
336 80 4 4 1170 1
337 90 4 6 830 0
338 72 1 1 1290 1
339 77 1 2 1507 0
340 72 5 6 110 1
341 57 1 6 927 0
342 95 1 4 2372 1
343 78 5 2 1485 1
344 53 1 6 597 0
345 61 1 5 2912 1
346 80 1 2 62 0
347 75 5 1 2936 1
348 56 4 5 2001 1
349 92 4 5 2284 1
350 74 1 4 1761 0
351 92 4 5 571 1
352 61 4 4 2171 0
353 56 1 2 253 0
354 94 4 6 957 1
355 88 4 1 2343 0
356 69 4 2 2172 1
357 61 4 4 2533 1
358 80 1 1 459 1
359 72 1 6 2218 0
360 92 2 6 1176 1
361 83 1 1 1213 0
362 93 4 1 2886 1
363 82 2 1 467 1
364 92 1 3 1505 1
365 58 4 6 2599 1
366 83 4 5 580 0
367 67 4 1 2346 0
368 79 4 1 2059 0
369 53 1 4 1226 0
370 70 4 1 1937 0
371 58 4 2 1904 1
372 56 4 1 371 1
373 90 4 6 2263 0
374 67 2 1 449 0
375 84 2 6 358 0
376 81 1 1 2965 0
377 73 1 4 2290 1
378 51 5 1 565 1
379 77 1 1 1550 0
380 86 2 6 825 1
381 53 2 5 2813 0
382 58 5 1 1241 1
383 90 2 1 56 1
384 78 2 2 1770 1
385 71 4 5 677 0
386 55 5 6 1959 0
387 80 2 6 109 0
388 83 1 1 958 0
389 88 1 2 2801 0
390 58 1 6 490 1
391 83 1 1 2787 1
392 61 5 1 2835 0
393 85 2 1 303 1
394 53 1 6 66 0
395 90 5 5 206 0
396 58 5 1 63 0
397 83 1 2 2013 1
398 72 1 2 2367 0
399 80 5 2 1241 0
400 87 1 5 1463 1
401 69 5 1 1052 0
402 71 4 3 2959 1
403 86 5 1 1123 0
404 81 1 3 1929 0
405 85 2 6 904 1
406 79 2 5 1368 0
407 73 5 1 2928 0
408 61 4 2 479 1
409 68 5 6 944 0
410 69 1 4 275 1
411 94 4 1 404 0
412 59 1 1 2912 1
413 85 2 1 525 0
414 77 1 6 2280 0
415 62 5 1 2953 0
416 81 2 5 2551 1
417 86 2 2 2707 0
418 74 1 2 201 0
419 57 4 1 628 1
420 66 2 4 1514 0
421 84 1 2 967 1
422 61 1 1 1378 0
423 87 4 1 2568 0
424 76 1 4 1092 0
425 64 2 5 2822 1
426 90 5 2 719 0
427 88 2 1 2961 0
428 82 2 2 294 0
429 62 2 5 2777 0
430 84 2 1 1174 1
431 82 4 4 298 1
432 62 5 6 1599 1
433 53 4 2 2037 0
434 76 5 6 1064 0
435 82 2 6 421 0
436 83 4 4 2689 1
437 87 1 1 1767 1
438 59 2 2 2921 0
439 59 4 1 1217 0
440 80 4 2 1817 1
441 52 1 5 1466 0
442 86 4 5 790 1
443 91 4 1 396 1
444 56 4 1 1713 1
445 86 1 1 1213 0
446 89 2 2 1896 1
447 58 2 1 1811 0
448 63 1 1 1577 1
449 62 4 1 1059 0
450 78 1 4 343 1
451 60 5 1 2707 1
452 95 1 4 2219 1
453 60 2 2 2174 1
454 78 1 6 662 0
455 89 4 1 2695 1
456 75 1 6 136 0
457 94 1 2 1620 0
458 85 1 6 1049 1
459 91 5 1 1439 1
460 82 1 1 1998 1
461 58 1 6 1997 1
462 76 4 1 1158 1
463 60 1 4 2946 1
464 72 4 4 2911 1
465 74 1 2 2103 1
466 94 4 1 1879 0
467 52 2 1 2146 0
468 93 5 2 2668 0
469 59 5 1 1535 1
470 65 2 1 394 1
471 83 2 4 2580 1
472 59 1 3 2904 1
473 63 1 1 1772 1
474 57 5 3 2548 1
475 65 4 1 460 0
476 50 2 1 2422 1
477 54 5 2 2631 0
478 77 1 1 1064 1
479 56 5 6 1052 1
480 50 4 1 408 1
481 84 1 5 2055 0
482 72 5 5 967 0
483 77 4 3 2639 0
484 60 2 4 2950 1
485 79 1 5 2752 1
486 62 4 1 1034 0
487 94 1 4 1722 1
488 90 1 4 2500 1
489 95 2 4 555 1
490 87 1 2 2743 1
491 92 4 6 95 1
492 61 4 6 994 0
493 74 2 1 2703 0
494 63 5 5 405 0
495 50 2 1 870 0
496 55 1 1 838 1
497 91 5 1 2921 1
498 93 1 1 383 1
499 92 2 2 181 1
500 84 2 1 1055 0

`# Registry Overview

`## Column {data-width=650}

`### Age at Diagnosis of MCC

dt$subjects <- "subjects" # add a column that unifies all the data (helpful for plotly)
# graph

# Create hover Text
a <- paste("<b>Record ID:</b> ", dt$record_id)
b <- paste("<b>Age at Diagnosis: </b>", dt$age_at_dx)

dt$hover <- paste(a, b, sep = "<br>")

plot_ly(data = dt, type = "box") %>% 
  add_boxplot(x = dt$subjects, 
              y = dt$age_at_dx, 
              boxpoints = "all", 
              jitter = 0.3, 
              pointpos = -1.8,
              marker = list(color = 'rgb(7,40,89)'),
              line = list(color = 'rgb(7,40,89)'),
              color = I("steelblue4")
              ) %>% 
  layout(title = "<b>Age at Diagnosis of MCC</b>") %>% 
  layout(showlegend = FALSE)  %>% 
  layout(
    hoverlabel = list(font=list(size=20))
  )

Age_at_Dx <- dt %>% 
  select(record_id, age_at_dx) %>% 
  drop_na(age_at_dx) # drop_na is a good function to eliminate rows that have missing values

Age_at_Dx$subjects <- "subjects" # add a column that unifies all the data (helpful for plotly)

Age_at_Dx %>% kable
plot_ly(data = Age_at_Dx, type = "box") %>% 
  add_boxplot(x = Age_at_Dx$subjects, y = Age_at_Dx$age_at_dx, 
              boxpoints = "all", jitter = 0.3, pointpos = -1.8,
              marker = list(color = 'rgb(7,40,89)'),
              line = list(color = 'rgb(7,40,89)'),
              color = I("steelblue4"),
              name = "MGH-HCC Cohort") %>% 
  layout(title = "Age at Diagnosis of MCC")

`## Column {data-width=350}

`### Clinical Stage at Diagnosis

cStageDF <- dt %>% 
  group_by(man_clinstage) %>% 
  tally()

cStageDF$stage <- c("I","IIA","IIB","III","IV")

# Create hover Text
a <- paste("<b>Clincal Stage:</b> ", cStageDF$stage)
b <- paste("<b>Number of Subjects: </b>", cStageDF$n)

cStageDF$hover <- paste(a, b, sep = "<br>")

cStage.plot <- plot_ly(data = cStageDF) %>% 
  add_bars(x = cStageDF$man_clinstage, 
           y = cStageDF$n,
           color = I("steelblue4"),
           text = cStageDF$hover,
           hovertemplate = "%{text}<extra></extra>") %>% 
  layout(
    title = "<b>Clinical Stage at Presentation</b>",
    yaxis = list(title = "<b>Number of Subjectsv"),
    xaxis = list(title = "<b>Clincal Stage</b>", 
                 ticktext = list("I", "IIA", "IIB", "III", "IV"), 
                 tickvals = list(1, 2, 3, 4, 5)))

cStage.plot

`### Pathological Stage at Diagnosis

pStage <-dt %>% select(record_id, 
                       man_pathstage)


pStageDF <- pStage %>% 
  group_by(man_pathstage) %>% 
  tally()

pStageDF$stage <- c("I","IIA","IIB","IIIA","IIIB", "IV")

# Create hover Text
a <- paste("<b>Pathological Stage:</b> ", pStageDF$stage)
b <- paste("<b>Number of Subjects: </b>", pStageDF$n)

pStageDF$hover <- paste(a, b, sep = "<br>")

pStage.plot <- plot_ly(data = pStageDF) %>% 
  add_bars(x = pStageDF$man_pathstage, y = pStageDF$n,
           color = I("steelblue4"),
           text = pStageDF$hover,
           hovertemplate = "%{text}<extra></extra>") %>% 
  layout(
    title = "<b>Pathological Stage at Presentation</b>",
    yaxis = list(title = "<b>Number of Subjects</b>"),
    xaxis = list(title = "<b>Pathological Stage</b>", 
                 ticktext = list("I", "IIA", "IIB", "IIIA", "IIIB","IV"), 
                 tickvals = list(1, 2, 3, 4, 5, 6)))

pStage.plot


This is what that RMarkdown looks like with the FlexDashbaord Template

Additional FlexDashboard Formatting to Enhance the User Experience (UX)

Adding Pages to A FlexDashboard

  • If you have numerous data visualizations in your dataset that you want to include in your FlexDashboard, dividing the dashboard into multiple pages can improve the overall UX
  • Each page is defined by a level 1 markdown header, (#), and will have an individual navigation tab
    • For example, in the data shown above, we may want to have the Age of Diagnosis of MCC boxplot on a page by itself, and the Clinical and Pathological Staging bar charts on a second page in the dashboard.

`# PAGE 1: Age at Diagnosis of MCC

### Chart A - Age at Diagnosis of MCC

dt <- read_excel("mcc_cohort_fake.xlsx") # Load the data
Age_at_Dx <- dt %>% select(record_id, age_at_dx) %>% drop_na(age_at_dx) # drop_na is a good function to eliminate rows that have missing values
Age_at_Dx$subjects <- "subjects" # add a column that unifies all the data (helpful for plotly)
Age_at_Dx %>% kable
plot_ly(data = Age_at_Dx, type = "box") %>% 
  add_boxplot(x = Age_at_Dx$subjects, y = Age_at_Dx$age_at_dx, 
              boxpoints = "all", jitter = 0.3, pointpos = -1.8,
              marker = list(color = 'rgb(7,40,89)'),
              line = list(color = 'rgb(7,40,89)'),
              color = I("steelblue4"),
              name = "MGH-HCC Cohort") %>% 
  layout(title = "Age at Diagnosis of MCC")

`# PAGE 2: Staging of MCC

`## Column {data-width=350}

### Chart B - Clinical Stage at Diagnosis of MCC

cStage <-dt %>% select(record_id, man_clinstage, man_pathstage) %>% drop_na(man_clinstage) %>% filter(man_clinstage < 98)
cStageDF <- cStage %>% group_by(man_clinstage) %>% tally()
plot_ly(data = cStageDF) %>% 
  add_bars(x = cStageDF$man_clinstage, y = cStageDF$n,
           color = I("steelblue4")) %>% 
  layout(
    title = "Clinical Stage at Presentation",
    yaxis = list(title = "Number of Subjects"),
    xaxis = list(title = "Clincal Stage", ticktext = list("I", "IIA", "IIB", "III", "IV"), tickvals = list(0, 1, 2, 3, 4)))

### Chart C - Pathological Stage at Diagnosis of MCC

pStage <-dt %>% select(record_id, man_clinstage, man_pathstage) %>% drop_na(man_pathstage) %>% filter(man_pathstage < 6)
pStageDF <- pStage %>% group_by(man_pathstage) %>% tally()
plot_ly(data = pStageDF) %>% 
  add_bars(x = pStageDF$man_pathstage, y = pStageDF$n,
           color = I("steelblue4")) %>% 
  layout(
    title = "Pathological Stage at Presentation",
    yaxis = list(title = "Number of Subjects"),
    xaxis = list(title = "Pathological Stage", ticktext = list("I", "IIA", "IIB", "IIIA", "IIIB","IV"), tickvals = list(0, 1, 2, 3, 4, 5)))

This is what page 1 of the dashboard now looks like
And this is what page 2 of the dashboard now looks like png

Add Tabs to A FlexDashboard

  • If your Dashboard has a lot of content, you may also want to add tabs within pages to further layer the data presentation
  • Instead of using Column {data-width=350} above the dotted lines in your Flex DashBoard, use Column {.tabset}

PAGE 1: Age at Diagnosis of MCC ======================================================
### Chart A - Age at Diagnosis of MCC

dt <- read_excel("mcc_cohort_fake.xlsx") # Load the data
Age_at_Dx <- dt %>% select(record_id, age_at_dx) %>% drop_na(age_at_dx) # drop_na is a good function to eliminate rows that have missing values
Age_at_Dx$subjects <- "subjects" # add a column that unifies all the data (helpful for plotly)
Age_at_Dx %>% kable
plot_ly(data = Age_at_Dx, type = "box") %>% 
  add_boxplot(x = Age_at_Dx$subjects, y = Age_at_Dx$age_at_dx, 
              boxpoints = "all", jitter = 0.3, pointpos = -1.8,
              marker = list(color = 'rgb(7,40,89)'),
              line = list(color = 'rgb(7,40,89)'),
              color = I("steelblue4"),
              name = "MGH-HCC Cohort") %>% 
  layout(title = "Age at Diagnosis of MCC")

PAGE 2: Staging of MCC ======================================================

Column {.tabset}
- - - - - - - - - - - - - - - -

### Chart B - Clinical Stage at Diagnosis of MCC

cStage <-dt %>% select(record_id, man_clinstage, man_pathstage) %>% drop_na(man_clinstage) %>% filter(man_clinstage < 98)
cStageDF <- cStage %>% group_by(man_clinstage) %>% tally()
plot_ly(data = cStageDF) %>% 
  add_bars(x = cStageDF$man_clinstage, y = cStageDF$n,
           color = I("steelblue4")) %>% 
  layout(
    title = "Clinical Stage at Presentation",
    yaxis = list(title = "Number of Subjects"),
    xaxis = list(title = "Clincal Stage", ticktext = list("I", "IIA", "IIB", "III", "IV"), tickvals = list(0, 1, 2, 3, 4)))

### Chart C - Pathological Stage at Diagnosis of MCC

pStage <-dt %>% select(record_id, man_clinstage, man_pathstage) %>% drop_na(man_pathstage) %>% filter(man_pathstage < 6)
pStageDF <- pStage %>% group_by(man_pathstage) %>% tally()
plot_ly(data = pStageDF) %>% 
  add_bars(x = pStageDF$man_pathstage, y = pStageDF$n,
           color = I("steelblue4")) %>% 
  layout(
    title = "Pathological Stage at Presentation",
    yaxis = list(title = "Number of Subjects"),
    xaxis = list(title = "Pathological Stage", ticktext = list("I", "IIA", "IIB", "IIIA", "IIIB","IV"), tickvals = list(0, 1, 2, 3, 4, 5)))

This is the rmd of the FlexDashboard with the green arrow highlighting this critical line of code


This is now what page 2 of the dashboard looks like

You will notice that the Clinical and Pathological Staging bar charts are no longer stacked in two rows on the same page. In contrast, you only see the Clinical Stage at Presentation graph, which takes up the entire page. You can see the tab in the upper left corner; if you click on the second tab, the chart for Pathological Stage at Presentation will emerge (see below).

Adding Side-by_Side Images Within a tabset Page

  • If you want to have a section that has multiple tabset pages, for example as seen here

and then you want one of those pages to have side-by-side images (e.g.), you can use the following strategy
* Create the two graphs you would like side-by-side
* Save them both as objects
* Then within the level three header ### (as above Bar Graphs of Staging), use cowplot::plot.grid(image1, image2) to execute that graph
* For example, you can see the code we used here

Take Home Points

  • Dashboards are an excellent data visualization tool for Clinical and Translational Research
  • Flexdashboard is a great package to develop dashboards with R
  • Adding pages and tabs to your dashboard can create a richer user experience for your intended audience

As always, please reach out to us with thoughts and feedback

Session Info

sessionInfo()
## R version 4.0.0 (2020-04-24)
## Platform: x86_64-apple-darwin17.0 (64-bit)
## Running under: macOS Mojave 10.14.6
## 
## Matrix products: default
## BLAS:   /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRblas.dylib
## LAPACK: /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRlapack.dylib
## 
## locale:
## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
##  [1] cowplot_1.1.0       scales_1.1.1        readxl_1.3.1       
##  [4] plotly_4.9.2.1      knitr_1.30          forcats_0.5.0      
##  [7] stringr_1.4.0       dplyr_1.0.2         purrr_0.3.4        
## [10] readr_1.4.0         tidyr_1.1.2         tibble_3.0.4       
## [13] ggplot2_3.3.2       tidyverse_1.3.0     httr_1.4.2         
## [16] REDCapR_0.11.0      RCurl_1.98-1.2      flexdashboard_0.5.2
## 
## loaded via a namespace (and not attached):
##  [1] Rcpp_1.0.5        lubridate_1.7.9.2 assertthat_0.2.1  digest_0.6.27    
##  [5] R6_2.5.0          cellranger_1.1.0  backports_1.2.0   reprex_0.3.0     
##  [9] evaluate_0.14     highr_0.8         blogdown_0.21     pillar_1.4.7     
## [13] rlang_0.4.8       lazyeval_0.2.2    rstudioapi_0.13   data.table_1.13.2
## [17] rmarkdown_2.5     webshot_0.5.2     htmlwidgets_1.5.3 munsell_0.5.0    
## [21] broom_0.7.2       compiler_4.0.0    modelr_0.1.8      xfun_0.19        
## [25] pkgconfig_2.0.3   htmltools_0.5.0   tidyselect_1.1.0  bookdown_0.21    
## [29] fansi_0.4.1       viridisLite_0.3.0 crayon_1.3.4      dbplyr_2.0.0     
## [33] withr_2.3.0       bitops_1.0-6      grid_4.0.0        jsonlite_1.7.1   
## [37] gtable_0.3.0      lifecycle_0.2.0   DBI_1.1.0         magrittr_2.0.1   
## [41] cli_2.2.0         stringi_1.5.3     fs_1.5.0          xml2_1.3.2       
## [45] ellipsis_0.3.1    generics_0.1.0    vctrs_0.3.5       kableExtra_1.3.1 
## [49] tools_4.0.0       glue_1.4.2        hms_0.5.3         yaml_2.2.1       
## [53] colorspace_2.0-0  rvest_0.3.6       haven_2.3.1
Avatar
David Michael Miller
Medical Oncologist and Dermatologist

My research interests include clinical and translational research in advanced skin cancers.

Related