Step 0: Use base ggplo2 to get the job done
library(tidyverse)
## ── Attaching packages ─────────────────────────────────────── tidyverse 1.3.0 ──
## ✓ ggplot2 3.3.5 ✓ purrr 0.3.4
## ✓ tibble 3.1.6 ✓ dplyr 1.0.8
## ✓ tidyr 1.0.2 ✓ stringr 1.4.0
## ✓ readr 1.3.1 ✓ forcats 0.5.0
## Warning: package 'ggplot2' was built under R version 3.6.2
## Warning: package 'tibble' was built under R version 3.6.2
## Warning: package 'purrr' was built under R version 3.6.2
## Warning: package 'dplyr' was built under R version 3.6.2
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## x dplyr::filter() masks stats::filter()
## x dplyr::lag() masks stats::lag()
library(gapminder)
gapminder %>%
filter(continent == "Americas") %>%
filter(year == 2002) %>%
select(country, pop) ->
prep
packcircles::circleProgressiveLayout(prep$pop,
sizetype = 'area') ->
pack
cbind(prep, pack) %>%
mutate(id = row_number())
## country pop x y radius id
## 1 Argentina 38331121 -3493.0180 0.0000 3493.0180 1
## 2 Bolivia 8445134 1639.5639 0.0000 1639.5639 2
## 3 Brazil 179914212 2732.7743 -9142.0260 7567.5936 3
## 4 Canada 31902268 1150.7522 4801.4069 3186.6608 4
## 5 Chile 15497046 5273.8171 1302.3806 2221.0049 5
## 6 Colombia 41008227 10562.3302 -1160.6508 3612.9384 6
## 7 Costa Rica 3834934 -4573.1172 -4469.2048 1104.8518 7
## 8 Cuba 11226999 -7453.2262 -3646.6547 1890.4139 8
## 9 Dominican Republic 8650322 -8636.6596 -299.9554 1659.3622 9
## 10 Ecuador 12921234 -7908.2513 3314.7888 2028.0425 10
## 11 El Salvador 6353681 -4769.2005 4746.5765 1422.1250 11
## 12 Guatemala 11178650 -3084.4567 7593.9564 1886.3390 12
## 13 Haiti 7607651 -133.6785 9366.9797 1556.1460 13
## 14 Honduras 6677328 2869.9023 9116.0827 1457.8956 14
## 15 Jamaica 2664659 4409.2334 7302.3944 920.9708 15
## 16 Mexico 102479927 10986.7220 8154.0495 5711.4249 16
## 17 Nicaragua 5146848 -5728.2786 -6555.5701 1279.9580 17
## 18 Panama 2990875 -7982.0775 -6463.5726 975.7177 18
## 19 Paraguay 5884491 -6893.5704 6556.3419 1368.6094 19
## 20 Peru 26769436 -6631.4420 10836.0023 2919.0711 20
## 21 Puerto Rico 3859606 -2614.0309 10551.5165 1108.4001 21
## 22 Trinidad and Tobago 1101832 -1083.9386 11293.7595 592.2196 22
## 23 United States 287675526 -18526.1513 -6598.5236 9569.2196 23
## 24 Uruguay 3363085 -11041.9619 913.3993 1034.6512 24
## 25 Venezuela 24287670 4129.4010 13162.9819 2780.4686 25
pack %>%
packcircles::circleLayoutVertices(npoints = 50) ->
circle_outlines
circle_outlines %>%
ggplot() +
aes(x = x, y = y) +
geom_polygon(colour = "black", alpha = 0.6) +
aes(group = id) +
aes(fill = factor(id)) +
geom_text(data = cbind(prep, pack),
aes(x, y, size = pop, label = country,
group = NULL, fill = NULL)) +
theme(legend.position = "none") +
coord_equal()
Step 1: computation
- define computation that ggplot2 should do for you, before plotting
- here it’s computing a variable with labels for each observation
- test that functionality!
# you won't use the scales argument, but ggplot will later
compute_panel_circle_pack <- function(data, scales){
data %>%
mutate(id = row_number()) ->
data1
if(is.null(data$area)){
data1 %>%
mutate(area = 1) ->
data1
}
data1 %>%
pull(area) %>%
packcircles::circleProgressiveLayout(
sizetype = 'area') %>%
packcircles::circleLayoutVertices(npoints = 300) %>%
left_join(data1) #%>%
# rename(group = id)
}
# step 1b test the computation function
gapminder::gapminder %>%
filter(continent == "Americas") %>%
filter(year == 2002) %>%
# input must have required aesthetic inputs as columns
rename(area = pop) %>%
compute_panel_circle_pack() %>%
head()
## Joining, by = "id"
## x y id country continent year lifeExp area gdpPercap
## 1 0.0000000 0.00000 1 Argentina Americas 2002 74.34 38331121 8797.641
## 2 -0.7660766 73.15225 1 Argentina Americas 2002 74.34 38331121 8797.641
## 3 -3.0639703 146.27241 1 Argentina Americas 2002 74.34 38331121 8797.641
## 4 -6.8926731 219.32842 1 Argentina Americas 2002 74.34 38331121 8797.641
## 5 -12.2505058 292.28821 1 Argentina Americas 2002 74.34 38331121 8797.641
## 6 -19.1351181 365.11980 1 Argentina Americas 2002 74.34 38331121 8797.641
# step 1b test the computation function
gapminder::gapminder %>%
filter(continent == "Americas") %>%
filter(year == 2002) %>%
# input must have required aesthetic inputs as columns
rename(area = pop) %>%
compute_panel_circle_pack() %>%
ggplot() +
aes(x = x, y = y, fill = country) +
geom_polygon()
## Joining, by = "id"
my_setup_data <- function(data, params){
if(data$group[1] == -1){
nrows <- nrow(data)
data$group <- seq_len(nrows)
}
data
}
Step 2: define ggproto
- what’s the naming convention for the proto object?
- which aesthetics are required as inputs?
- where does the function from above go?
StatCirclepack <- ggplot2::ggproto(`_class` = "StatCirclepack",
`_inherit` = ggplot2::Stat,
# setup_data = my_setup_data,
required_aes = c("id"),
compute_panel = compute_panel_circle_pack#,
# default_aes = aes(fill = after_stat(area))
)
Step 3: define geom_* function
geom_polygon_circlepack <- function(mapping = NULL, data = NULL,
position = "identity", na.rm = FALSE,
show.legend = NA,
inherit.aes = TRUE, ...) {
ggplot2::layer(
stat = StatCirclepack, # proto object from Step 2
geom = ggplot2::GeomPoint, # inherit other behavior
data = data,
mapping = mapping,
position = position,
show.legend = show.legend,
inherit.aes = inherit.aes,
params = list(na.rm = na.rm, ...)
)
}
Step 4: Enjoy! Use your function
gapminder::gapminder %>%
filter(year == 2002) %>%
ggplot() +
aes(id = country) +
geom_polygon_circlepack(alpha = .5, size = .002)
## Joining, by = "id"
last_plot() +
aes(color = continent)
## Joining, by = "id"
last_plot() +
aes(area = pop)
## Joining, by = "id"
last_plot() +
aes(color = continent) +
facet_wrap(facets = vars(continent))
## Joining, by = "id"
## Joining, by = "id"
## Joining, by = "id"
## Joining, by = "id"
## Joining, by = "id"