├── .gitignore
├── figs
├── inputs.png
├── new_app.png
├── outputs.png
└── rstudio-hex-shiny-dot-psd.png
├── README.md
├── intro_to_shiny.Rproj
├── apps
├── session_one_app
│ └── app.R
├── mortality_report.Rmd
└── mortality_dashboard.Rmd
├── shiny_session_one.Rmd
├── shiny_session_two.Rmd
├── shiny_session_three.Rmd
├── shiny_session_one.html
├── shiny_session_two.html
└── shiny_session_three.html
/.gitignore:
--------------------------------------------------------------------------------
1 | .RHistory
2 | .Rproj.user
3 | *cache
4 | *files
5 |
--------------------------------------------------------------------------------
/figs/inputs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/juliasilge/intro_to_shiny/HEAD/figs/inputs.png
--------------------------------------------------------------------------------
/figs/new_app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/juliasilge/intro_to_shiny/HEAD/figs/new_app.png
--------------------------------------------------------------------------------
/figs/outputs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/juliasilge/intro_to_shiny/HEAD/figs/outputs.png
--------------------------------------------------------------------------------
/figs/rstudio-hex-shiny-dot-psd.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/juliasilge/intro_to_shiny/HEAD/figs/rstudio-hex-shiny-dot-psd.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # An Introduction to Shiny
2 |
3 | Some slides and apps for my introductory Shiny workshop at the February 2017 [satRday conference in Cape Town, South Africa](http://satrdays.org/capetown2017/)
--------------------------------------------------------------------------------
/intro_to_shiny.Rproj:
--------------------------------------------------------------------------------
1 | Version: 1.0
2 |
3 | RestoreWorkspace: Default
4 | SaveWorkspace: Default
5 | AlwaysSaveHistory: Default
6 |
7 | EnableCodeIndexing: Yes
8 | UseSpacesForTab: Yes
9 | NumSpacesForTab: 4
10 | Encoding: UTF-8
11 |
12 | RnwWeave: Sweave
13 | LaTeX: pdfLaTeX
14 |
--------------------------------------------------------------------------------
/apps/session_one_app/app.R:
--------------------------------------------------------------------------------
1 | library(shiny)
2 | library(ggplot2)
3 | library(dplyr)
4 | library(DT)
5 | library(southafricastats)
6 |
7 | mortality_zaf <- mortality_zaf %>%
8 | filter(!(indicator %in% c("All causes")))
9 |
10 | # body of the UI
11 | ui <- fluidPage(
12 |
13 | # application title
14 | titlePanel("Mortality in South African Provinces"),
15 |
16 | # sidebar with input
17 | sidebarLayout(
18 | sidebarPanel(
19 | selectInput(inputId = "province",
20 | label = "Province:",
21 | choices = unique(mortality_zaf$province),
22 | selected = "Gauteng",
23 | multiple = TRUE),
24 | checkboxInput(inputId = "show_data",
25 | label = "Show table?",
26 | value = FALSE)
27 | ),
28 |
29 | # show the output
30 | mainPanel(
31 | plotOutput(outputId = "mortalityPlot"),
32 | dataTableOutput(outputId = "mortalityTable")
33 | )
34 | )
35 | )
36 |
37 | # calculations behind the scenes
38 | server <- function(input, output) {
39 |
40 | selected_df <- reactive({
41 | mortality_zaf %>%
42 | filter(province %in% input$province)
43 | })
44 |
45 | output$mortalityPlot <- renderPlot({
46 | selected_df() %>%
47 | ggplot(aes(year, deaths, color = indicator)) +
48 | geom_line(alpha = 0.8, size = 1.5) +
49 | facet_wrap(~province, scales = "free") +
50 | theme_minimal(base_size = 18)
51 | })
52 |
53 | output$mortalityTable <- renderDataTable({
54 | if(input$show_data){
55 | DT::datatable(data = selected_df())
56 | }
57 | })
58 |
59 | }
60 |
61 | # run the application
62 | shinyApp(ui = ui, server = server)
63 |
64 |
--------------------------------------------------------------------------------
/apps/mortality_report.Rmd:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Mortality in South African Provinces"
3 | author: "Julia Silge"
4 | date: "2/5/2017"
5 | output: html_document
6 | runtime: shiny
7 | ---
8 |
9 | ```{r setup, include=FALSE}
10 | knitr::opts_chunk$set(echo = TRUE, warning = FALSE, message = FALSE)
11 | ```
12 |
13 | ## Plot without Shiny
14 |
15 | ```{r}
16 | library(dplyr)
17 | library(tidyr)
18 | library(ggplot2)
19 | library(southafricastats)
20 |
21 | totals <- population_zaf %>%
22 | filter(year == 2013) %>%
23 | select(province, total)
24 |
25 |
26 | compare_provinces <- mortality_zaf %>%
27 | left_join(population_zaf) %>%
28 | filter(!is.na(total)) %>%
29 | mutate(mortality = deaths / total * 1e3) %>%
30 | group_by(province, indicator) %>%
31 | summarise(mortality = mean(mortality, na.rm = TRUE)) %>%
32 | ungroup %>%
33 | left_join(totals) %>%
34 | spread(indicator, mortality)
35 |
36 | ```
37 |
38 |
39 | ```{r, fig.width=8, fig.height=6, echo=FALSE}
40 | ggplot(compare_provinces, aes(`Cerebrovascular diseases (I60-I69)`,
41 | `Diabetes mellitus (E10-E14)`,
42 | size = total,
43 | label = province)) +
44 | geom_point(alpha = 0.7, color = "midnightblue") +
45 | geom_text(aes(size = 3e6), vjust = 2.5) +
46 | theme_minimal() +
47 | theme(legend.position="none")
48 | ```
49 |
50 | ## Interactive Shiny version of plot
51 |
52 | ```{r, echo = FALSE}
53 | selectInput(inputId = "x",
54 | label = "X-axis:",
55 | choices = colnames(compare_provinces)[3:20],
56 | selected = "Other forms of heart disease (I30-I52)")
57 |
58 | selectInput(inputId = "y",
59 | label = "Y-axis:",
60 | choices = colnames(compare_provinces)[3:20],
61 | selected = "Non-natural causes")
62 | ```
63 |
64 | ```{r, echo = FALSE, fig.width=8, fig.height=8}
65 |
66 | selected_df <- reactive({
67 | subset_df <- compare_provinces[, c(1:2,
68 | which(colnames(compare_provinces) == input$x),
69 | which(colnames(compare_provinces) == input$y))]
70 | colnames(subset_df) <- c("province", "total", "selected_x", "selected_y")
71 | subset_df
72 | })
73 |
74 | fillCol(height = 800,
75 | renderPlot({
76 | ggplot(selected_df(), aes(x = selected_x,
77 | y = selected_y,
78 | size = total,
79 | label = province)) +
80 | geom_point(alpha = 0.7, color = "midnightblue") +
81 | theme_minimal() +
82 | labs(x = input$x, y = input$y) +
83 | geom_text(aes(size = 1e7), vjust = 2) +
84 | theme_minimal(base_size = 14) +
85 | theme(legend.position="none")
86 | }, height = 800)
87 | )
88 | ```
89 |
90 |
--------------------------------------------------------------------------------
/apps/mortality_dashboard.Rmd:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Mortality in South African Provinces"
3 | runtime: shiny
4 | output:
5 | flexdashboard::flex_dashboard:
6 | orientation: columns
7 | vertical_layout: fill
8 | ---
9 |
10 | ```{r setup, include=FALSE}
11 | library(flexdashboard)
12 | library(shiny)
13 | library(dplyr)
14 | library(tidyr)
15 | library(ggplot2)
16 | library(leaflet)
17 | library(southafricastats)
18 |
19 | totals <- population_zaf %>%
20 | filter(year == 2013) %>%
21 | select(province, total)
22 |
23 | compare_provinces <- mortality_zaf %>%
24 | left_join(population_zaf) %>%
25 | filter(!is.na(total)) %>%
26 | mutate(mortality = deaths / total * 1e3) %>%
27 | group_by(province, indicator) %>%
28 | summarise(mortality = mean(mortality, na.rm = TRUE)) %>%
29 | ungroup %>%
30 | left_join(totals) %>%
31 | spread(indicator, mortality)
32 |
33 | mortality_zaf <- mortality_zaf %>%
34 | filter(!(indicator %in% c("All causes")))
35 |
36 | ```
37 |
38 | Column {.sidebar}
39 | =====================================================================
40 |
41 | This app explores mortality data from the [South Africa Data Portal](http://southafrica.opendataforafrica.org/).
42 |
43 | Use the input below to select a cause of death to explore.
44 |
45 | ```{r}
46 | selectInput(inputId = "indicator",
47 | label = "Cause of death:",
48 | choices = unique(mortality_zaf$indicator),
49 | selected = "Tuberculosis (A15-A19)")
50 | ```
51 |
52 |
53 |
54 | Map {data-icon="fa-map-marker"}
55 | ====================================================================
56 |
57 | ### Which provinces have a higher mortality rate from the selected cause of death?
58 |
59 | ```{r}
60 | selected_df <- reactive({
61 | subset_df <- compare_provinces[, c(1,
62 | which(colnames(compare_provinces) == input$indicator))]
63 | colnames(subset_df) <- c("province", "indicator")
64 | population_zaf %>%
65 | filter(year == 2013) %>%
66 | left_join(subset_df, by = "province") %>%
67 | mutate(indicator = indicator / sum(indicator, na.rm = TRUE))
68 | })
69 |
70 | renderLeaflet({
71 | leaflet(selected_df()) %>%
72 | addProviderTiles("CartoDB.Positron") %>%
73 | addCircles(lng = ~longitude, lat = ~latitude, weight = 2.5,
74 | radius = ~sqrt(indicator) * 3e5 , popup = ~province,
75 | color = "magenta")
76 | })
77 | ```
78 |
79 | Comparing provinces {data-icon="fa-list"}
80 | ====================================================================
81 |
82 | ### How does the selected mortality rate compare to the overall mortality rate?
83 |
84 | ```{r}
85 | scatterplot_df <- reactive({
86 | subset_df <- compare_provinces[, c(1:2,
87 | which(colnames(compare_provinces) == "All causes"),
88 | which(colnames(compare_provinces) == input$indicator))]
89 | colnames(subset_df) <- c("province", "total", "selected_x", "selected_y")
90 | subset_df
91 | })
92 |
93 | renderPlot({
94 | ggplot(scatterplot_df(), aes(x = selected_x,
95 | y = selected_y,
96 | size = total,
97 | label = province)) +
98 | geom_point(alpha = 0.7, color = "magenta4") +
99 | theme_minimal() +
100 | labs(x = "All causes", y = input$indicator) +
101 | geom_text(aes(size = 1e7), vjust = 2) +
102 | scale_x_continuous(limits = c(7.7, 14.2)) +
103 | theme_minimal(base_size = 14) +
104 | theme(legend.position="none")
105 | })
106 | ```
107 |
108 | Changes in time {data-icon="fa-area-chart"}
109 | ====================================================================
110 |
111 | ### How have the number of deaths changed in time?
112 |
113 | ```{r}
114 | renderPlot({
115 | mortality_zaf %>%
116 | filter(indicator == input$indicator) %>%
117 | ggplot(aes(year, deaths, color = province)) +
118 | geom_line(alpha = 0.8, size = 1.5) +
119 | theme_minimal(base_size = 18) +
120 | labs(x = NULL, y = "Number of deaths per year")
121 | })
122 | ```
123 |
124 |
125 | Table {data-icon="fa-table"}
126 | ====================================================================
127 |
128 | ### Explore the data as reported by the South Africa Data Portal
129 |
130 | ```{r}
131 | renderDataTable({
132 | mortality_zaf %>%
133 | filter(indicator == input$indicator)
134 | },
135 | options = list(pageLength = 10)
136 | )
137 | ```
138 |
--------------------------------------------------------------------------------
/shiny_session_one.Rmd:
--------------------------------------------------------------------------------
1 | ---
2 | title: "An Introduction to Shiny"
3 | author: "Julia Silge"
4 | output:
5 | rmdshower::shower_presentation:
6 | self_contained: false
7 | highlight: tango
8 | ---
9 |
10 | ```{r, echo = FALSE, warning = FALSE}
11 | library(knitr)
12 | knitr::opts_chunk$set(cache = TRUE, warning = FALSE, message = FALSE, dpi = 180)
13 | options(width=80)
14 | # to knit this document use devtools::install_github("mangothecat/rmdshower")
15 | ```
16 |
17 | ## An Introduction to Shiny
18 |
19 |
20 |
21 | ### Julia Silge (Stack Overflow)
22 |
23 | #### [\@juliasilge](https://twitter.com/juliasilge)
24 |
25 | #### [http://juliasilge.com/](http://juliasilge.com/)
26 |
27 |
28 | ## Let's install some packages
29 |
30 | ```{r, eval=FALSE}
31 | install.packages(c("shiny",
32 | "dplyr",
33 | "ggplot2",
34 | "DT"
35 | "devtools"))
36 |
37 | devtools::install_github("juliasilge/southafricastats")
38 | ```
39 |
40 | # What is a Shiny app?
41 |
42 | ## A web application framework for R
43 |
44 | - Shiny allows us as data scientists and analysts to turn our analyses written in R into interactive apps
45 | - A Shiny app is run by a server (computer)
46 |
47 |
48 |
49 | ## Navigation
50 |
51 | - Different viewing modes
52 | - How do you close the app?
53 | - Remember that your computer is running (i.e., serving) the app
54 | - The app is *reactive*
55 |
56 | ## Shiny is flexible {.grid}
57 |
58 | - Check out a [complex example](https://beta.rstudioconnect.com/jcheng/scorecard-app/)
59 | - What is in [the code](https://github.com/jcheng5/scorecard-app)?
60 |
61 | # Inputs and outputs
62 |
63 | ## Reactive programming
64 |
65 | - A Shiny app has an UI and a server function
66 | - The UI controls how the app looks and is laid out
67 | - The server function has the instructions about how to build the app
68 |
69 | ## Reactive programming
70 |
71 | - Most of us who write R code are used to writing scripts to analyze data that are imperative or procedural (or maybe functional)
72 | - A reactive paradigm focuses on how data will flow through the code and how changes propagate
73 | - Reactive programming is important when a user is interacting with an interface
74 |
75 |
76 | ## Inputs {.grid}
77 |
78 |
79 |
80 |
81 | ## Outputs {.grid}
82 |
83 |
84 |
85 | [https://www.rstudio.com/resources/cheatsheets/](https://www.rstudio.com/resources/cheatsheets/)
86 |
87 | ## First steps to reactivity
88 |
89 | Reactivity occurs when an input value is used to render an output object
90 |
91 | ```{r, eval = FALSE}
92 | selectInput(inputId = "province",
93 | label = "Province:",
94 | choices = unique(mortality$province),
95 | selected = "Gauteng")
96 | ```
97 |
98 | ## First steps to reactivity
99 |
100 | Reactivity occurs when an input value is used to render an output object
101 |
102 | ```{r, eval = FALSE}
103 | # calculations behind the scenes
104 | server <- function(input, output) {
105 |
106 | output$mortalityPlot <- renderPlot({
107 | mortality %>%
108 | filter(province == input$province) %>%
109 | ggplot(aes(year, deaths, color = indicator)) +
110 | geom_line(alpha = 0.8, size = 1.5) +
111 | theme_minimal(base_size = 18)
112 | })
113 | }
114 | ```
115 |
116 | ## First steps to reactivity {.grid}
117 |
118 | Reactivity occurs when an input value is used to render an output object
119 |
120 | - Be sure to add the necessary libraries at the beginning of the app
121 | - Change the name of your output plot
122 | - Do you want to filter out any of the mortality causes?
123 |
124 | ## A new kind of input
125 |
126 | We can select more than one thing at a time
127 |
128 | ```{r, eval = FALSE}
129 | selectInput(inputId = "province",
130 | label = "Province:",
131 | choices = unique(mortality$province),
132 | selected = "Gauteng",
133 | multiple = TRUE)
134 | ```
135 |
136 | ## A new kind of input
137 |
138 | We can select more than one thing at a time
139 |
140 | ```{r, eval = FALSE}
141 | # calculations behind the scenes
142 | server <- function(input, output) {
143 |
144 | output$mortalityPlot <- renderPlot({
145 | mortality %>%
146 | filter(province %in% input$province) %>%
147 | ggplot(aes(year, deaths, color = indicator)) +
148 | geom_line(alpha = 0.8, size = 1.5) +
149 | facet_wrap(~province, scales = "free") +
150 | theme_minimal(base_size = 18)
151 | })
152 | }
153 | ```
154 |
155 | ## Checkbox input
156 |
157 | ```{r, eval = FALSE}
158 | checkboxInput(inputId = "show_data",
159 | label = "Show table?",
160 | value = FALSE)
161 | ```
162 |
163 | ## Checkbox input
164 |
165 | ```{r, eval = FALSE}
166 | output$mortalityTable <- renderDataTable({
167 | if(input$show_data){
168 | DT::datatable(data = selected_df())
169 | }
170 | })
171 | ```
172 |
173 | # Sharing your app
174 |
175 | ## With someone who has R installed?
176 |
177 | - Share the code for your app (`app.R`)
178 | - Your collaborator can run the app locally
179 |
180 | ## With everyone publicly?
181 |
182 | - Publish using an account on [shinyapps.io](http://www.shinyapps.io/)
183 | - There are a variety of scalable options from free to \$\$\$
184 | - I started with a free account and now pay for a starter account (after a few of my blog posts with Shiny apps got a lot of views)
185 |
186 | ## With people in your organization?
187 |
188 | - Consider installing Shiny Server on a machine of your own
189 | - It was much easier than I thought
190 | - Check out RStudio's [clear, helpful instructions](https://www.rstudio.com/products/shiny/download-server/)
191 |
--------------------------------------------------------------------------------
/shiny_session_two.Rmd:
--------------------------------------------------------------------------------
1 | ---
2 | title: "An Introduction to Shiny"
3 | author: "Julia Silge"
4 | output:
5 | rmdshower::shower_presentation:
6 | self_contained: false
7 | highlight: tango
8 | ---
9 |
10 | ```{r, echo = FALSE, warning = FALSE}
11 | library(knitr)
12 | knitr::opts_chunk$set(cache = TRUE, warning = FALSE, message = FALSE, dpi = 180)
13 | options(width=80)
14 | # to knit this document use devtools::install_github("mangothecat/rmdshower")
15 | ```
16 |
17 | ## An Introduction to Shiny: Session Two
18 |
19 |
20 |
21 | ### Julia Silge (Stack Overflow)
22 |
23 | #### [\@juliasilge](https://twitter.com/juliasilge)
24 |
25 | #### [http://juliasilge.com/](http://juliasilge.com/)
26 |
27 | ## Shiny + R Markdown
28 |
29 | - R Markdown is my jam
30 | - We can use Shiny to make interactive reports with R Markdown
31 | - Add `runtime: shiny` to the YAML of an R Markdown document
32 |
33 | ## Let's install some packages
34 |
35 | ```{r, eval=FALSE}
36 | install.packages(c("shiny",
37 | "dplyr",
38 | "ggplot2",
39 | "tidyr",
40 | "flexdashboard",
41 | "devtools"))
42 |
43 | devtools::install_github("juliasilge/southafricastats")
44 | ```
45 |
46 |
47 | ## Extending R Markdown with Shiny {.grid}
48 |
49 | - R Markdown has built-in capability to handle Shiny reactivity
50 | - We can write reports that are interactive to the user
51 | - R Markdown reports with Shiny must be run locally or by a Shiny server
52 |
53 | ## Making a regular plot
54 |
55 | ```{r}
56 | library(dplyr)
57 | library(tidyr)
58 | library(ggplot2)
59 | library(southafricastats)
60 |
61 | totals <- population_zaf %>%
62 | filter(year == 2013) %>%
63 | select(province, total)
64 |
65 |
66 | compare_provinces <- mortality_zaf %>%
67 | left_join(population_zaf) %>%
68 | filter(!is.na(total)) %>%
69 | mutate(mortality = deaths / total * 1e3) %>%
70 | group_by(province, indicator) %>%
71 | summarise(mortality = mean(mortality, na.rm = TRUE)) %>%
72 | ungroup %>%
73 | left_join(totals) %>%
74 | spread(indicator, mortality)
75 | ```
76 |
77 | ## Making a regular plot
78 |
79 | ```{r, eval=FALSE}
80 | ggplot(compare_provinces, aes(`Cerebrovascular diseases (I60-I69)`,
81 | `Diabetes mellitus (E10-E14)`,
82 | size = total,
83 | label = province)) +
84 | geom_point(alpha = 0.7, color = "midnightblue") +
85 | geom_text(aes(size = 3e6), vjust = 2.5) +
86 | theme_minimal() +
87 | theme(legend.position="none")
88 | ```
89 |
90 | ## Making a regular plot
91 |
92 | ```{r, echo=FALSE, fig.width=4.5, fig.height=3}
93 | ggplot(compare_provinces, aes(`Cerebrovascular diseases (I60-I69)`,
94 | `Diabetes mellitus (E10-E14)`,
95 | size = total,
96 | label = province)) +
97 | geom_point(alpha = 0.7, color = "midnightblue") +
98 | geom_text(aes(size = 1.8e6), vjust = -1.5) +
99 | theme_minimal() +
100 | xlim(c(0.3, 0.7)) +
101 | ylim(c(0.3, 0.55)) +
102 | theme(legend.position="none")
103 | ```
104 |
105 | ## Making an input for R Markdown
106 |
107 | ```{r, eval = FALSE}
108 | selectInput(inputId = "x",
109 | label = "X-axis:",
110 | choices = colnames(compare_provinces)[3:20],
111 | selected = "Other forms of heart disease (I30-I52)")
112 |
113 | selectInput(inputId = "y",
114 | label = "Y-axis:",
115 | choices = colnames(compare_provinces)[3:20],
116 | selected = "Non-natural causes")
117 | ```
118 |
119 |
120 | ## What do we do with those strings now?
121 |
122 | - The type of most things you access like `input$x` is a string
123 | - If we didn't have any spaces or special characters, we could use `aes_string`
124 |
125 | ```{r, eval=FALSE}
126 | ggplot(compare_provinces, aes_string(x = input$x,
127 | y = input$y)) +
128 | geom_point()
129 | ```
130 |
131 | - But alas, we cannot
132 |
133 |
134 | ## What do we do with those strings now?
135 |
136 | - Instead, let's use a `reactive` expression
137 |
138 | ```{r, eval=FALSE}
139 | selected_df <- reactive({
140 | subset_df <- compare_provinces[, c(1:2,
141 | which(colnames(compare_provinces) == input$x),
142 | which(colnames(compare_provinces) == input$y))]
143 | colnames(subset_df) <- c("province", "total",
144 | "selected_x", "selected_y")
145 | subset_df
146 | })
147 | ```
148 |
149 | - A reactive expression uses input from the user and returns a value
150 | - A reactive expression updates every time the input changes
151 |
152 | ## What do we do with those strings now?
153 |
154 | - Instead, let's use a `reactive` expression.
155 |
156 | ```{r, eval=FALSE}
157 | selected_df <- reactive({
158 | subset_df <- compare_provinces[, c(1:2,
159 | which(colnames(compare_provinces) == input$x),
160 | which(colnames(compare_provinces) == input$y))]
161 | colnames(subset_df) <- c("province", "total",
162 | "selected_x", "selected_y")
163 | subset_df
164 | })
165 | ```
166 |
167 | - The best uses for reactive expressions are when you want to avoid re-running unnecessary code
168 | - Only call a `reactive` expression from within another `reactive` function or a `render*` function
169 |
170 | ## Reactive expressions
171 |
172 | - Do not put side effects in reactive expressions
173 |
174 |
175 | 176 | 177 | ## Writing an output for R Markdown 178 | 179 | ```{r, eval=FALSE} 180 | renderPlot({ 181 | ggplot(selected_df(), aes(x = selected_x, 182 | y = selected_y, 183 | size = total, 184 | label = province)) + 185 | geom_point(alpha = 0.7, color = "midnightblue") + 186 | theme_minimal() + 187 | labs(x = input$x, y = input$y) + 188 | geom_text(aes(size = 1e7), vjust = 2) + 189 | theme_minimal(base_size = 14) + 190 | theme(legend.position="none") 191 | }) 192 | ``` 193 | 194 | # Is that too... squashed?! 195 | 196 | ## Writing an output for R Markdown 197 | 198 | ```{r, eval=FALSE} 199 | fillCol(height = 800, 200 | renderPlot({ 201 | ggplot(selected_df(), aes(x = selected_x, 202 | y = selected_y, 203 | size = total, 204 | label = province)) + 205 | geom_point(alpha = 0.7, color = "midnightblue") + 206 | theme_minimal() + 207 | labs(x = input$x, y = input$y) + 208 | geom_text(aes(size = 1e7), vjust = 2) + 209 | theme_minimal(base_size = 14) + 210 | theme(legend.position="none") 211 | }, height = 800) 212 | ) 213 | ``` 214 | 215 | ## Flexible layouts {.grid} 216 | 217 | - Using [fill layouts](http://shiny.rstudio.com/articles/gadget-ui.html#fillrowfillcol) can be helpful once you are putting Shiny outputs into R Markdown 218 | - Use `fillCol` (or maybe `fillRow` in some situations) to make your report look nice 219 | 220 | ## How to share interactive reports 221 | 222 | - R Markdown reports with `runtime: shiny` must be served by a Shiny server 223 | - Run it locally! Put in on [shinyapps.io](http://www.shinyapps.io/)! Build your own Shiny server! 224 | 225 | ## The flexdashboard package {.grid} 226 | 227 | - I make almost all of my Shiny apps now using the [flexdashboard](http://rmarkdown.rstudio.com/flexdashboard/) package 228 | - The ratio of how good they look to how hard I have to work is *just* right 229 | - Flexdashboard adapts itself for mobile devices 230 | - Flexdashboard does not have to include Shiny elements 231 | 232 | ## Check out a couple of examples {.grid} 233 | 234 | - [Women in the Stack Overflow Developer survey](https://juliasilge.shinyapps.io/survey2016/) 235 | - [Code here](https://github.com/juliasilge/stacksurveyapp) 236 | - [Emergency room visits](https://datassist.shinyapps.io/neiss_demographics/) 237 | - [Code here](https://github.com/juliasilge/neissapp) 238 | -------------------------------------------------------------------------------- /shiny_session_three.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "An Introduction to Shiny" 3 | author: "Julia Silge" 4 | output: 5 | rmdshower::shower_presentation: 6 | self_contained: false 7 | highlight: tango 8 | --- 9 | 10 | ```{r, echo = FALSE, warning = FALSE} 11 | library(knitr) 12 | knitr::opts_chunk$set(cache = TRUE, warning = FALSE, message = FALSE, dpi = 180) 13 | options(width=80) 14 | # to knit this document use devtools::install_github("mangothecat/rmdshower") 15 | ``` 16 | 17 | ## An Introduction to Shiny: Session Three 18 | 19 |.@jcheng on reactive vs observe #shinydevcon #rstats pic.twitter.com/g9hJTbZB1o
— Ajinkya Kale (@ajinkyakale) January 30, 2016
20 |
21 | ### Julia Silge (Stack Overflow)
22 |
23 | #### [\@juliasilge](https://twitter.com/juliasilge)
24 |
25 | #### [http://juliasilge.com/](http://juliasilge.com/)
26 |
27 | ## Let's install some packages
28 |
29 | ```{r, eval=FALSE}
30 | install.packages(c("shiny",
31 | "flexdashboard",
32 | "dplyr",
33 | "tidyr",
34 | "ggplot2",
35 | "leaflet"
36 | "devtools"))
37 |
38 | devtools::install_github("juliasilge/southafricastats")
39 | ```
40 |
41 | ## Flexdashboards are R Markdown documents {.grid}
42 |
43 | - Most of what we already talked about applies
44 | - It takes care of most annoying layout issues, leaving you with beautiful dashboards without headaches
45 | - Let's check out a [few examples](http://rmarkdown.rstudio.com/flexdashboard/examples.html)
46 |
47 | ## Let's talk about layouts
48 |
49 | - There are many ways to make a dashboard using this package
50 | - RStudio shows lots of [example layouts](http://rmarkdown.rstudio.com/flexdashboard/layouts.html) to get you started
51 | - Flexdashboard uses markdown headers to define different sections of the dashboard.
52 | - You can make dashboards with single or multiple pages, with tabbed columns/rows, with a sidebar, etc.
53 |
54 | # Let's make a multiple page dashboard using Shiny reactivity
55 |
56 | ## Multiple pages {.grid}
57 |
58 | - To make multiple pages in a flexdashboard, use a level 1 markdown header (`=======================`)
59 | - If you have A LOT of pages, you can make menus or use links
60 | - You can use icons in the navigation menu for multiple pages
61 | - One option is [Font Awesome icons](http://fontawesome.io/icons/)
62 |
63 | ## Creating a global sidebar
64 |
65 | - For our dashboard, we want the sidebar to apply across all pages
66 | - We should define the sidebar with a level 1 markdown header
67 |
68 | ```{r, eval = FALSE}
69 | Column {.sidebar}
70 | =====================================================================
71 |
72 | This app explores mortality data from the
73 | [South Africa Data Portal](http://southafrica.opendataforafrica.org/).
74 |
75 | Use the input below to select a cause of death to explore.
76 |
77 | ```
78 |
79 | ## Creating a global sidebar
80 |
81 | - Our dashboard is going to use Shiny for reactivity
82 | - Add `runtime: shiny` to the YAML
83 | - Add the Shiny input to a code chunk in the sidebar
84 |
85 | ```{r, eval = FALSE}
86 | selectInput(inputId = "indicator",
87 | label = "Cause of death:",
88 | choices = unique(mortality_zaf$indicator),
89 | selected = "Tuberculosis (A15-A19)")
90 |
91 | ```
92 |
93 | ## Making our first page
94 |
95 | - Let's make a leaflet map of the selected cause of mortality
96 | - We need the mortality rate `spread` in a new data frame
97 |
98 | ```{r, eval=FALSE}
99 | totals <- population_zaf %>%
100 | filter(year == 2013) %>%
101 | select(province, total)
102 |
103 | compare_provinces <- mortality_zaf %>%
104 | left_join(population_zaf) %>%
105 | filter(!is.na(total)) %>%
106 | mutate(mortality = deaths / total * 1e3) %>%
107 | group_by(province, indicator) %>%
108 | summarise(mortality = mean(mortality, na.rm = TRUE)) %>%
109 | ungroup %>%
110 | left_join(totals) %>%
111 | spread(indicator, mortality)
112 | ```
113 |
114 | ## Making our first page
115 |
116 | - Now let's set up our first page
117 |
118 | ```{r, eval = FALSE}
119 | Map {data-icon="fa-map-marker"}
120 | ====================================================================
121 |
122 | ### Which provinces have a higher mortality rate from the selected cause of death?
123 |
124 | ```
125 |
126 | ## Making our first page
127 |
128 | - Let's set up a `reactive` expression to select the mortality rate we are interested in
129 |
130 | ```{r, eval=FALSE}
131 | selected_df <- reactive({
132 | subset_df <- compare_provinces[, c(1,
133 | which(colnames(compare_provinces) == input$indicator))]
134 | colnames(subset_df) <- c("province", "indicator")
135 | population_zaf %>%
136 | filter(year == 2013) %>%
137 | left_join(subset_df, by = "province") %>%
138 | mutate(indicator = indicator / sum(indicator, na.rm = TRUE))
139 | })
140 | ```
141 |
142 | ## Making our first page
143 |
144 | - Now we're ready to make a leaflet map
145 | - We can use `renderLeaflet` in the same way we'd use `renderPlot` or another Shiny output
146 |
147 | ```{r, eval=FALSE}
148 | renderLeaflet({
149 | leaflet(selected_df()) %>%
150 | addProviderTiles("CartoDB.Positron") %>%
151 | addCircles(lng = ~longitude, lat = ~latitude, weight = 2.5,
152 | radius = ~sqrt(indicator) * 3e5 , popup = ~province,
153 | color = "magenta")
154 | })
155 | ```
156 |
157 | # Are we ready for another page?
158 |
159 | ## Setting up multiple pages {.grid}
160 |
161 | - We will use the same Shiny input from the global sidebar
162 | - Let's make a scatterplot comparing the selected mortality rate to the overall rate
163 |
164 | ## Making our second page
165 |
166 | ```{r, eval=FALSE}
167 | mortality_zaf <- mortality_zaf %>%
168 | filter(!(indicator %in% c("All causes")))
169 | ```
170 |
171 |
172 | ## Making our second page
173 |
174 | ```{r, eval=FALSE}
175 | Comparing provinces {data-icon="fa-list"}
176 | ====================================================================
177 |
178 | ### How does the selected mortality rate compare to the overall mortality rate?
179 |
180 | ```
181 |
182 | ## Making our second page
183 |
184 | - Time for another `reactive` expression!
185 | - If we didn't have spaces in our column names here, we could use `aes_string`
186 |
187 | ```{r, eval=FALSE}
188 | scatterplot_df <- reactive({
189 | subset_df <- compare_provinces[, c(1:2,
190 | which(colnames(compare_provinces) == "All causes"),
191 | which(colnames(compare_provinces) == input$indicator))]
192 | colnames(subset_df) <- c("province", "total", "selected_x", "selected_y")
193 | subset_df
194 | })
195 |
196 | ```
197 |
198 | ## Making our second page
199 |
200 | ```{r, eval=FALSE}
201 | renderPlot({
202 | ggplot(scatterplot_df(), aes(x = selected_x,
203 | y = selected_y,
204 | size = total,
205 | label = province)) +
206 | geom_point(alpha = 0.7, color = "magenta4") +
207 | theme_minimal() +
208 | labs(x = "All causes", y = input$indicator) +
209 | geom_text(aes(size = 1e7), vjust = 2) +
210 | scale_x_continuous(limits = c(7.7, 14.2)) +
211 | theme_minimal(base_size = 14) +
212 | theme(legend.position="none")
213 | })
214 | ```
215 |
216 | # Our dashboard is shaping up
217 |
218 | ## Making our third page
219 |
220 | ```{r, eval=FALSE}
221 | Changes in time {data-icon="fa-area-chart"}
222 | ====================================================================
223 |
224 | ### How have the number of deaths changed in time?
225 |
226 | ```
227 |
228 | ## Making our third page
229 |
230 | ```{r, eval=FALSE}
231 | renderPlot({
232 | mortality_zaf %>%
233 | filter(indicator == input$indicator) %>%
234 | ggplot(aes(year, deaths, color = province)) +
235 | geom_line(alpha = 0.8, size = 1.5) +
236 | theme_minimal(base_size = 18) +
237 | labs(x = NULL, y = "Number of deaths per year")
238 | })
239 | ```
240 |
241 | # Time for the last page
242 |
243 | ## Making our last page
244 |
245 | ```{r, eval=FALSE}
246 | Table {data-icon="fa-table"}
247 | ====================================================================
248 |
249 | ### Explore the data as reported by the South Africa Data Portal
250 |
251 | ```
252 |
253 | ## Making our last page
254 |
255 | ```{r, eval=FALSE}
256 | renderDataTable({
257 | mortality_zaf %>%
258 | filter(indicator == input$indicator)
259 | },
260 | options = list(pageLength = 10)
261 | )
262 | ```
263 |
264 | ## Options for jazzing up flexdashboards {.grid}
265 |
266 | - Explore the [themes that come in the package](http://rmarkdown.rstudio.com/flexdashboard/using.html#appearance)
267 | - Consider showing the code that made your dashboard with `source_code: embed`
268 | - Consider using plotly or other htmlwidgets
269 |
270 | # Time for you to experiment
271 |
--------------------------------------------------------------------------------
/shiny_session_one.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Julia Silge
60 |Julia Silge
60 |Julia Silge
60 |