├── 2-Interaktive-Diagramme-verknüpfen.Rmd
├── Interaktive_Kontrollelemente_ohne_Shiny.Rmd
├── LICENSE
├── README.md
├── Shiny-like interactivity_selectors.Rmd
├── WDI_mort-under-5.rds
└── link-2-interactive-plots_plotly_crosstalk.Rmd
/2-Interaktive-Diagramme-verknüpfen.Rmd:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Plotly: Zwei interaktive Diagramme verknüpfen"
3 | output:
4 | flexdashboard::flex_dashboard:
5 | orientation: columns
6 | vertical_layout: fill
7 | theme: spacelab
8 | source_code: embed
9 | fontsize: 16pt
10 | ---
11 |
12 | Daten: WDI
13 | ==========
14 |
15 | Wir nutzen Daten der **World Bank**: *World Development Indicators*, WDI.
16 |
17 | Der Datenzugriff erfolgt bequem mit dem **WDI-Paket**. Um die aktuelle Liste der verfügbaren Datenreihen abzurufen, aktualisieren wir die Liste, die im Paket enthalten ist, von der Webseite mit der *WDIcache()*-Funktion.
18 |
19 | ```{r setup}
20 |
21 | library(knitr)
22 | library(kableExtra)
23 | library(flexdashboard)
24 | library(WDI)
25 | library(tidyverse)
26 | library(plotly)
27 | library(crosstalk)
28 | library(ggthemes)
29 |
30 | knitr::opts_chunk$set(echo = FALSE)
31 |
32 | # cache <- WDIcache()
33 | #
34 | # data_org <- WDI(country = "all",
35 | # indicator = c(mortality_under_5 = "SH.DYN.MORT",
36 | # renewable_energy_consumption = "EG.FEC.RNEW.ZS"),
37 | # extra = TRUE,
38 | # cache = cache)
39 | #
40 | # saveRDS(data_org, "WDI_mort-under-5.rds")
41 |
42 | data_org <- readRDS("WDI_mort-under-5.rds")
43 |
44 | data <- data_org %>%
45 | filter(region != "Aggregates") %>%
46 | na.omit()
47 |
48 | data %>%
49 | select(country, year, mortality_under_5, region, capital) %>%
50 | head() %>%
51 | kbl() %>%
52 | kable_paper("hover", full_width = FALSE,
53 | lightable_options = "striped",
54 | font_size = 18)
55 |
56 | ```
57 |
58 | Heute interessieren wir uns vor allem für Kindersterblichkeit bis 5 Jahre (pro 1000 Geburten): *Mortality rate, under-5 (per 1,000 live births)*.
59 |
60 |
61 | ggplot2 und ggplotly
62 | ====================
63 |
64 | Column
65 | ------
66 |
67 | ```{r static-plot}
68 |
69 | p <- ggplot(data, aes(x = year, y = mortality_under_5, group = country)) +
70 | geom_line(color = "blue") +
71 | theme_economist_white() +
72 | labs(title = "Mortality by Year",
73 | x = "Year",
74 | y = "Mortality Rate under-5 per 1,000 live births)",
75 | caption = "Data Source: World Bank, World Development Indicators (WDI),
76 | obtained via the WDI R package, version 2.7.1")
77 |
78 | p
79 |
80 | ```
81 |
82 | Zu viele Linien / Länder!
83 |
84 | Column
85 | ------
86 |
87 | ```{r ggplotly}
88 |
89 | ggplotly(p)
90 |
91 | # ggplotly(p) %>%
92 | # layout(annotations = list(
93 | # x = 2016, y = 250, xanchor = 'right',
94 | # showarrow = FALSE,
95 | # # xshift = 0, yshift = 0, xref = 'paper', yref = 'paper',
96 | # text = "Data Source: World Bank, World Development Indicators (WDI),
97 | # obtained via the WDI R package, version 2.7.1"),
98 | # font = list(size = 11)
99 | # )
100 |
101 | ```
102 | Das interaktive Diagramm zu erstellen ist einfach mit *ggplotly()*, dem ein als Objekt gespeichertes statisches ggplot-Diagramm übergeben wird.
103 |
104 | Verbesserungsmöglichkeit: *facetting*, d. h. separate Unter-Diagramme z. B. nach Regionen.
105 |
106 | Heute wollen wir jedoch einen anderen Ansatz wählen.
107 |
108 |
109 | plotly und crosstalk: Regionen interaktiv auswählen
110 | ===================================================
111 |
112 | ```{r plotly-crosstalk}
113 |
114 | shared_data <- SharedData$new(data, key = ~region)
115 |
116 | p1 <- shared_data %>%
117 | plot_ly() %>%
118 | group_by(region) %>%
119 | summarise(avg_mort = round(mean(mortality_under_5, na.rm = TRUE), 1)) %>%
120 | add_markers(x = ~avg_mort, y = ~region, size = 2,
121 | hoverinfo = "text",
122 | text = ~paste("Region:", region,
123 | "
Average mortality rate, under-5 (per 1,000 live births):", avg_mort)) %>%
124 | layout(xaxis = list(title = "Average Mortality Rate,\nunder-5 (per 1,000 live births)"))
125 |
126 | p2 <- shared_data %>%
127 | plot_ly(x = ~year, y = ~mortality_under_5, ids = ~country,
128 | hoverinfo = "text",
129 | text = ~paste("Country:", country,
130 | "
Region:", region,
131 | "
Year:", year,
132 | "
Mortality rate, under-5 (per 1,000 live births):", mortality_under_5)) %>%
133 | group_by(country) %>%
134 | add_lines(color = I("darkgrey")) %>%
135 | layout(xaxis = list(title = "Year"), yaxis = list(title = "Mortality Rate, under-5 (per 1,000 live births"),
136 | title = list(text = "Mortality under-5 by Year"))
137 |
138 | cols <- toRGB(RColorBrewer::brewer.pal(3, "Dark2"))
139 |
140 | p <- subplot(p1, p2, shareX = FALSE, shareY = FALSE, titleX = TRUE) %>%
141 | hide_legend() %>%
142 | highlight(on = "plotly_click", off = "plotly_doubleclick",
143 | dynamic = TRUE, color = cols, selectize = TRUE)
144 |
145 | # Hack from https://stackoverflow.com/questions/36988379/adjust-axis-positions-ggplot2-facets
146 |
147 | p$x$layout$margin$l <- p$x$layout$margin$l + 90
148 | p$x$layout$margin$b <- p$x$layout$margin$b + 90
149 |
150 | p
151 |
152 | ```
153 |
154 | Anmerkungen
155 | ===========
156 |
157 | **crosstalk** ist eine leistungsfähige Ergänzung zu **plotly**: Man kann damit zwei Diagramme interaktiv verknüpfen.
158 |
159 | Beide Pakete wurden von **Carson Sievert** initiiert. *help(package = "plotly")* / *help(package = "crosstalk")*, um Mitstreiter abzurufen.
160 |
161 | Um zwei Diagramme zu verknüpfen, benötigen wir ein **Shared Data Object**. Es basiert auf dem **R6**-Paket und dem gleichnamigen System für objektorientiertes Programmieren in R.
162 |
163 | Die Diagramme werden mit der *plotly*-Syntax erstellt, die z. B. die Tilde ~ erfordert, um Variablen anzugeben, und mit der Pipe %>% statt, wie ggplot2, mit dem + Operator arbeitet.
--------------------------------------------------------------------------------
/Interaktive_Kontrollelemente_ohne_Shiny.Rmd:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Plotly: Kontroll-Elemente wie in Shiny Apps - ohne Shiny!"
3 | output:
4 | flexdashboard::flex_dashboard:
5 | orientation: columns
6 | vertical_layout: fill
7 | theme: spacelab
8 | source_code: embed
9 | fontsize: 16pt
10 | ---
11 |
12 | World Bank Data: WDI
13 | =======================
14 |
15 | Die Daten stammen von **The World Bank**: *World Development Indicators*, WDI.
16 |
17 | Bequem geladen mit dem **WDI-Paket**.
18 |
19 | ```{r setup}
20 |
21 | library(knitr)
22 | library(kableExtra)
23 | library(flexdashboard)
24 | library(WDI)
25 | library(tidyverse)
26 | library(plotly)
27 | library(crosstalk)
28 | library(ggthemes)
29 |
30 | knitr::opts_chunk$set(echo = FALSE)
31 |
32 | # cache <- WDIcache()
33 |
34 | # Noteworthy indicators, but with many missings:
35 | # renewable_energy_consumption = "EG.FEC.RNEW.ZS",
36 | # GDP_per_cap = "6.0.GDPpc_constant",
37 | # GDP_usd = "6.0.GDP_usd",
38 | # GNI_per_cap = "6.0.GNIpc"
39 | # obesity_pct = "HF.STA.OB18.ZS",
40 | # overweight_pct = "HF.STA.OW18.ZS"
41 |
42 | # data_org <- WDI(country = "all",
43 | # indicator = c(survival_15_60 = "HD.HCI.AMRT",
44 | # life_expectancy = "SP.DYN.LE00.IN",
45 | # air_pollution = "EN.ATM.PM25.MC.M3"),
46 | # extra = TRUE,
47 | # cache = cache)
48 |
49 | # saveRDS(data_org, "WDI_data.rds")
50 |
51 | data_org <- readRDS("WDI_data.rds")
52 |
53 | data <- data_org %>%
54 | filter(region != "Aggregates") %>%
55 | filter(!is.na(air_pollution) & !is.na(life_expectancy)) %>%
56 | filter(year == 2017)
57 |
58 | data %>%
59 | select(country, year, air_pollution, life_expectancy, region, capital) %>%
60 | head() %>%
61 | kbl() %>%
62 | kable_paper("hover", full_width = FALSE,
63 | lightable_options = "striped",
64 | font_size = 18)
65 |
66 | ```
67 |
68 | Heute geht es um **Luftverschmutzung** *(air pollution)*, definiert als durchschnittliche jährliche Menge in Mikrogramm pro Kubikmeter, der Menschen ausgesetzt sind, sowie **Lebenserwartung** *(life expectancy)* in Jahren zum Geburtszeitpunkt.
69 |
70 |
71 | ggplot2 und ggplotly
72 | ====================
73 |
74 | Column
75 | ------
76 |
77 | ```{r static-plot, fig.width = 9, fig.height = 6}
78 |
79 | p <- data %>%
80 | ggplot(aes(x = air_pollution, y = life_expectancy, group = country, color = region)) +
81 | geom_point(size = 3, alpha = 0.8) +
82 | theme_economist_white(base_family = "Verdana") +
83 | # scale_color_economist() +
84 | # scale_colour_viridis_d() +
85 | scale_color_brewer(palette = "Dark2") +
86 | labs(title = "Life Expectancy vs. Air Pollution 2017",
87 | x = "Air Pollution
88 | Mean Annual Exposure in micrograms per cubic meter",
89 | y = "Life Expectancy\nat birth in years",
90 | caption = "Data Source: World Bank, World Development Indicators (WDI),
91 | obtained via the WDI R package, version 2.7.1") +
92 | theme(legend.position = "right",
93 | legend.text = element_text(size = 14),
94 | legend.title = element_blank())
95 |
96 | p
97 |
98 | ```
99 |
100 |
101 | Column
102 | ------
103 |
104 | ```{r ggplotly, fig.width = 9, fig.height = 6}
105 |
106 | ggplotly(p)
107 |
108 | # ggplotly(p) %>%
109 | # layout(annotations = list(
110 | # x = 2016, y = 250, xanchor = 'right',
111 | # showarrow = FALSE,
112 | # # xshift = 0, yshift = 0, xref = 'paper', yref = 'paper',
113 | # text = "Data Source: World Bank, World Development Indicators (WDI),
114 | # obtained via the WDI R package, version 2.7.1"),
115 | # font = list(size = 11)
116 | # )
117 |
118 | ```
119 |
120 | Mögliche Verbesserung: Facets.
121 |
122 | Heute geht es jedoch um eine andere Möglichkeit ...
123 |
124 | plotly und crosstalk: Regionen und Länder interaktiv auswählen
125 | ==============================================================
126 |
127 | ```{r plotly-crosstalk}
128 |
129 | shared_data <- data %>%
130 | select(country, air_pollution, life_expectancy, region) %>%
131 | na.omit() %>%
132 | mutate(region = stringr::str_replace(region, "&", "and"),
133 | air_pollution = round(air_pollution, 1),
134 | life_expectancy = round(life_expectancy, 1)) %>%
135 | SharedData$new()
136 |
137 | p <- shared_data %>%
138 | plot_ly(x = ~air_pollution, y = ~life_expectancy, color = ~region,
139 | hoverinfo = "text",
140 | text = ~paste("Country:", country,
141 | "
Region:", region,
142 | "
Air Pollution:", air_pollution,
143 | "
Life Expectancy:", life_expectancy)) %>%
144 | group_by(region) %>%
145 | add_markers(size = 3) %>%
146 | layout(xaxis = list(title = "Air Pollution
Mean Annual Exposure in micrograms per cubic meter"),
147 | yaxis = list(title = "Life Expectancy
at birth in years"),
148 | legend = list(font = list(size = 16)))
149 |
150 | # Combining several selectors
151 |
152 | bscols(widths = c(3, 9),
153 | list(
154 | filter_checkbox(id = "region", label = "Region",
155 | sharedData = shared_data, group = ~region),
156 | filter_select(id = "country", label = "Country",
157 | sharedData = shared_data, group = ~country),
158 | filter_slider(id = "slider_ap", label = "Air Pollution",
159 | sharedData = shared_data, column = ~air_pollution),
160 | filter_slider(id = "slider_le", label = "Life Expectancy",
161 | sharedData = shared_data, column = ~life_expectancy)
162 | ),
163 | p)
164 |
165 | ```
166 |
167 | Anmerkungen
168 | ===========
169 |
170 | **crosstalk** ist eine leistungsfähige Ergänzung zu **plotly**: Man kann damit zwei Diagramme interaktiv verknüpfen.
171 |
172 | Beide Pakete wurden von **Carson Sievert** initiiert. *help(package = "plotly")* / *help(package = "crosstalk")*, um Mitstreiter abzurufen.
173 |
174 | Wir benötigen ein **Shared Data Object** für die Verknüpfung der Kontrollelemente mit dem Diagramm. Die Kernfunktionalität basiert auf dem **R6**-Paket und dem gleichnamigen System für objektorientiertes Programmieren in R.
175 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Wolf Riepl
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # exploring-plotly
2 | Exploring plotly functionality, e. g. how crosstalk enhances plotly
3 |
--------------------------------------------------------------------------------
/Shiny-like interactivity_selectors.Rmd:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Plotly: Shiny-like selectors without shiny"
3 | output:
4 | flexdashboard::flex_dashboard:
5 | orientation: columns
6 | vertical_layout: fill
7 | theme: spacelab
8 | source_code: embed
9 | fontsize: 16pt
10 | ---
11 |
12 | World Bank Data: WDI
13 | =======================
14 |
15 | We're using data from **The World Bank**: *World Development Indicators*, WDI.
16 |
17 | The data is accessed via the **WDI R package**. To make sure we get the newest list of available data series, we update the old list stored in the package with the current one from the website using the *WDIcache()* function.
18 |
19 | ```{r setup}
20 |
21 | library(knitr)
22 | library(kableExtra)
23 | library(flexdashboard)
24 | library(WDI)
25 | library(tidyverse)
26 | library(plotly)
27 | library(crosstalk)
28 | library(ggthemes)
29 |
30 | knitr::opts_chunk$set(echo = FALSE)
31 |
32 | # cache <- WDIcache()
33 |
34 | # Noteworthy indicators, but with many missings:
35 | # renewable_energy_consumption = "EG.FEC.RNEW.ZS",
36 | # GDP_per_cap = "6.0.GDPpc_constant",
37 | # GDP_usd = "6.0.GDP_usd",
38 | # GNI_per_cap = "6.0.GNIpc"
39 | # obesity_pct = "HF.STA.OB18.ZS",
40 | # overweight_pct = "HF.STA.OW18.ZS"
41 |
42 | # data_org <- WDI(country = "all",
43 | # indicator = c(survival_15_60 = "HD.HCI.AMRT",
44 | # life_expectancy = "SP.DYN.LE00.IN",
45 | # air_pollution = "EN.ATM.PM25.MC.M3"),
46 | # extra = TRUE,
47 | # cache = cache)
48 |
49 | # saveRDS(data_org, "WDI_data.rds")
50 |
51 | data_org <- readRDS("WDI_data.rds")
52 |
53 | data <- data_org %>%
54 | filter(region != "Aggregates") %>%
55 | filter(!is.na(air_pollution) & !is.na(life_expectancy)) %>%
56 | filter(year == 2017)
57 |
58 | data %>%
59 | select(country, year, air_pollution, life_expectancy, region, capital) %>%
60 | head() %>%
61 | kbl() %>%
62 | kable_paper("hover", full_width = FALSE,
63 | lightable_options = "striped",
64 | font_size = 18)
65 |
66 | ```
67 |
68 | The indicators we're interested in are **air pollution**, defined as *mean annual exposure (micrograms per cubic meter)*, and **life expectancy** at birth in years.
69 |
70 |
71 | ggplot2 and ggplotly
72 | ====================
73 |
74 | A quick start can be made using a static ggplot2 diagram. Until quite recently, I only used plotly via the *ggplotly()* function to turn a static plot into an interactive one with mouse-over-effects, like this:
75 |
76 | Column
77 | ------
78 |
79 | ```{r static-plot, fig.width = 9, fig.height = 6}
80 |
81 | p <- data %>%
82 | ggplot(aes(x = air_pollution, y = life_expectancy, group = country, color = region)) +
83 | geom_point(size = 3, alpha = 0.8) +
84 | theme_economist_white(base_family = "Verdana") +
85 | # scale_color_economist() +
86 | # scale_colour_viridis_d() +
87 | scale_color_brewer(palette = "Dark2") +
88 | labs(title = "Life Expectancy vs. Air Pollution 2017",
89 | x = "Air Pollution
90 | Mean Annual Exposure in micrograms per cubic meter",
91 | y = "Life Expectancy\nat birth in years",
92 | caption = "Data Source: World Bank, World Development Indicators (WDI),
93 | obtained via the WDI R package, version 2.7.1") +
94 | theme(legend.position = "right",
95 | legend.text = element_text(size = 14),
96 | legend.title = element_blank())
97 |
98 | p
99 |
100 | ```
101 |
102 |
103 | Column
104 | ------
105 |
106 | ```{r ggplotly, fig.width = 9, fig.height = 6}
107 |
108 | ggplotly(p)
109 |
110 | # ggplotly(p) %>%
111 | # layout(annotations = list(
112 | # x = 2016, y = 250, xanchor = 'right',
113 | # showarrow = FALSE,
114 | # # xshift = 0, yshift = 0, xref = 'paper', yref = 'paper',
115 | # text = "Data Source: World Bank, World Development Indicators (WDI),
116 | # obtained via the WDI R package, version 2.7.1"),
117 | # font = list(size = 11)
118 | # )
119 |
120 | ```
121 |
122 | We could use facetting to get a better overview of regions.
123 |
124 | However, today we prefer an interactive approach.
125 |
126 | plotly and crosstalk: Select Regions interactively
127 | ==================================================
128 |
129 | ```{r plotly-crosstalk}
130 |
131 | shared_data <- data %>%
132 | select(country, air_pollution, life_expectancy, region) %>%
133 | na.omit() %>%
134 | mutate(region = stringr::str_replace(region, "&", "and"),
135 | air_pollution = round(air_pollution, 1),
136 | life_expectancy = round(life_expectancy, 1)) %>%
137 | SharedData$new()
138 |
139 | p <- shared_data %>%
140 | plot_ly(x = ~air_pollution, y = ~life_expectancy, color = ~region,
141 | hoverinfo = "text",
142 | text = ~paste("Country:", country,
143 | "
Region:", region,
144 | "
Air Pollution:", air_pollution,
145 | "
Life Expectancy:", life_expectancy)) %>%
146 | group_by(region) %>%
147 | add_markers(size = 3) %>%
148 | layout(xaxis = list(title = "Air Pollution
Mean Annual Exposure in micrograms per cubic meter"),
149 | yaxis = list(title = "Life Expectancy
at birth in years"),
150 | legend = list(font = list(size = 16)))
151 |
152 | # Combining several selectors
153 |
154 | bscols(widths = c(3, 9),
155 | list(
156 | filter_checkbox(id = "region", label = "Region",
157 | sharedData = shared_data, group = ~region),
158 | filter_select(id = "country", label = "Country",
159 | sharedData = shared_data, group = ~country),
160 | filter_slider(id = "slider_ap", label = "Air Pollution",
161 | sharedData = shared_data, column = ~air_pollution),
162 | filter_slider(id = "slider_le", label = "Life Expectancy",
163 | sharedData = shared_data, column = ~life_expectancy)
164 | ),
165 | p)
166 |
167 | ```
168 |
169 | Notes
170 | =====
171 |
172 | The **crosstalk** package is a great companion to **plotly**, enabling us to make interactive selections without using shiny. Both plotly and crosstalk were created by **Carson Sievert**. See *help(package = "plotly")* / *help(package = "crosstalk")* to see further contributors.
173 |
174 | To set up this functionality, we need to set up a **Shared Data Object**. This is based on the R6 system for object oriented programming in R.
175 |
176 | Note that we apply the specific plotly syntax, which requires the tilde ~ to specify variables, and uses the pipe %>% rather than the + operator like ggplot2.
177 |
--------------------------------------------------------------------------------
/WDI_mort-under-5.rds:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fjodor/exploring-plotly/65ca46b9524b57430958319dc8016853f406233b/WDI_mort-under-5.rds
--------------------------------------------------------------------------------
/link-2-interactive-plots_plotly_crosstalk.Rmd:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Plotly: Linking two plots"
3 | output:
4 | flexdashboard::flex_dashboard:
5 | orientation: columns
6 | vertical_layout: fill
7 | theme: spacelab
8 | source_code: embed
9 | fontsize: 16pt
10 | ---
11 |
12 | Packages and Data: WDI
13 | =======================
14 |
15 | We're using data from **The World Bank**: *World Development Indicators*, WDI.
16 |
17 | The data is accessed via the **WDI R package**. To make sure we get the newest list of available data series, we update the old list stored in the package with the current one from the website using the *WDIcache()* function.
18 |
19 | ```{r setup}
20 |
21 | library(knitr)
22 | library(kableExtra)
23 | library(flexdashboard)
24 | library(WDI)
25 | library(tidyverse)
26 | library(plotly)
27 | library(crosstalk)
28 | library(ggthemes)
29 |
30 | knitr::opts_chunk$set(echo = FALSE)
31 |
32 | # cache <- WDIcache()
33 | #
34 | # data_org <- WDI(country = "all",
35 | # indicator = c(mortality_under_5 = "SH.DYN.MORT",
36 | # renewable_energy_consumption = "EG.FEC.RNEW.ZS"),
37 | # extra = TRUE,
38 | # cache = cache)
39 | #
40 | # saveRDS(data_org, "WDI_mort-under-5.rds")
41 |
42 | data_org <- readRDS("WDI_mort-under-5.rds")
43 |
44 | data <- data_org %>%
45 | filter(region != "Aggregates") %>%
46 | na.omit()
47 |
48 | data %>%
49 | select(country, year, mortality_under_5, region, capital) %>%
50 | head() %>%
51 | kbl() %>%
52 | kable_paper("hover", full_width = FALSE,
53 | lightable_options = "striped",
54 | font_size = 18)
55 |
56 | ```
57 |
58 | The indicator we're interested in is *Mortality rate, under-5 (per 1,000 live births)*.
59 |
60 |
61 | ggplot2 and ggplotly
62 | ====================
63 |
64 | A quick start can be made using a static ggplot2 diagram. Until quite recently, I only used plotly via the ggplotly() function to turn a static plot into an interactive one with mouse-over-effects, like this:
65 |
66 | Column
67 | ------
68 |
69 | ```{r static-plot}
70 |
71 | p <- ggplot(data, aes(x = year, y = mortality_under_5, group = country)) +
72 | geom_line(color = "blue") +
73 | theme_economist_white() +
74 | labs(title = "Mortality by Year",
75 | x = "Year",
76 | y = "Mortality Rate under-5 per 1,000 live births)",
77 | caption = "Data Source: World Bank, World Development Indicators (WDI),
78 | obtained via the WDI R package, version 2.7.1")
79 |
80 | p
81 |
82 | ```
83 |
84 | That's a lot of lines! Hard to get insight from such a plot.
85 |
86 | Column
87 | ------
88 |
89 | ```{r ggplotly}
90 |
91 | ggplotly(p)
92 |
93 | # ggplotly(p) %>%
94 | # layout(annotations = list(
95 | # x = 2016, y = 250, xanchor = 'right',
96 | # showarrow = FALSE,
97 | # # xshift = 0, yshift = 0, xref = 'paper', yref = 'paper',
98 | # text = "Data Source: World Bank, World Development Indicators (WDI),
99 | # obtained via the WDI R package, version 2.7.1"),
100 | # font = list(size = 11)
101 | # )
102 |
103 | ```
104 |
105 | This is very simple! Just assign the ggplot2 call to an object (p) and pass it to plotly's *ggplotly()* function.
106 |
107 | Making use of the mouse-over-effects, we can at least discover that the noticeable spikes relate to tragic events in Rwanda and Haiti respectively. However, it is still not very practical to get an overview of the data with so many countries in one plot.
108 |
109 | We could resort to facetting (e. g. by region), but today we'd like to take a different approach.
110 |
111 |
112 | plotly and crosstalk: Select Regions interactively
113 | ==================================================
114 |
115 | ```{r plotly-crosstalk}
116 |
117 | shared_data <- SharedData$new(data, key = ~region)
118 |
119 | p1 <- shared_data %>%
120 | plot_ly() %>%
121 | group_by(region) %>%
122 | summarise(avg_mort = round(mean(mortality_under_5, na.rm = TRUE), 1)) %>%
123 | add_markers(x = ~avg_mort, y = ~region, size = 2,
124 | hoverinfo = "text",
125 | text = ~paste("Region:", region,
126 | "
Average mortality rate, under-5 (per 1,000 live births):", avg_mort)) %>%
127 | layout(xaxis = list(title = "Average Mortality Rate,\nunder-5 (per 1,000 live births)"))
128 |
129 | p2 <- shared_data %>%
130 | plot_ly(x = ~year, y = ~mortality_under_5, ids = ~country,
131 | hoverinfo = "text",
132 | text = ~paste("Country:", country,
133 | "
Region:", region,
134 | "
Year:", year,
135 | "
Mortality rate, under-5 (per 1,000 live births):", mortality_under_5)) %>%
136 | group_by(country) %>%
137 | add_lines(color = I("darkgrey")) %>%
138 | layout(xaxis = list(title = "Year"), yaxis = list(title = "Mortality Rate, under-5 (per 1,000 live births"),
139 | title = list(text = "Mortality under-5 by Year"))
140 |
141 | cols <- toRGB(RColorBrewer::brewer.pal(3, "Dark2"))
142 |
143 | p <- subplot(p1, p2, shareX = FALSE, shareY = FALSE, titleX = TRUE) %>%
144 | hide_legend() %>%
145 | highlight(on = "plotly_click", off = "plotly_doubleclick",
146 | dynamic = TRUE, color = cols, selectize = TRUE)
147 |
148 | # Hack from https://stackoverflow.com/questions/36988379/adjust-axis-positions-ggplot2-facets
149 |
150 | p$x$layout$margin$l <- p$x$layout$margin$l + 90
151 | p$x$layout$margin$b <- p$x$layout$margin$b + 90
152 |
153 | p
154 |
155 | ```
156 |
157 | Notes
158 | =====
159 |
160 | The **crosstalk** package is a great companion to **plotly**, enabling us to link two charts interactively. Both packages were created by **Carson Sievert**. See *help(package = "plotly")* / *help(package = "crosstalk")* to see further contributors.
161 |
162 | To link charts, we need to set up a **Shared Data Object**. This is based on the R6 system for object oriented programming in R.
163 |
164 | Next, we create two plots. Note that now we employ the specific plotly syntax, which requires the tilde ~ to specify variables, and uses the pipe %>% rather than the + operator like ggplot2.
--------------------------------------------------------------------------------