/
02_shinydashboard.Rmd
317 lines (244 loc) · 12.6 KB
/
02_shinydashboard.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
# ShinyDashboard {#shinydashboard}
[Shinydashboard](https://rstudio.github.io/shinydashboard/){target="_blank"} is an R `r glossary("package")` that provides functions to upgrade the appearance and function of your Shiny apps.
## Basic template for shinydashboard projects
The `r pkg("shinyintro")` package provides a basic template for a shinydashboard `r glossary("project")`.
```{r basic-template-app, eval=TRUE, echo=FALSE, fig.cap="Basic Template.App You can also access this app with `shinyintro::app(\"basic_template\")`or view it in a [separate tab](https://shiny.psy.gla.ac.uk/debruine/basic_template/){target=\"_blank\"}."}
if (is_html)
knitr::include_app("https://shiny.psy.gla.ac.uk/debruine/basic_template/",
height = "400px")
```
----
You can start a new app using the template with the code `shinyintro::clone("basic_template", "myapp")`. This will create a new directory called `r path("myapp")` in your `r glossary("working directory")` and open the `r path("app.R")` file in RStudio.
This directory contains:
* `r path("app.R")`: the file where you define the `r glossary("ui")` and `r glossary("server")`
* `r path("DESCRIPTION")`: A file that contains some structured info about the app
* `r path("README.md")`: A file that can contain any information you want
* `r path("scripts")`: a directory that can contain external R code that you can source into the `r path("app.R")` file
* `r path("www")`: a directory that contains helper files like images, `r glossary("CSS")`, and `r glossary("JavaScript")`
## Dashboard Structure
Notice that the ui is created with `r func("dashboardPage")` now. This needs to be set up a little differently than `r func("fluidPage")`. The main parts of a dashboard page are the header, sidebar, and body.
You can also change the default `r arg("skin")` colour. Possible skin colours are: `r dt("red")`, `r dt("yellow")` (looks orange to me), `r dt("green")`, `r dt("blue")`, `r dt("purple")`, and `r dt("black")`.
```{r}
dashboardPage(skin = "purple",
dashboardHeader(),
dashboardSidebar(),
dashboardBody())
```
### dashboardHeader
You can add a title to the header, and change the title width.
```{r}
dashboardHeader(title = "Basic Template",
# puts sidebar toggle on right
titleWidth = "calc(100% - 44px)")
```
You can also include message, notification, and task menus in the header. We won't be using those in this class, but you can learn more at [the shinydashboard site](https://rstudio.github.io/shinydashboard/structure.html#message-menus){target="_blank"}.
::: {.info data-latex=""}
If you don't want to use a header, include `dashboardHeader(disable = TRUE)` inside `r func("dashboardPage")`.
:::
### dashboardSidebar
The sidebar usually contains a `r func("sidebarMenu")`, which needs a unique ID and a list of menu items. Each `r func("menuItem")` consists of the `r arg("title")`, a `r arg("tabName")` that will be used to refer to the tab later, and an `r arg("icon")`. You can find a list of the available free icons at [fontawesome](https://fontawesome.com/icons?d=gallery&m=free){target="_blank"}.
You can also add in any other elements to the sidebar. The code below adds a link using `r func("tags$a")` Text inside of the sidebar usually looks too close to the edges, so we use [css](#CSS) to style the link and add padding.
```{r}
dashboardSidebar(
sidebarMenu(id = "tabs",
menuItem(
"Tab Title",
tabName = "demo_tab",
icon = icon("dragon")
)),
tags$a("ShinyIntro book",
href = "https://debruine.github.io/shinyintro/",
style = "padding: 1em;")
)
```
::: {.info data-latex=""}
If you don't want to use a sidebar, include `dashboardSidebar(disable = TRUE)` inside `r func("dashboardPage")`.
:::
### dashboardBody
The main part of the app goes inside `r func("dashboardBody")` If you're going to use `r glossary("javascript")` functions (which the basic template does and we'll learn more about in Section\ \@ref(shinyjs)), you need to put `r func("useShinyjs")` first. Then you include the head, linking to any custom CSS or JavaScript files.
The contents of the body go after that. The most common pattern is a multi-page tabbed pattern, which is set up with `r func("tabItems")`, containing a `r func("tabItem")` for each tab. The `r arg("tabName")` has to match the name you used in the sidebar `r func("menuItem")`, so that tab shows when the user clicks on the corresponding menu item.
```{r}
dashboardBody(
shinyjs::useShinyjs(),
tags$head(
# links to files in www/
tags$link(rel = "stylesheet",
type = "text/css",
href = "custom.css"),
tags$script(src = "custom.js")
),
tabItems(
tabItem(tabName = "demo_tab",
imageOutput("logo"))
)
)
```
Since each tab is usually a quite complex list of elements, I like to define each tab outside `r func("dashboardPage")` and then just put a list of the tab objects inside `r func("tabItems")`. This way, it's easy to move the whole tab definition to an external file if it gets too complex (see Section\ \@ref(structure)).
## Body Structure
Tab items can be structured in several ways. At the simplest, you can just list each element after the `r arg("tabName")`.
```{r}
tabItem(
tabName = "demo_tab",
textInput("given", "Given Name"),
textInput("surname", "Surname"),
selectInput("pet", "What is your favourite pet?",
c("cats", "dogs", "ferrets")),
textAreaInput("bio", NULL,
height = "100px",
placeholder = "brief bio")
)
```
### Boxes
Most `r pkg("shinydashboard")` apps organise the parts inside boxes.
```{r}
tabItem(tabName = "demo_tab",
box(
textInput("given", "Given Name"),
textInput("surname", "Surname"),
selectInput("pet", "What is your favourite pet?",
c("cats", "dogs", "ferrets"))
),
box(
textAreaInput("bio", NULL,
height = "100px",
placeholder = "brief bio")
))
```
```{r sdb-layout2, eval=TRUE, echo=FALSE, fig.cap = 'Organizing elements inside boxes.'}
knitr::include_graphics('images/sdb_layout2.png')
```
You can add titles to the boxes, make them collapsible and/or give them solid headers.
```{r}
tabItem(
tabName = "demo_tab",
box(title = "Personal Info",
collapsible = TRUE,
textInput("given", "Given Name"),
textInput("surname", "Surname"),
selectInput("pet", "What is your favourite pet?", c("cats", "dogs", "ferrets"))
),
box(title = "Biography",
solidHeader = TRUE,
textAreaInput("bio", NULL, height = "100px", placeholder = "brief bio")
)
)
```
<img src="images/sdb_box_collapse.gif" />
In the normal shinydashboard style, solid headers only have a colour if the box also has the status argument set. In the basic template provided in this class, there is custom CSS to make solid headers the same colour as the theme skin, but you can also set the `r arg("status")`.
```{r}
tabItem(
tabName = "demo_tab",
box(title = "No Status", solidHeader = TRUE),
box(title = "Primary", solidHeader = TRUE, status = "primary"),
box(title = "Success", solidHeader = TRUE, status = "success"),
box(title = "Info", solidHeader = TRUE, status = "info"),
box(title = "Warning", solidHeader = TRUE, status = "warning"),
box(title = "Danger", solidHeader = TRUE, status = "danger")
)
```
```{r sdb-box-status, eval=TRUE, echo=FALSE, fig.cap = 'Shinydashboard Box Statuses.'}
knitr::include_graphics('images/sdb_box_status.png')
```
### Info and Value Boxes
You can use an `r func("infoBox")` or a `r func("valueBox")` to highlight a small amount of information. The default background is aqua, but the basic template changes this to the skin colour. However, you can customise this by setting the `r arg("color")` argument.
```{r}
tabItem(
tabName = "demo_tab",
infoBox("Default InfoBox", "Value", "Subtitle"),
valueBox("Default ValueBox", "With subtitle"),
valueBox("No subtitle", "")
)
```
```{r sdb-value-info, eval=TRUE, echo=FALSE, fig.cap = 'Examples of value and info boxes you can make.'}
knitr::include_graphics('images/sdb_value_info.png')
```
`r pkg("Shinydashboard")` uses a grid system that is `r dt(12)` units across. The default width of boxes is `r dt(6)`, and info and value boxes are `r dt(4)`.
::: {.try data-latex=""}
Try to write the code to create the second row of info boxes shown above and the third row of value boxes.
:::
### Tab Boxes
Create a box with multiple tabs using `r func("tabBox")`, which contains `r func("tabPanel")`.
```{r}
tabItem(
tabName = "demo_tab",
tabBox(
title = "Test Yourself 1",
tabPanel("Question", "What function creates tabBox contents?"),
tabPanel("Answer", "tabPanel()")
),
tabBox(
title = "Test Yourself 2",
side = "right",
selected = "Question",
tabPanel("Answer", "selected"),
tabPanel("Question", "What attribute changes the default tab?")
)
)
```
```{r sdb-tab-box, eval=TRUE, echo=FALSE, fig.cap = 'Tab Boxes'}
knitr::include_graphics('images/sdb_tab_box.png')
```
### Row Layout
You can arrange the boxes inside a `r func("fluidRow")`. Set the box height in pixels. If the window gets too narrow, the boxes will move to stack instead of be in rows.
```{r}
tabItem(
tabName = "demo_tab",
fluidRow(
box("A", title = "2x100", width = 2, height = 100),
box("B", title = "1x100", width = 1, height = 100),
box("C", title = "2x200", width = 2, height = 200),
box("D", title = "3x300", width = 3, height = 300),
box("E", title = "4x100", width = 4, height = 100),
box("F", title = "5x100", width = 5, height = 100),
box("G", title = "7x100", width = 7, height = 100)
)
)
```
```{r sdb-row-layout, eval=TRUE, echo=FALSE, fig.cap = 'An example fluidRow layout of boxes with different widths and heights.'}
knitr::include_graphics('images/sdb_row_layout.png')
```
### Column Layout
Alternatively, you can arrange boxes or other elements inside a `r func("column")` with a specific `r arg("width")`. Elements inside this column have a width relative to the column width, so no matter what value you set the column `r arg("width")` to, an element inside with a `r arg("width")` of `r dt(6)` will be half the column width.
```{r}
tabItem(
tabName = "demo_tab",
column(width = 6,
box("A", title = "12x100", width = 12, height = 100),
box("B", title = "6x100", width = 6, height = 100),
box("C", title = "6x200", width = 6, height = 200)
),
column(width = 4,
box("D", title = "12x300", width = 12, height = 300),
box("E", title = "12x100", width = 12, height = 100)
),
column(width = 2,
box("F", title = "12x100", width = 12, height = 100),
box("G", title = "12x100", width = 12, height = 100)
)
)
```
```{r sdb-column-layout, eval=TRUE, echo=FALSE, fig.cap = 'An example for column layout.'}
knitr::include_graphics('images/sdb_column_layout.png')
```
## Further Resources {#resources-shinydashboard}
* [ShinyDashboard](https://rstudio.github.io/shinydashboard/){target="_blank"}
## Your App {#your-app-sdb}
### Create an app from the basic template
* Create a demo app from the basic template and run it.
* Close the app and run it again.
* Look at the code to see how the theme colour and sidebar icon change.
* Change the title and author in the `r path("DESCRIPTION")` file and set DisplayMode to "Showcase" instead of "Normal" to see what happens when you run it.
### Customize the header
* Change the `r arg("title")` to the title of the app you want to build.
* Choose a `r arg("skin")` color.
* Experiment with different values for the `r arg("titleWidth")` argument. Try `r dt("50%")` or `r dt("200px")` and see how the title behaves when you change the width of the browser window.
### Customize the sidebar
* Add tabs to the `r func("sidebarMenu")` for the pages of your custom app.
* Choose appropriate `r arg("icon")` for each tab.
* Remove the link to the ShinyIntro book and add some information about your app, like the author or a use license.
### Customize the body
* Create an empty `r func("tabItem")` for each tab you put in the `r func("sidebarMenu")` and add them to the `r func("dashboardBody")`.
* Start adding elements to each tab, such as a list of inputs with questions or a `r func("plotOutput")` to display a feedback plot.
* Experiment with different ways to display the elements by grouping them into boxes
* Experiment with different layouts for your boxes and elements.
* Make sure you check how the app looks on different sized screens, such as phone screens.