class: center, middle, title-slide # Visualizing proportions ### Claus O. Wilke ### last updated: 2021-09-23 --- ## The archetypal visualization of proportions: pie chart .small-font.center[ ![](visualizing-proportions_files/figure-html/bundestag-pie-1.svg)<!-- --> Party composition of the 8th German Bundestag, 1976–1980 ] ??? Figure redrawn from [Claus O. Wilke. Fundamentals of Data Visualization. O'Reilly, 2019.](https://clauswilke.com/dataviz) --- ## Pie chart vs stacked bars vs side-by-side bars <br> .center[ ![](visualizing-proportions_files/figure-html/bundestag-various-1.svg)<!-- --> ] ??? Figures redrawn from [Claus O. Wilke. Fundamentals of Data Visualization. O'Reilly, 2019.](https://clauswilke.com/dataviz) --- ## Example where side-by-side bars are preferred .center[ ![](visualizing-proportions_files/figure-html/marketshare-side-by-side-1.svg)<!-- --> ] .xtiny-font.right[ Inspired by: https://en.wikipedia.org/wiki/File:Piecharts.svg ] ??? Figure redrawn from [Claus O. Wilke. Fundamentals of Data Visualization. O'Reilly, 2019.](https://clauswilke.com/dataviz) --- ## Example where side-by-side bars are preferred .center[ ![](visualizing-proportions_files/figure-html/marketshare-stacked-1.svg)<!-- --> ] .xtiny-font.right[ Inspired by: https://en.wikipedia.org/wiki/File:Piecharts.svg ] ??? Figure redrawn from [Claus O. Wilke. Fundamentals of Data Visualization. O'Reilly, 2019.](https://clauswilke.com/dataviz) --- ## Example where side-by-side bars are preferred .center[ ![](visualizing-proportions_files/figure-html/marketshare-pies-1.svg)<!-- --> ] .xtiny-font.right[ Inspired by: https://en.wikipedia.org/wiki/File:Piecharts.svg ] ??? Figure redrawn from [Claus O. Wilke. Fundamentals of Data Visualization. O'Reilly, 2019.](https://clauswilke.com/dataviz) --- ## Example where side-by-side bars are preferred .center[ ![](visualizing-proportions_files/figure-html/marketshare-side-by-side2-1.svg)<!-- --> ] .xtiny-font.right[ Inspired by: https://en.wikipedia.org/wiki/File:Piecharts.svg ] ??? Figure redrawn from [Claus O. Wilke. Fundamentals of Data Visualization. O'Reilly, 2019.](https://clauswilke.com/dataviz) --- ## Example where stacked bars are preferred .small-font.center[ ![](visualizing-proportions_files/figure-html/women-parliament-1.svg)<!-- --> Change in the gender composition of the Rwandan parliament from 1997 to 2016 ] ??? Figure redrawn from [Claus O. Wilke. Fundamentals of Data Visualization. O'Reilly, 2019.](https://clauswilke.com/dataviz) --- ## Pros and cons of different approaches .small-font.center[ | Pie chart | Stacked bars | Side-by-side bars :---------- | :-------: | :----------: | :---------------: Allows easy comparison of relative proportions | ✖ | ✖ | ✔ ] --- ## Pros and cons of different approaches .small-font.center[ | Pie chart | Stacked bars | Side-by-side bars :---------- | :-------: | :----------: | :---------------: Allows easy comparison of relative proportions | ✖ | ✖ | ✔ Shows data as proportions of a whole | ✔ | ✔ | ✖ ] --- ## Pros and cons of different approaches .small-font.center[ | Pie chart | Stacked bars | Side-by-side bars :---------- | :-------: | :----------: | :---------------: Allows easy comparison of relative proportions | ✖ | ✖ | ✔ Shows data as proportions of a whole | ✔ | ✔ | ✖ Emphasizes simple fractions (1/2, 1/3, ...) | ✔ | ✖ | ✖ ] --- ## Pros and cons of different approaches .small-font.center[ | Pie chart | Stacked bars | Side-by-side bars :---------- | :-------: | :----------: | :---------------: Allows easy comparison of relative proportions | ✖ | ✖ | ✔ Shows data as proportions of a whole | ✔ | ✔ | ✖ Emphasizes simple fractions (1/2, 1/3, ...) | ✔ | ✖ | ✖ Visually appealing for small datasets | ✔ | ✖ | ✔ ] --- ## Pros and cons of different approaches .small-font.center[ | Pie chart | Stacked bars | Side-by-side bars :---------- | :-------: | :----------: | :---------------: Allows easy comparison of relative proportions | ✖ | ✖ | ✔ Shows data as proportions of a whole | ✔ | ✔ | ✖ Emphasizes simple fractions (1/2, 1/3, ...) | ✔ | ✖ | ✖ Visually appealing for small datasets | ✔ | ✖ | ✔ Works well for a large number of subsets | ✖ | ✖ | ✔ ] --- ## Pros and cons of different approaches .small-font.center[ | Pie chart | Stacked bars | Side-by-side bars :---------- | :-------: | :----------: | :---------------: Allows easy comparison of relative proportions | ✖ | ✖ | ✔ Shows data as proportions of a whole | ✔ | ✔ | ✖ Emphasizes simple fractions (1/2, 1/3, ...) | ✔ | ✖ | ✖ Visually appealing for small datasets | ✔ | ✖ | ✔ Works well for a large number of subsets | ✖ | ✖ | ✔ Works well for time series and similar | ✖ | ✔ | ✖ ] -- No one visualization fits all scenarios! [//]: # "segment ends here" --- class: center middle ## Nested proportions: proportions of proportions --- ## Mosaic plots subdivide data along two dimensions .center[ <img src = "https://clauswilke.com/dataviz/nested_proportions_files/figure-html/bridges-mosaic-1.png", width = 75%></img> ] .absolute-bottom-right.tiny-font[ Dataset: Bridges in Pittsburgh by construction material and era of construction ] ??? Figure from [Claus O. Wilke. Fundamentals of Data Visualization. O'Reilly, 2019.](https://clauswilke.com/dataviz) --- ## Closely related to mosaic plot: Treemap .center[ <img src = "https://clauswilke.com/dataviz/nested_proportions_files/figure-html/bridges-treemap-1.png", width = 65%></img> ] ??? Figure from [Claus O. Wilke. Fundamentals of Data Visualization. O'Reilly, 2019.](https://clauswilke.com/dataviz) --- ## Treemaps work well for more complex cases .center.move-up-1em[ <img src = "https://clauswilke.com/dataviz/nested_proportions_files/figure-html/US-states-treemap-1.png", width = 80%></img> ] .absolute-bottom-right.tiny-font[ Dataset: Land surface area of US states ] ??? Figure from [Claus O. Wilke. Fundamentals of Data Visualization. O'Reilly, 2019.](https://clauswilke.com/dataviz) --- ## We can nest pie charts with clever coloring .center.move-up-1em[ <img src = "https://clauswilke.com/dataviz/nested_proportions_files/figure-html/bridges-nested-pie2-1.png", width = 70%></img> ] ??? Figure from [Claus O. Wilke. Fundamentals of Data Visualization. O'Reilly, 2019.](https://clauswilke.com/dataviz) --- ## Parallel sets can show many subdivisions at once .center[ <img src = "https://clauswilke.com/dataviz/nested_proportions_files/figure-html/bridges-parallel-sets1-1.png", width = 75%></img> ] ??? Figure from [Claus O. Wilke. Fundamentals of Data Visualization. O'Reilly, 2019.](https://clauswilke.com/dataviz) [//]: # "segment ends here" --- class: center middle ## Making pie charts with **ggplot2** --- ## Making pie charts with **ggplot2** We have three options: - `geom_bar()`/`geom_col()` with poolar coordinates Pros: simple Cons: hard to customize -- - `geom_arc_bar()` with `stat_pie()` Pros: relatively simple, some customization Cons: requires **ggforce** & some more complex code -- - `geom_arc_bar()` with manual computation Pros: maximum flexibility for customization Cons: requires **ggforce** & much more complex code --- ## Making pie charts with **ggplot2**: polar coords .pull-left.tiny-font[ ```r # the data bundestag <- tibble( party = c("CDU/CSU", "SPD", "FDP"), seats = c(243, 214, 39) ) bundestag ``` ``` # A tibble: 3 × 2 party seats <chr> <dbl> 1 CDU/CSU 243 2 SPD 214 3 FDP 39 ``` ] --- ## Making pie charts with **ggplot2**: polar coords .pull-left.tiny-font[ ```r # the data bundestag <- tibble( party = c("CDU/CSU", "SPD", "FDP"), seats = c(243, 214, 39) ) # make bar chart ggplot(bundestag) + aes(seats, "YY", fill = party) + geom_col() ``` ] .pull-right[ ![](visualizing-proportions_files/figure-html/bundestag-coord-polar1-out-1.svg)<!-- --> ] --- ## Making pie charts with **ggplot2**: polar coords .pull-left.tiny-font[ ```r # the data bundestag <- tibble( party = c("CDU/CSU", "SPD", "FDP"), seats = c(243, 214, 39) ) # make bar chart in polar coords ggplot(bundestag) + aes(seats, "YY", fill = party) + geom_col() + coord_polar() ``` ] .pull-right[ ![](visualizing-proportions_files/figure-html/bundestag-coord-polar2-out-1.svg)<!-- --> ] --- ## Making pie charts with **ggplot2**: polar coords .pull-left.tiny-font[ ```r # the data bundestag <- tibble( party = c("CDU/CSU", "SPD", "FDP"), seats = c(243, 214, 39) ) # make bar chart in polar coords ggplot(bundestag) + aes(seats, "YY", fill = party) + geom_col() + coord_polar() + scale_x_continuous( name = NULL, breaks = NULL ) + scale_y_discrete( name = NULL, breaks = NULL ) + ggtitle("German Bundestag 1976-1980") ``` ] .pull-right[ ![](visualizing-proportions_files/figure-html/bundestag-coord-polar3-out-1.svg)<!-- --> ] --- ## Making pie charts with **ggplot2**: **ggforce** stat pie .pull-left.tiny-font[ ```r library(ggforce) ggplot(bundestag) + aes( x0 = 0, y0 = 0, # position of pie center r0 = 0, r = 1, # inner and outer radius amount = seats, # size of pie slices fill = party ) + geom_arc_bar(stat = "pie") ``` ] .pull-right[ ![](visualizing-proportions_files/figure-html/bundestag-stat-pie1-out-1.svg)<!-- --> ] --- ## Making pie charts with **ggplot2**: **ggforce** stat pie .pull-left.tiny-font[ ```r library(ggforce) ggplot(bundestag) + aes( x0 = 0, y0 = 0, # position of pie center r0 = 0, r = 1, # inner and outer radius amount = seats, # size of pie slices fill = party ) + geom_arc_bar(stat = "pie") + coord_fixed() ``` ] .pull-right[ ![](visualizing-proportions_files/figure-html/bundestag-stat-pie2-out-1.svg)<!-- --> ] --- ## Making pie charts with **ggplot2**: **ggforce** stat pie .pull-left.tiny-font[ ```r library(ggforce) ggplot(bundestag) + aes( x0 = 0, y0 = 0, # position of pie center r0 = 0, r = 1, # inner and outer radius amount = seats, # size of pie slices fill = party ) + geom_arc_bar(stat = "pie") + coord_fixed( xlim = c(-1, 3), ylim = c(-1, 3) ) ``` ] .pull-right[ ![](visualizing-proportions_files/figure-html/bundestag-stat-pie3-out-1.svg)<!-- --> ] --- ## Making pie charts with **ggplot2**: **ggforce** stat pie .pull-left.tiny-font[ ```r library(ggforce) ggplot(bundestag) + aes( x0 = 1, y0 = 1, # position of pie center r0 = 0, r = 1, # inner and outer radius amount = seats, # size of pie slices fill = party ) + geom_arc_bar(stat = "pie") + coord_fixed( xlim = c(-1, 3), ylim = c(-1, 3) ) ``` ] .pull-right[ ![](visualizing-proportions_files/figure-html/bundestag-stat-pie4-out-1.svg)<!-- --> ] --- ## Making pie charts with **ggplot2**: **ggforce** stat pie .pull-left.tiny-font[ ```r library(ggforce) ggplot(bundestag) + aes( x0 = 1, y0 = 1, # position of pie center r0 = 1, r = 2, # inner and outer radius amount = seats, # size of pie slices fill = party ) + geom_arc_bar(stat = "pie") + coord_fixed( xlim = c(-1, 3), ylim = c(-1, 3) ) ``` ] .pull-right[ ![](visualizing-proportions_files/figure-html/bundestag-stat-pie5-out-1.svg)<!-- --> ] --- ## Making pie charts with **ggplot2**: **ggforce** manual comp. .tiny-font[ ```r # prepare pie data pie_data <- bundestag %>% arrange(seats) # sort so pie slices end up sorted pie_data ``` ``` # A tibble: 3 × 2 party seats <chr> <dbl> 1 FDP 39 2 SPD 214 3 CDU/CSU 243 ``` ] --- ## Making pie charts with **ggplot2**: **ggforce** manual comp. .tiny-font[ ```r # prepare pie data pie_data <- bundestag %>% arrange(seats) %>% # sort so pie slices end up sorted mutate( end_angle = 2*pi*cumsum(seats)/sum(seats) # ending angle for each pie slice ) pie_data ``` ``` # A tibble: 3 × 3 party seats end_angle <chr> <dbl> <dbl> 1 FDP 39 0.494 2 SPD 214 3.20 3 CDU/CSU 243 6.28 ``` ] --- ## Making pie charts with **ggplot2**: **ggforce** manual comp. .tiny-font[ ```r # prepare pie data pie_data <- bundestag %>% arrange(seats) %>% # sort so pie slices end up sorted mutate( end_angle = 2*pi*cumsum(seats)/sum(seats), # ending angle for each pie slice start_angle = lag(end_angle, default = 0) # starting angle for each pie slice ) pie_data ``` ``` # A tibble: 3 × 4 party seats end_angle start_angle <chr> <dbl> <dbl> <dbl> 1 FDP 39 0.494 0 2 SPD 214 3.20 0.494 3 CDU/CSU 243 6.28 3.20 ``` ] --- ## Making pie charts with **ggplot2**: **ggforce** manual comp. .tiny-font[ ```r # prepare pie data pie_data <- bundestag %>% arrange(seats) %>% # sort so pie slices end up sorted mutate( end_angle = 2*pi*cumsum(seats)/sum(seats), # ending angle for each pie slice start_angle = lag(end_angle, default = 0), # starting angle for each pie slice mid_angle = 0.5*(start_angle + end_angle), # middle of each pie slice, for text labels ) pie_data ``` ``` # A tibble: 3 × 5 party seats end_angle start_angle mid_angle <chr> <dbl> <dbl> <dbl> <dbl> 1 FDP 39 0.494 0 0.247 2 SPD 214 3.20 0.494 1.85 3 CDU/CSU 243 6.28 3.20 4.74 ``` ] --- ## Making pie charts with **ggplot2**: **ggforce** manual comp. .tiny-font[ ```r # prepare pie data pie_data <- bundestag %>% arrange(seats) %>% # sort so pie slices end up sorted mutate( end_angle = 2*pi*cumsum(seats)/sum(seats), # ending angle for each pie slice start_angle = lag(end_angle, default = 0), # starting angle for each pie slice mid_angle = 0.5*(start_angle + end_angle), # middle of each pie slice, for text labels # horizontal and vertical justifications for outer labels hjust = ifelse(mid_angle > pi, 1, 0), vjust = ifelse(mid_angle < pi/2 | mid_angle > 3*pi/2, 0, 1) ) pie_data ``` ``` # A tibble: 3 × 7 party seats end_angle start_angle mid_angle hjust vjust <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> 1 FDP 39 0.494 0 0.247 0 0 2 SPD 214 3.20 0.494 1.85 0 1 3 CDU/CSU 243 6.28 3.20 4.74 1 0 ``` ] --- ## Making pie charts with **ggplot2**: **ggforce** manual comp. .pull-left.tiny-font[ ```r ggplot(pie_data) + aes( x0 = 0, y0 = 0, r0 = 0, r = 1, start = start_angle, end = end_angle, fill = party ) + geom_arc_bar() + coord_fixed() ``` ] .pull-right[ ![](visualizing-proportions_files/figure-html/bundestag-arc-bar1-out-1.svg)<!-- --> ] --- ## Making pie charts with **ggplot2**: **ggforce** manual comp. .pull-left.tiny-font[ ```r ggplot(pie_data) + aes( x0 = 0, y0 = 0, r0 = 0, r = 1, start = start_angle, end = end_angle, fill = party ) + geom_arc_bar() + geom_text( # place amounts inside the pie aes( x = 0.6 * sin(mid_angle), y = 0.6 * cos(mid_angle), label = seats ) ) + coord_fixed() ``` ] .pull-right[ ![](visualizing-proportions_files/figure-html/bundestag-arc-bar2-out-1.svg)<!-- --> ] --- ## Making pie charts with **ggplot2**: **ggforce** manual comp. .pull-left.tiny-font[ ```r ggplot(pie_data) + aes( x0 = 0, y0 = 0, r0 = 0, r = 1, start = start_angle, end = end_angle, fill = party ) + geom_arc_bar() + geom_text( # place amounts inside the pie aes( x = 0.2 * sin(mid_angle), y = 0.2 * cos(mid_angle), label = seats ) ) + coord_fixed() ``` ] .pull-right[ ![](visualizing-proportions_files/figure-html/bundestag-arc-bar3-out-1.svg)<!-- --> ] --- ## Making pie charts with **ggplot2**: **ggforce** manual comp. .pull-left.tiny-font[ ```r ggplot(pie_data) + aes( x0 = 0, y0 = 0, r0 = 0, r = 1, start = start_angle, end = end_angle, fill = party ) + geom_arc_bar() + geom_text( # place amounts inside the pie aes( x = 0.8 * sin(mid_angle), y = 0.8 * cos(mid_angle), label = seats ) ) + coord_fixed() ``` ] .pull-right[ ![](visualizing-proportions_files/figure-html/bundestag-arc-bar4-out-1.svg)<!-- --> ] --- ## Making pie charts with **ggplot2**: **ggforce** manual comp. .pull-left.tiny-font[ ```r ggplot(pie_data) + aes( x0 = 0, y0 = 0, r0 = 0, r = 1, start = start_angle, end = end_angle, fill = party ) + geom_arc_bar() + geom_text( # place amounts inside the pie aes( x = 0.6 * sin(mid_angle), y = 0.6 * cos(mid_angle), label = seats ) ) + coord_fixed() ``` ] .pull-right[ ![](visualizing-proportions_files/figure-html/bundestag-arc-bar5-out-1.svg)<!-- --> ] --- ## Making pie charts with **ggplot2**: **ggforce** manual comp. .pull-left.xtiny-font[ ```r ggplot(pie_data) + aes( x0 = 0, y0 = 0, r0 = 0, r = 1, start = start_angle, end = end_angle, fill = party ) + geom_arc_bar() + geom_text( # place amounts inside the pie aes( x = 0.6 * sin(mid_angle), y = 0.6 * cos(mid_angle), label = seats ) ) + geom_text( # place party name outside the pie aes( x = 1.05 * sin(mid_angle), y = 1.05 * cos(mid_angle), label = party, hjust = hjust, vjust = vjust ) ) + coord_fixed() ``` ] .pull-right[ ![](visualizing-proportions_files/figure-html/bundestag-arc-bar6-out-1.svg)<!-- --> ] --- ## Making pie charts with **ggplot2**: **ggforce** manual comp. .pull-left.xtiny-font[ ```r ggplot(pie_data) + aes( x0 = 0, y0 = 0, r0 = 0, r = 1, start = start_angle, end = end_angle, fill = party ) + geom_arc_bar() + geom_text( # place amounts inside the pie aes( x = 0.6 * sin(mid_angle), y = 0.6 * cos(mid_angle), label = seats ) ) + geom_text( # place party name outside the pie aes( x = 1.05 * sin(mid_angle), y = 1.05 * cos(mid_angle), label = party, hjust = hjust, vjust = vjust ) ) + coord_fixed(xlim = c(-1.8, 1.3)) ``` ] .pull-right[ ![](visualizing-proportions_files/figure-html/bundestag-arc-bar7-out-1.svg)<!-- --> ] --- ## Making pie charts with **ggplot2**: **ggforce** manual comp. .pull-left.xtiny-font[ ```r ggplot(pie_data) + aes( x0 = 0, y0 = 0, r0 = 0.4, r = 1, start = start_angle, end = end_angle, fill = party ) + geom_arc_bar() + geom_text( # place amounts inside the pie aes( x = 0.7 * sin(mid_angle), y = 0.7 * cos(mid_angle), label = seats ) ) + geom_text( # place party name outside the pie aes( x = 1.05 * sin(mid_angle), y = 1.05 * cos(mid_angle), label = party, hjust = hjust, vjust = vjust ) ) + coord_fixed(xlim = c(-1.8, 1.3)) ``` ] .pull-right[ ![](visualizing-proportions_files/figure-html/bundestag-arc-bar8-out-1.svg)<!-- --> ] [//]: # "segment ends here" --- ## Further reading - Fundamentals of Data Visualization: [Chapter 10: Visualizing proportions](https://clauswilke.com/dataviz/visualizing-proportions.html) - Fundamentals of Data Visualization: [Chapter 11: Visualizing nested proportions](https://clauswilke.com/dataviz/nested-proportions.html) - **ggplot2** reference documentation: [`position_stack()`, `position_fill()`](https://ggplot2.tidyverse.org/reference/position_stack.html) - **ggplot2** reference documentation: [`position_dodge()`](https://ggplot2.tidyverse.org/reference/position_dodge.html) - **ggforce** reference documentation: [`geom_arc_bar()`](https://ggforce.data-imaginist.com/reference/geom_arc_bar.html)