Using R to Web Scrape Wikipedia and Visualize the Results.
Introduction
It has been a while since I wrote a blog for this website. This blog inspired by this visualization build by Greta vega and Estefanía Casal and presented at the excellent Outlier.io presentation (video link here) I attended earlier this year and my desire to do some more automated web scraping. The above-mentioned plot was prepared in R, but clearly completed and post-processed in some sort of photo editing software. I wanted to make a similar visualization, but only using R. This did mean I had to use some quite new and experimental packages, so there is a good chance the syntax of some of these packages might have changed by the time you read this.
It is clear that for this blog I chose form over function, but that does not mean there are no interesting lessons to learn from the analysis. I used R to web scrape information about Wikipedia entries of the 260 districts in Ghana. Currently, almost all districts have Wikipedia page, but some 37 still do not. Furthermore, the first Wikipedia pages for these districts were created back in 2006, while 3 districts only got their Wikipedia page in 2021. Finally, it is apparent that there is a wide variation in how active the Wikipedia pages of different districts are. This activeness is measured by the total number of words added to a page in a given year and on how many different edits were made in a single year.
Packages
These are the packages I use for this blog.
library(rvest)
library(httr)
library(tidyverse)
library(ggfittext)
library(ggplot2)
library(cowplot)
library(tidyverse)
library(colorspace)
library(ggtext)
library(showtext)
library(formattable)
library(lubridate)
library(glue)
library(patchwork)
library(kableExtra)
library(ggfittext)
Step 1: Scrape the data from Wikipedia
To get the data on when a Wikipedia was first created, how often certain Wikipedia pages were edited, and how long a Wikipedia page, I need to scrape that data from Wikipedia. Luckily, 1) there is a Wikipedia page with links to all the Wikipedia of different districts and 2) Wikipedia saves copies of all old versions of Wikipedia entries. This makes it possible to easily see how the content of a Wikipedia page used to look a couple of years ago.
First I set the page with links to pages of districts
url <- "https://en.wikipedia.org/wiki/Districts_of_Ghana"
webpage <- read_html(url)
Then I use a function to get links from a table. This code was taken from this Stackoverflow answer
html_table_href <- function (x, header = NA, trim = TRUE, fill = FALSE, dec = ".")
{
fx <- function (x, header = NA, trim = TRUE, fill = FALSE, dec = ".")
{
stopifnot(html_name(x) == "table")
rows <- html_nodes(x, "tr")
n <- length(rows)
cells <- lapply(rows, "html_nodes", xpath = ".//td|.//th")
ncols <- lapply(cells, html_attr, "colspan", default = "1")
ncols <- lapply(ncols, as.integer)
nrows <- lapply(cells, html_attr, "rowspan", default = "1")
nrows <- lapply(nrows, as.integer)
p <- unique(vapply(ncols, sum, integer(1)))
maxp <- max(p)
if (length(p) > 1 & maxp * n != sum(unlist(nrows)) & maxp *
n != sum(unlist(ncols))) {
if (!fill) {
stop("Table has inconsistent number of columns. ",
"Do you want fill = TRUE?", call. = FALSE)
}
}
values <- lapply(lapply(cells, html_node, "a"), html_attr, name = "href")
values[[1]] <- html_text(cells[[1]])
out <- matrix(NA_character_, nrow = n, ncol = maxp)
for (i in seq_len(n)) {
row <- values[[i]]
ncol <- ncols[[i]]
col <- 1
for (j in seq_len(length(ncol))) {
out[i, col:(col + ncol[j] - 1)] <- row[[j]]
col <- col + ncol[j]
}
}
for (i in seq_len(maxp)) {
for (j in seq_len(n)) {
rowspan <- nrows[[j]][i]
colspan <- ncols[[j]][i]
if (!is.na(rowspan) & (rowspan > 1)) {
if (!is.na(colspan) & (colspan > 1)) {
nrows[[j]] <- c(utils::head(nrows[[j]], i),
rep(rowspan, colspan - 1), utils::tail(nrows[[j]],
length(rowspan) - (i + 1)))
rowspan <- nrows[[j]][i]
}
for (k in seq_len(rowspan - 1)) {
l <- utils::head(out[j + k, ], i - 1)
r <- utils::tail(out[j + k, ], maxp - i + 1)
out[j + k, ] <- utils::head(c(l, out[j, i],
r), maxp)
}
}
}
}
if (is.na(header)) {
header <- all(html_name(cells[[1]]) == "th")
}
if (header) {
col_names <- out[1, , drop = FALSE]
out <- out[-1, , drop = FALSE]
}
else {
col_names <- paste0("X", seq_len(ncol(out)))
}
df <- lapply(seq_len(maxp), function(i) {
utils::type.convert(out[, i], as.is = TRUE, dec = dec)
})
names(df) <- col_names
class(df) <- "data.frame"
attr(df, "row.names") <- .set_row_names(length(df[[1]]))
if (length(unique(col_names)) < length(col_names)) {
warning("At least two columns have the same name")
}
df
}
lapply(x, fx, header = header, trim = trim, fill = fill,
dec = dec)
}
Now I can scrape the URLs to the Wikipedia pages of all the different districts and create a dataframe with the name of the district and a link to the edit history of that specific page.
districts_href <- webpage %>%
html_nodes("[class='wikitable sortable']") %>%
html_table_href(fill = TRUE) %>%
do.call(rbind, .) %>%
as_tibble() %>%
select(District_link = District)
districts <- webpage %>%
html_nodes("[class='wikitable sortable']") %>%
html_table(fill = TRUE) %>%
do.call(rbind, .) %>%
as_tibble() %>%
mutate(District = gsub("\\[[^][]*]", "", District)) %>%
bind_cols(districts_href) %>%
mutate(page_available = !grepl("redlink=1$", District_link))%>%
mutate(link_to_hist = paste0("https://en.wikipedia.org/w/index.php?title=",
gsub("/wiki/", "", District_link),
"&offset=&limit=5000&action=history"))
saveRDS(districts, "districts_in_Ghana.RDS")
districts %>%
select(District, District_link, link_to_hist)
District | District_link | link_to_hist |
---|---|---|
Asunafo North | /wiki/Asunafo_North_Municipal_District | https://en.wikipedia.org/w/index.php?title=Asunafo_North_Municipal_District&offset=&limit=5000&action=history |
Asunafo South | /wiki/Asunafo_South_District | https://en.wikipedia.org/w/index.php?title=Asunafo_South_District&offset=&limit=5000&action=history |
Asutifi North | /wiki/Asutifi_North_(district) | https://en.wikipedia.org/w/index.php?title=Asutifi_North_(district)&offset=&limit=5000&action=history |
Asutifi South | /wiki/Asutifi_South_(district) | https://en.wikipedia.org/w/index.php?title=Asutifi_South_(district)&offset=&limit=5000&action=history |
Tano North | /wiki/Tano_North_Municipal_District | https://en.wikipedia.org/w/index.php?title=Tano_North_Municipal_District&offset=&limit=5000&action=history |
Tano South | /wiki/Tano_South_Municipal_District | https://en.wikipedia.org/w/index.php?title=Tano_South_Municipal_District&offset=&limit=5000&action=history |
Adansi Asokwa | /wiki/Adansi_Asokwa_District | https://en.wikipedia.org/w/index.php?title=Adansi_Asokwa_District&offset=&limit=5000&action=history |
Adansi North | /wiki/Adansi_North_District | https://en.wikipedia.org/w/index.php?title=Adansi_North_District&offset=&limit=5000&action=history |
Adansi South | /wiki/Adansi_South_District | https://en.wikipedia.org/w/index.php?title=Adansi_South_District&offset=&limit=5000&action=history |
Afigya-Kwabre North | /wiki/Afigya_Kwabre_North_District | https://en.wikipedia.org/w/index.php?title=Afigya_Kwabre_North_District&offset=&limit=5000&action=history |
Afigya-Kwabre South | /wiki/Afigya_Kwabre_South_District | https://en.wikipedia.org/w/index.php?title=Afigya_Kwabre_South_District&offset=&limit=5000&action=history |
Ahafo-Ano North | /wiki/Ahafo_Ano_North_Municipal_District | https://en.wikipedia.org/w/index.php?title=Ahafo_Ano_North_Municipal_District&offset=&limit=5000&action=history |
Ahafo-Ano South East | /wiki/Ahafo_Ano_South_East_District | https://en.wikipedia.org/w/index.php?title=Ahafo_Ano_South_East_District&offset=&limit=5000&action=history |
Ahafo-Ano South West | /wiki/Ahafo_Ano_South_District | https://en.wikipedia.org/w/index.php?title=Ahafo_Ano_South_District&offset=&limit=5000&action=history |
Akrofuom | /wiki/Akrofuom_District | https://en.wikipedia.org/w/index.php?title=Akrofuom_District&offset=&limit=5000&action=history |
Amansie Central | /wiki/Amansie_Central_District | https://en.wikipedia.org/w/index.php?title=Amansie_Central_District&offset=&limit=5000&action=history |
Amansie West | /wiki/Amansie_West_District | https://en.wikipedia.org/w/index.php?title=Amansie_West_District&offset=&limit=5000&action=history |
Amansie South | /wiki/Amansie_South_District | https://en.wikipedia.org/w/index.php?title=Amansie_South_District&offset=&limit=5000&action=history |
Asante-Akim Central | /wiki/Asante_Akim_Central_Municipal_District | https://en.wikipedia.org/w/index.php?title=Asante_Akim_Central_Municipal_District&offset=&limit=5000&action=history |
Asante-Akim North | /wiki/Asante_Akim_North_District | https://en.wikipedia.org/w/index.php?title=Asante_Akim_North_District&offset=&limit=5000&action=history |
Asante-Akim South | /wiki/Asante_Akim_South_Municipal_District | https://en.wikipedia.org/w/index.php?title=Asante_Akim_South_Municipal_District&offset=&limit=5000&action=history |
Asokore-Mampong | /wiki/Asokore_Mampong_Municipal_District | https://en.wikipedia.org/w/index.php?title=Asokore_Mampong_Municipal_District&offset=&limit=5000&action=history |
Asokwa | /wiki/Asokwa_Municipal_District | https://en.wikipedia.org/w/index.php?title=Asokwa_Municipal_District&offset=&limit=5000&action=history |
Atwima-Kwanwoma | /wiki/Atwima_Kwanwoma_District | https://en.wikipedia.org/w/index.php?title=Atwima_Kwanwoma_District&offset=&limit=5000&action=history |
Atwima-Mponua | /wiki/Atwima_Mponua_District | https://en.wikipedia.org/w/index.php?title=Atwima_Mponua_District&offset=&limit=5000&action=history |
Atwima-Nwabiagya | /wiki/Atwima_Nwabiagya_Municipal_District | https://en.wikipedia.org/w/index.php?title=Atwima_Nwabiagya_Municipal_District&offset=&limit=5000&action=history |
Atwima-Nwabiagya North | /wiki/Atwima_Nwabiagya_North_District | https://en.wikipedia.org/w/index.php?title=Atwima_Nwabiagya_North_District&offset=&limit=5000&action=history |
Bekwai | /wiki/Bekwai_Municipal_Assembly | https://en.wikipedia.org/w/index.php?title=Bekwai_Municipal_Assembly&offset=&limit=5000&action=history |
Bosome Freho | /wiki/Bosome_Freho_District | https://en.wikipedia.org/w/index.php?title=Bosome_Freho_District&offset=&limit=5000&action=history |
Bosomtwe | /wiki/Bosomtwe_District | https://en.wikipedia.org/w/index.php?title=Bosomtwe_District&offset=&limit=5000&action=history |
Ejisu | /wiki/Ejisu_Municipal_District | https://en.wikipedia.org/w/index.php?title=Ejisu_Municipal_District&offset=&limit=5000&action=history |
Ejura/Sekyedumase | /wiki/Ejura/Sekyedumase_Municipal_District | https://en.wikipedia.org/w/index.php?title=Ejura/Sekyedumase_Municipal_District&offset=&limit=5000&action=history |
Juaben | /wiki/Juaben_Municipal_District | https://en.wikipedia.org/w/index.php?title=Juaben_Municipal_District&offset=&limit=5000&action=history |
Kumasi | /wiki/Kumasi_Metropolitan_Assembly | https://en.wikipedia.org/w/index.php?title=Kumasi_Metropolitan_Assembly&offset=&limit=5000&action=history |
Kwabre East | /wiki/Kwabre_East_Municipal_District | https://en.wikipedia.org/w/index.php?title=Kwabre_East_Municipal_District&offset=&limit=5000&action=history |
Kwadaso | /wiki/Kwadaso_Municipal_District | https://en.wikipedia.org/w/index.php?title=Kwadaso_Municipal_District&offset=&limit=5000&action=history |
Mampong | /wiki/Mampong_Municipal_District | https://en.wikipedia.org/w/index.php?title=Mampong_Municipal_District&offset=&limit=5000&action=history |
Obuasi East | /wiki/Obuasi_East_District | https://en.wikipedia.org/w/index.php?title=Obuasi_East_District&offset=&limit=5000&action=history |
Obuasi | /wiki/Obuasi_Municipal_District | https://en.wikipedia.org/w/index.php?title=Obuasi_Municipal_District&offset=&limit=5000&action=history |
Offinso | /wiki/Offinso_Municipal_District | https://en.wikipedia.org/w/index.php?title=Offinso_Municipal_District&offset=&limit=5000&action=history |
Offinso North | /wiki/Offinso_North_District | https://en.wikipedia.org/w/index.php?title=Offinso_North_District&offset=&limit=5000&action=history |
Oforikrom | /wiki/Oforikrom_Municipal_District | https://en.wikipedia.org/w/index.php?title=Oforikrom_Municipal_District&offset=&limit=5000&action=history |
Old Tafo | /wiki/Old_Tafo_Municipal_District | https://en.wikipedia.org/w/index.php?title=Old_Tafo_Municipal_District&offset=&limit=5000&action=history |
Sekyere Afram Plains | /wiki/Sekyere_Afram_Plains_District | https://en.wikipedia.org/w/index.php?title=Sekyere_Afram_Plains_District&offset=&limit=5000&action=history |
Sekyere Central | /wiki/Sekyere_Central_District | https://en.wikipedia.org/w/index.php?title=Sekyere_Central_District&offset=&limit=5000&action=history |
Sekyere East | /wiki/Sekyere_East_District | https://en.wikipedia.org/w/index.php?title=Sekyere_East_District&offset=&limit=5000&action=history |
Sekyere Kumawu | /wiki/Sekyere_Kumawu_District | https://en.wikipedia.org/w/index.php?title=Sekyere_Kumawu_District&offset=&limit=5000&action=history |
Sekyere South | /wiki/Sekyere_South_District | https://en.wikipedia.org/w/index.php?title=Sekyere_South_District&offset=&limit=5000&action=history |
Suame | /wiki/Suame_Municipal_District | https://en.wikipedia.org/w/index.php?title=Suame_Municipal_District&offset=&limit=5000&action=history |
Banda | /wiki/Banda_District,_Ghana | https://en.wikipedia.org/w/index.php?title=Banda_District,_Ghana&offset=&limit=5000&action=history |
Berekum East | /wiki/Berekum_East_Municipal_District | https://en.wikipedia.org/w/index.php?title=Berekum_East_Municipal_District&offset=&limit=5000&action=history |
Berekum West | /wiki/Berekum_West_District | https://en.wikipedia.org/w/index.php?title=Berekum_West_District&offset=&limit=5000&action=history |
Dormaa Central | /wiki/Dormaa_Central_Municipal_District | https://en.wikipedia.org/w/index.php?title=Dormaa_Central_Municipal_District&offset=&limit=5000&action=history |
Dormaa East | /wiki/Dormaa_East_District | https://en.wikipedia.org/w/index.php?title=Dormaa_East_District&offset=&limit=5000&action=history |
Dormaa West | /wiki/Dormaa_West_District | https://en.wikipedia.org/w/index.php?title=Dormaa_West_District&offset=&limit=5000&action=history |
Jaman North | /wiki/Jaman_North_District | https://en.wikipedia.org/w/index.php?title=Jaman_North_District&offset=&limit=5000&action=history |
Jaman South | /wiki/Jaman_South_Municipal_District | https://en.wikipedia.org/w/index.php?title=Jaman_South_Municipal_District&offset=&limit=5000&action=history |
Sunyani | /wiki/Sunyani_Municipal_District | https://en.wikipedia.org/w/index.php?title=Sunyani_Municipal_District&offset=&limit=5000&action=history |
Sunyani West | /wiki/Sunyani_West_District | https://en.wikipedia.org/w/index.php?title=Sunyani_West_District&offset=&limit=5000&action=history |
Tain | /wiki/Tain_District | https://en.wikipedia.org/w/index.php?title=Tain_District&offset=&limit=5000&action=history |
Wenchi | /wiki/Wenchi_Municipal_District | https://en.wikipedia.org/w/index.php?title=Wenchi_Municipal_District&offset=&limit=5000&action=history |
Atebubu-Amantin | /wiki/Atebubu-Amantin_Municipal_District | https://en.wikipedia.org/w/index.php?title=Atebubu-Amantin_Municipal_District&offset=&limit=5000&action=history |
Kintampo North | /wiki/Kintampo_North_Municipal_District | https://en.wikipedia.org/w/index.php?title=Kintampo_North_Municipal_District&offset=&limit=5000&action=history |
Kintampo South | /wiki/Kintampo_South_District | https://en.wikipedia.org/w/index.php?title=Kintampo_South_District&offset=&limit=5000&action=history |
Nkoranza North | /wiki/Nkoranza_North_District | https://en.wikipedia.org/w/index.php?title=Nkoranza_North_District&offset=&limit=5000&action=history |
Nkoranza South | /wiki/Nkoranza_South_Municipal_District | https://en.wikipedia.org/w/index.php?title=Nkoranza_South_Municipal_District&offset=&limit=5000&action=history |
Pru East | /wiki/Pru_East_District | https://en.wikipedia.org/w/index.php?title=Pru_East_District&offset=&limit=5000&action=history |
Pru West | /wiki/Pru_West_District | https://en.wikipedia.org/w/index.php?title=Pru_West_District&offset=&limit=5000&action=history |
Sene East | /wiki/Sene_East_District | https://en.wikipedia.org/w/index.php?title=Sene_East_District&offset=&limit=5000&action=history |
Sene West | /wiki/Sene_West_District | https://en.wikipedia.org/w/index.php?title=Sene_West_District&offset=&limit=5000&action=history |
Techiman | /wiki/Techiman_Municipal_District | https://en.wikipedia.org/w/index.php?title=Techiman_Municipal_District&offset=&limit=5000&action=history |
Techiman North | /wiki/Techiman_North_District | https://en.wikipedia.org/w/index.php?title=Techiman_North_District&offset=&limit=5000&action=history |
Abura/Asebu/Kwamankese | /wiki/Abura/Asebu/Kwamankese_District | https://en.wikipedia.org/w/index.php?title=Abura/Asebu/Kwamankese_District&offset=&limit=5000&action=history |
Agona East | /wiki/Agona_East_District | https://en.wikipedia.org/w/index.php?title=Agona_East_District&offset=&limit=5000&action=history |
Agona West Municipal | /wiki/Agona_West_Municipal_District | https://en.wikipedia.org/w/index.php?title=Agona_West_Municipal_District&offset=&limit=5000&action=history |
Ajumako/Enyan/Essiam | /wiki/Ajumako/Enyan/Essiam_District | https://en.wikipedia.org/w/index.php?title=Ajumako/Enyan/Essiam_District&offset=&limit=5000&action=history |
Asikuma Odoben Brakwa | /wiki/Asikuma/Odoben/Brakwa_District | https://en.wikipedia.org/w/index.php?title=Asikuma/Odoben/Brakwa_District&offset=&limit=5000&action=history |
Assin Central Municipal | /w/index.php?title=Assin_Central_Municipal&action=edit&redlink=1 | https://en.wikipedia.org/w/index.php?title=/w/index.php?title=Assin_Central_Municipal&action=edit&redlink=1&offset=&limit=5000&action=history |
Assin North | /wiki/Assin_North_District | https://en.wikipedia.org/w/index.php?title=Assin_North_District&offset=&limit=5000&action=history |
Assin South | /wiki/Assin_South_District | https://en.wikipedia.org/w/index.php?title=Assin_South_District&offset=&limit=5000&action=history |
Awutu Senya East | /wiki/Awutu_Senya_East_(municipal_district) | https://en.wikipedia.org/w/index.php?title=Awutu_Senya_East_(municipal_district)&offset=&limit=5000&action=history |
Awutu Senya West | /wiki/Awutu_Senya_West_(district) | https://en.wikipedia.org/w/index.php?title=Awutu_Senya_West_(district)&offset=&limit=5000&action=history |
Cape Coast Metropolitan | /wiki/Cape_Coast_Metropolitan_Assembly | https://en.wikipedia.org/w/index.php?title=Cape_Coast_Metropolitan_Assembly&offset=&limit=5000&action=history |
Effutu Municipal | /wiki/Effutu_Municipal_District | https://en.wikipedia.org/w/index.php?title=Effutu_Municipal_District&offset=&limit=5000&action=history |
Ekumfi | /wiki/Ekumfi_District | https://en.wikipedia.org/w/index.php?title=Ekumfi_District&offset=&limit=5000&action=history |
Gomoa East | /wiki/Gomoa_East_District | https://en.wikipedia.org/w/index.php?title=Gomoa_East_District&offset=&limit=5000&action=history |
Gomoa Central | /wiki/Gomoa_Central_District | https://en.wikipedia.org/w/index.php?title=Gomoa_Central_District&offset=&limit=5000&action=history |
Gomoa West | /wiki/Gomoa_West_District | https://en.wikipedia.org/w/index.php?title=Gomoa_West_District&offset=&limit=5000&action=history |
Komenda/Edina/Eguafo/Abirem Municipal | /wiki/Komenda/Edina/Eguafo/Abirem_Municipal_District | https://en.wikipedia.org/w/index.php?title=Komenda/Edina/Eguafo/Abirem_Municipal_District&offset=&limit=5000&action=history |
Mfantsiman Municipal | /wiki/Mfantsiman_Municipal_District | https://en.wikipedia.org/w/index.php?title=Mfantsiman_Municipal_District&offset=&limit=5000&action=history |
Twifo Atti Morkwa | /wiki/Twifo-Ati_Morkwa_(district) | https://en.wikipedia.org/w/index.php?title=Twifo-Ati_Morkwa_(district)&offset=&limit=5000&action=history |
Twifo/Heman/Lower Denkyira | /wiki/Twifo/Heman/Lower_Denkyira_District | https://en.wikipedia.org/w/index.php?title=Twifo/Heman/Lower_Denkyira_District&offset=&limit=5000&action=history |
Upper Denkyira East Municipal | /wiki/Upper_Denkyira_East_Municipal_District | https://en.wikipedia.org/w/index.php?title=Upper_Denkyira_East_Municipal_District&offset=&limit=5000&action=history |
Upper Denkyira West | /wiki/Upper_Denkyira_West_District | https://en.wikipedia.org/w/index.php?title=Upper_Denkyira_West_District&offset=&limit=5000&action=history |
Abuakwa North | /wiki/Abuakwa_North_Municipal_District | https://en.wikipedia.org/w/index.php?title=Abuakwa_North_Municipal_District&offset=&limit=5000&action=history |
Abuakwa South | /wiki/Abuakwa_South_Municipal_District | https://en.wikipedia.org/w/index.php?title=Abuakwa_South_Municipal_District&offset=&limit=5000&action=history |
Achiase | /wiki/Achiase_District | https://en.wikipedia.org/w/index.php?title=Achiase_District&offset=&limit=5000&action=history |
Akuapim North | /wiki/Akuapim_North_Municipal_District | https://en.wikipedia.org/w/index.php?title=Akuapim_North_Municipal_District&offset=&limit=5000&action=history |
Akuapim South | /wiki/Akuapim_South_District | https://en.wikipedia.org/w/index.php?title=Akuapim_South_District&offset=&limit=5000&action=history |
Akyemansa | /wiki/Akyemansa_District | https://en.wikipedia.org/w/index.php?title=Akyemansa_District&offset=&limit=5000&action=history |
Asene Manso Akroso | /wiki/Asene_Manso_Akroso_District | https://en.wikipedia.org/w/index.php?title=Asene_Manso_Akroso_District&offset=&limit=5000&action=history |
Asuogyaman | /wiki/Asuogyaman_District | https://en.wikipedia.org/w/index.php?title=Asuogyaman_District&offset=&limit=5000&action=history |
Atiwa East | /wiki/Atiwa_East_District | https://en.wikipedia.org/w/index.php?title=Atiwa_East_District&offset=&limit=5000&action=history |
Atiwa West | /wiki/Atiwa_West_District | https://en.wikipedia.org/w/index.php?title=Atiwa_West_District&offset=&limit=5000&action=history |
Ayensuano | /wiki/Ayensuano_District | https://en.wikipedia.org/w/index.php?title=Ayensuano_District&offset=&limit=5000&action=history |
Birim Central | /wiki/Birim_Central_Municipal_District | https://en.wikipedia.org/w/index.php?title=Birim_Central_Municipal_District&offset=&limit=5000&action=history |
Birim North | /wiki/Birim_North_District | https://en.wikipedia.org/w/index.php?title=Birim_North_District&offset=&limit=5000&action=history |
Birim South | /wiki/Birim_South_District | https://en.wikipedia.org/w/index.php?title=Birim_South_District&offset=&limit=5000&action=history |
Denkyembour | /wiki/Denkyembour_District | https://en.wikipedia.org/w/index.php?title=Denkyembour_District&offset=&limit=5000&action=history |
Fanteakwa North | /wiki/Fanteakwa_North_District | https://en.wikipedia.org/w/index.php?title=Fanteakwa_North_District&offset=&limit=5000&action=history |
Fanteakwa South | /wiki/Fanteakwa_South_District | https://en.wikipedia.org/w/index.php?title=Fanteakwa_South_District&offset=&limit=5000&action=history |
Kwaebibirem | /wiki/Kwaebibirem_Municipal_District | https://en.wikipedia.org/w/index.php?title=Kwaebibirem_Municipal_District&offset=&limit=5000&action=history |
Kwahu Afram Plains North | /wiki/Kwahu_Afram_Plains_North_District | https://en.wikipedia.org/w/index.php?title=Kwahu_Afram_Plains_North_District&offset=&limit=5000&action=history |
Kwahu Afram Plains South | /wiki/Kwahu_Afram_Plains_South_District | https://en.wikipedia.org/w/index.php?title=Kwahu_Afram_Plains_South_District&offset=&limit=5000&action=history |
Kwahu East | /wiki/Kwahu_East_District | https://en.wikipedia.org/w/index.php?title=Kwahu_East_District&offset=&limit=5000&action=history |
Kwahu South | /wiki/Kwahu_South_District | https://en.wikipedia.org/w/index.php?title=Kwahu_South_District&offset=&limit=5000&action=history |
Kwahu West | /wiki/Kwahu_West_Municipal_District | https://en.wikipedia.org/w/index.php?title=Kwahu_West_Municipal_District&offset=&limit=5000&action=history |
Lower Manya Krobo | /wiki/Lower_Manya_Krobo_Municipal_District | https://en.wikipedia.org/w/index.php?title=Lower_Manya_Krobo_Municipal_District&offset=&limit=5000&action=history |
New Juaben North | /wiki/New_Juaben_North_Municipal_Assembly | https://en.wikipedia.org/w/index.php?title=New_Juaben_North_Municipal_Assembly&offset=&limit=5000&action=history |
New Juaben South | /wiki/New_Juaben_South_Municipal_Assembly | https://en.wikipedia.org/w/index.php?title=New_Juaben_South_Municipal_Assembly&offset=&limit=5000&action=history |
Nsawam Adoagyire | /wiki/Nsawam_Adoagyire_Municipal_District | https://en.wikipedia.org/w/index.php?title=Nsawam_Adoagyire_Municipal_District&offset=&limit=5000&action=history |
Okere | /wiki/Okere_District | https://en.wikipedia.org/w/index.php?title=Okere_District&offset=&limit=5000&action=history |
Suhum | /wiki/Suhum_Municipal_District | https://en.wikipedia.org/w/index.php?title=Suhum_Municipal_District&offset=&limit=5000&action=history |
Upper Manya Krobo | /wiki/Upper_Manya_Krobo_District | https://en.wikipedia.org/w/index.php?title=Upper_Manya_Krobo_District&offset=&limit=5000&action=history |
Upper West Akim | /wiki/Upper_West_Akim_District | https://en.wikipedia.org/w/index.php?title=Upper_West_Akim_District&offset=&limit=5000&action=history |
West Akim | /wiki/West_Akim_Municipal_District | https://en.wikipedia.org/w/index.php?title=West_Akim_Municipal_District&offset=&limit=5000&action=history |
Yilo-Krobo | /wiki/Yilo_Krobo_Municipal_District | https://en.wikipedia.org/w/index.php?title=Yilo_Krobo_Municipal_District&offset=&limit=5000&action=history |
Ablekuma Central | /wiki/Ablekuma_Central_Municipal_District | https://en.wikipedia.org/w/index.php?title=Ablekuma_Central_Municipal_District&offset=&limit=5000&action=history |
Ablekuma North | /wiki/Ablekuma_North_Municipal_District | https://en.wikipedia.org/w/index.php?title=Ablekuma_North_Municipal_District&offset=&limit=5000&action=history |
Ablekuma West | /wiki/Ablekuma_West_Municipal_District | https://en.wikipedia.org/w/index.php?title=Ablekuma_West_Municipal_District&offset=&limit=5000&action=history |
Accra | /wiki/Accra_Metropolitan_District | https://en.wikipedia.org/w/index.php?title=Accra_Metropolitan_District&offset=&limit=5000&action=history |
Ada East | /wiki/Ada_East_District | https://en.wikipedia.org/w/index.php?title=Ada_East_District&offset=&limit=5000&action=history |
Ada West | /wiki/Ada_West_District | https://en.wikipedia.org/w/index.php?title=Ada_West_District&offset=&limit=5000&action=history |
Adenta | /wiki/Adenta_Municipal_District | https://en.wikipedia.org/w/index.php?title=Adenta_Municipal_District&offset=&limit=5000&action=history |
Ashaiman | /wiki/Ashaiman_Municipal_District | https://en.wikipedia.org/w/index.php?title=Ashaiman_Municipal_District&offset=&limit=5000&action=history |
Ayawaso Central | /wiki/Ayawaso_Central_Municipal_District | https://en.wikipedia.org/w/index.php?title=Ayawaso_Central_Municipal_District&offset=&limit=5000&action=history |
Ayawaso East | /wiki/Ayawaso_East_Municipal_District | https://en.wikipedia.org/w/index.php?title=Ayawaso_East_Municipal_District&offset=&limit=5000&action=history |
Ayawaso North | /wiki/Ayawaso_North_Municipal_District | https://en.wikipedia.org/w/index.php?title=Ayawaso_North_Municipal_District&offset=&limit=5000&action=history |
Ayawaso West | /wiki/Ayawaso_West_Municipal_District | https://en.wikipedia.org/w/index.php?title=Ayawaso_West_Municipal_District&offset=&limit=5000&action=history |
Ga Central | /wiki/Ga_Central_Municipal_District | https://en.wikipedia.org/w/index.php?title=Ga_Central_Municipal_District&offset=&limit=5000&action=history |
Ga East | /wiki/Ga_East_Municipal_District | https://en.wikipedia.org/w/index.php?title=Ga_East_Municipal_District&offset=&limit=5000&action=history |
Ga North | /wiki/Ga_North_Municipal_District | https://en.wikipedia.org/w/index.php?title=Ga_North_Municipal_District&offset=&limit=5000&action=history |
Ga South | /wiki/Ga_South_Municipal_District | https://en.wikipedia.org/w/index.php?title=Ga_South_Municipal_District&offset=&limit=5000&action=history |
Ga West | /wiki/Ga_West_Municipal_District | https://en.wikipedia.org/w/index.php?title=Ga_West_Municipal_District&offset=&limit=5000&action=history |
Korle-Klottey | /wiki/Korle_Klottey_Municipal_District | https://en.wikipedia.org/w/index.php?title=Korle_Klottey_Municipal_District&offset=&limit=5000&action=history |
Kpone-Katamanso | /wiki/Kpone_Katamanso_Municipal_District | https://en.wikipedia.org/w/index.php?title=Kpone_Katamanso_Municipal_District&offset=&limit=5000&action=history |
Krowor | /wiki/Krowor_Municipal_District | https://en.wikipedia.org/w/index.php?title=Krowor_Municipal_District&offset=&limit=5000&action=history |
La-Dade-Kotopon | /wiki/La_Dade_Kotopon_Municipal_District | https://en.wikipedia.org/w/index.php?title=La_Dade_Kotopon_Municipal_District&offset=&limit=5000&action=history |
La-Nkwantanang-Madina | /wiki/La_Nkwantanang_Madina_Municipal_District | https://en.wikipedia.org/w/index.php?title=La_Nkwantanang_Madina_Municipal_District&offset=&limit=5000&action=history |
Ledzokuku | /wiki/Ledzokuku_Municipal_District | https://en.wikipedia.org/w/index.php?title=Ledzokuku_Municipal_District&offset=&limit=5000&action=history |
Ningo-Prampram | /wiki/Ningo_Prampram_District | https://en.wikipedia.org/w/index.php?title=Ningo_Prampram_District&offset=&limit=5000&action=history |
Okaikwei North | /wiki/Okaikwei_North_Municipal_District | https://en.wikipedia.org/w/index.php?title=Okaikwei_North_Municipal_District&offset=&limit=5000&action=history |
Shai-Osudoku | /wiki/Shai_Osudoku_District | https://en.wikipedia.org/w/index.php?title=Shai_Osudoku_District&offset=&limit=5000&action=history |
Tema Metropolitan | /wiki/Tema_Metropolis_District | https://en.wikipedia.org/w/index.php?title=Tema_Metropolis_District&offset=&limit=5000&action=history |
Tema West | /wiki/Tema_West_Municipal_District | https://en.wikipedia.org/w/index.php?title=Tema_West_Municipal_District&offset=&limit=5000&action=history |
Weija-Gbawe | /w/index.php?title=Weija_Gbawe_Municipal_District&action=edit&redlink=1 | https://en.wikipedia.org/w/index.php?title=/w/index.php?title=Weija_Gbawe_Municipal_District&action=edit&redlink=1&offset=&limit=5000&action=history |
Gushegu Municipal | /wiki/Gushegu_District | https://en.wikipedia.org/w/index.php?title=Gushegu_District&offset=&limit=5000&action=history |
Karaga | /wiki/Karaga_District | https://en.wikipedia.org/w/index.php?title=Karaga_District&offset=&limit=5000&action=history |
Kpandai | /wiki/Kpandai_District | https://en.wikipedia.org/w/index.php?title=Kpandai_District&offset=&limit=5000&action=history |
Kumbungu | /wiki/Kumbungu_District | https://en.wikipedia.org/w/index.php?title=Kumbungu_District&offset=&limit=5000&action=history |
Mion | /wiki/Mion_District | https://en.wikipedia.org/w/index.php?title=Mion_District&offset=&limit=5000&action=history |
Nanton | /wiki/Nanton_District | https://en.wikipedia.org/w/index.php?title=Nanton_District&offset=&limit=5000&action=history |
Nanumba North Municipal | /w/index.php?title=Nanumba_North_Municipal&action=edit&redlink=1 | https://en.wikipedia.org/w/index.php?title=/w/index.php?title=Nanumba_North_Municipal&action=edit&redlink=1&offset=&limit=5000&action=history |
Nanumba South | /wiki/Nanumba_South_District | https://en.wikipedia.org/w/index.php?title=Nanumba_South_District&offset=&limit=5000&action=history |
Saboba | /wiki/Saboba_District | https://en.wikipedia.org/w/index.php?title=Saboba_District&offset=&limit=5000&action=history |
Sagnarigu Municipal | /wiki/Sagnarigu_Municipal_District | https://en.wikipedia.org/w/index.php?title=Sagnarigu_Municipal_District&offset=&limit=5000&action=history |
Savelugu Municipal | /wiki/Savelugu_Municipal_District | https://en.wikipedia.org/w/index.php?title=Savelugu_Municipal_District&offset=&limit=5000&action=history |
Tamale Metropolitan | /wiki/Tamale_Metropolitan_District | https://en.wikipedia.org/w/index.php?title=Tamale_Metropolitan_District&offset=&limit=5000&action=history |
Tatale Sanguli | /wiki/Tatale_Sangule_District | https://en.wikipedia.org/w/index.php?title=Tatale_Sangule_District&offset=&limit=5000&action=history |
Tolon | /wiki/Tolon_District | https://en.wikipedia.org/w/index.php?title=Tolon_District&offset=&limit=5000&action=history |
Yendi Municipal | /wiki/Yendi_Municipal_District | https://en.wikipedia.org/w/index.php?title=Yendi_Municipal_District&offset=&limit=5000&action=history |
Zabzugu | /wiki/Zabzugu_District | https://en.wikipedia.org/w/index.php?title=Zabzugu_District&offset=&limit=5000&action=history |
Bunkpurugu Nyankpanduri | /w/index.php?title=Bunkpurugu_Nyankpanduri_District&action=edit&redlink=1 | https://en.wikipedia.org/w/index.php?title=/w/index.php?title=Bunkpurugu_Nyankpanduri_District&action=edit&redlink=1&offset=&limit=5000&action=history |
Chereponi | /wiki/Chereponi_District | https://en.wikipedia.org/w/index.php?title=Chereponi_District&offset=&limit=5000&action=history |
East Mamprusi | /wiki/East_Mamprusi_Municipal_Assembly | https://en.wikipedia.org/w/index.php?title=East_Mamprusi_Municipal_Assembly&offset=&limit=5000&action=history |
Mamprugu Moagduri | /wiki/Mamprugu_Moagduri_District | https://en.wikipedia.org/w/index.php?title=Mamprugu_Moagduri_District&offset=&limit=5000&action=history |
West Mamprusi | /wiki/West_Mamprusi_District | https://en.wikipedia.org/w/index.php?title=West_Mamprusi_District&offset=&limit=5000&action=history |
Yunyoo-Nasuan | /w/index.php?title=Yunyoo-Nasuan_District&action=edit&redlink=1 | https://en.wikipedia.org/w/index.php?title=/w/index.php?title=Yunyoo-Nasuan_District&action=edit&redlink=1&offset=&limit=5000&action=history |
Biakoye | /wiki/Biakoye_District | https://en.wikipedia.org/w/index.php?title=Biakoye_District&offset=&limit=5000&action=history |
Jasikan | /wiki/Jasikan_District | https://en.wikipedia.org/w/index.php?title=Jasikan_District&offset=&limit=5000&action=history |
Kadjebi | /wiki/Kadjebi_District | https://en.wikipedia.org/w/index.php?title=Kadjebi_District&offset=&limit=5000&action=history |
Krachi East | /wiki/Krachi_East_District | https://en.wikipedia.org/w/index.php?title=Krachi_East_District&offset=&limit=5000&action=history |
Krachi Nchumuru | /wiki/Krachi_Nchumuru_(district) | https://en.wikipedia.org/w/index.php?title=Krachi_Nchumuru_(district)&offset=&limit=5000&action=history |
Krachi West | /wiki/Krachi_West_District | https://en.wikipedia.org/w/index.php?title=Krachi_West_District&offset=&limit=5000&action=history |
Nkwanta North | /wiki/Nkwanta_North_District | https://en.wikipedia.org/w/index.php?title=Nkwanta_North_District&offset=&limit=5000&action=history |
Nkwanta South | /wiki/Nkwanta_South_District | https://en.wikipedia.org/w/index.php?title=Nkwanta_South_District&offset=&limit=5000&action=history |
Bole | /wiki/Bole_District | https://en.wikipedia.org/w/index.php?title=Bole_District&offset=&limit=5000&action=history |
Central Gonja | /wiki/Central_Gonja_District | https://en.wikipedia.org/w/index.php?title=Central_Gonja_District&offset=&limit=5000&action=history |
East Gonja Municipal | /wiki/East_Gonja_Municipal_District | https://en.wikipedia.org/w/index.php?title=East_Gonja_Municipal_District&offset=&limit=5000&action=history |
North Gonja | /wiki/North_Gonja_(district) | https://en.wikipedia.org/w/index.php?title=North_Gonja_(district)&offset=&limit=5000&action=history |
North East Gonja | /wiki/North_East_Gonja_District | https://en.wikipedia.org/w/index.php?title=North_East_Gonja_District&offset=&limit=5000&action=history |
Sawla-Tuna-Kalba | /wiki/Sawla-Tuna-Kalba_District | https://en.wikipedia.org/w/index.php?title=Sawla-Tuna-Kalba_District&offset=&limit=5000&action=history |
West Gonja | /wiki/West_Gonja_District | https://en.wikipedia.org/w/index.php?title=West_Gonja_District&offset=&limit=5000&action=history |
Bawku Municipal | /wiki/Bawku_Municipal_District | https://en.wikipedia.org/w/index.php?title=Bawku_Municipal_District&offset=&limit=5000&action=history |
Bawku West | /wiki/Bawku_West_District | https://en.wikipedia.org/w/index.php?title=Bawku_West_District&offset=&limit=5000&action=history |
Binduri | /wiki/Binduri_(district) | https://en.wikipedia.org/w/index.php?title=Binduri_(district)&offset=&limit=5000&action=history |
Bolgatanga East | /wiki/Bolgatanga_East_District | https://en.wikipedia.org/w/index.php?title=Bolgatanga_East_District&offset=&limit=5000&action=history |
Bolgatanga Municipal | /wiki/Bolgatanga_Municipal_District | https://en.wikipedia.org/w/index.php?title=Bolgatanga_Municipal_District&offset=&limit=5000&action=history |
Bongo | /wiki/Bongo_District | https://en.wikipedia.org/w/index.php?title=Bongo_District&offset=&limit=5000&action=history |
Builsa North Municipal | /wiki/Builsa_North_District | https://en.wikipedia.org/w/index.php?title=Builsa_North_District&offset=&limit=5000&action=history |
Builsa South | /wiki/Builsa_South_(district) | https://en.wikipedia.org/w/index.php?title=Builsa_South_(district)&offset=&limit=5000&action=history |
Garu | /wiki/Garu_District | https://en.wikipedia.org/w/index.php?title=Garu_District&offset=&limit=5000&action=history |
Kassena Nankana Municipal | /wiki/Kassena_Nankana_East_District | https://en.wikipedia.org/w/index.php?title=Kassena_Nankana_East_District&offset=&limit=5000&action=history |
Kassena Nankana West | /wiki/Kassena_Nankana_West_District | https://en.wikipedia.org/w/index.php?title=Kassena_Nankana_West_District&offset=&limit=5000&action=history |
Nabdam | /wiki/Nabdam_(district) | https://en.wikipedia.org/w/index.php?title=Nabdam_(district)&offset=&limit=5000&action=history |
Pusiga | /wiki/Pusiga_(district) | https://en.wikipedia.org/w/index.php?title=Pusiga_(district)&offset=&limit=5000&action=history |
Talensi | /wiki/Talensi_(district) | https://en.wikipedia.org/w/index.php?title=Talensi_(district)&offset=&limit=5000&action=history |
Tempane | /wiki/Tempane_District | https://en.wikipedia.org/w/index.php?title=Tempane_District&offset=&limit=5000&action=history |
Daffiama Bussie Issa | /wiki/Daffiama_Bussie_Issa_(district) | https://en.wikipedia.org/w/index.php?title=Daffiama_Bussie_Issa_(district)&offset=&limit=5000&action=history |
Jirapa Municipal | /wiki/Jirapa_Municipal | https://en.wikipedia.org/w/index.php?title=Jirapa_Municipal&offset=&limit=5000&action=history |
Lambussie Karni | /wiki/Lambussie_Karni_District | https://en.wikipedia.org/w/index.php?title=Lambussie_Karni_District&offset=&limit=5000&action=history |
Lawra Municipal | /wiki/Lawra_District | https://en.wikipedia.org/w/index.php?title=Lawra_District&offset=&limit=5000&action=history |
Nadowli Kaleo | /wiki/Nadowli_District | https://en.wikipedia.org/w/index.php?title=Nadowli_District&offset=&limit=5000&action=history |
Nandom Municipal | /wiki/Nandom_(district) | https://en.wikipedia.org/w/index.php?title=Nandom_(district)&offset=&limit=5000&action=history |
Sissala East Municipal | /w/index.php?title=Sissala_East_Municipal&action=edit&redlink=1 | https://en.wikipedia.org/w/index.php?title=/w/index.php?title=Sissala_East_Municipal&action=edit&redlink=1&offset=&limit=5000&action=history |
Sissala West | /wiki/Sissala_West_District | https://en.wikipedia.org/w/index.php?title=Sissala_West_District&offset=&limit=5000&action=history |
Wa East | /wiki/Wa_East_District | https://en.wikipedia.org/w/index.php?title=Wa_East_District&offset=&limit=5000&action=history |
Wa Municipal | /wiki/Wa_Municipal_District | https://en.wikipedia.org/w/index.php?title=Wa_Municipal_District&offset=&limit=5000&action=history |
Wa West | /wiki/Wa_West_District | https://en.wikipedia.org/w/index.php?title=Wa_West_District&offset=&limit=5000&action=history |
Adaklu District | /wiki/Adaklu_District | https://en.wikipedia.org/w/index.php?title=Adaklu_District&offset=&limit=5000&action=history |
Afadzato South | /wiki/Afadzato_South_District | https://en.wikipedia.org/w/index.php?title=Afadzato_South_District&offset=&limit=5000&action=history |
Agotime Ziope | /wiki/Agotime_Ziope_District | https://en.wikipedia.org/w/index.php?title=Agotime_Ziope_District&offset=&limit=5000&action=history |
Akatsi North | /wiki/Akatsi_North_District | https://en.wikipedia.org/w/index.php?title=Akatsi_North_District&offset=&limit=5000&action=history |
Akatsi South | /wiki/Akatsi_South_District | https://en.wikipedia.org/w/index.php?title=Akatsi_South_District&offset=&limit=5000&action=history |
Anloga | /wiki/Anloga_District | https://en.wikipedia.org/w/index.php?title=Anloga_District&offset=&limit=5000&action=history |
Central Tongu | /wiki/Central_Tongu_District | https://en.wikipedia.org/w/index.php?title=Central_Tongu_District&offset=&limit=5000&action=history |
Ho Municipal | /wiki/Ho_Municipal | https://en.wikipedia.org/w/index.php?title=Ho_Municipal&offset=&limit=5000&action=history |
Ho West | /wiki/Ho_West_District | https://en.wikipedia.org/w/index.php?title=Ho_West_District&offset=&limit=5000&action=history |
Hohoe Municipal | /wiki/Hohoe_Municipal | https://en.wikipedia.org/w/index.php?title=Hohoe_Municipal&offset=&limit=5000&action=history |
Keta Municipal | /wiki/Keta_Municipal | https://en.wikipedia.org/w/index.php?title=Keta_Municipal&offset=&limit=5000&action=history |
Ketu North Municipal | /wiki/Ketu_North_Municipal_District | https://en.wikipedia.org/w/index.php?title=Ketu_North_Municipal_District&offset=&limit=5000&action=history |
Ketu South Municipal | /wiki/Ketu_South_Municipal_District | https://en.wikipedia.org/w/index.php?title=Ketu_South_Municipal_District&offset=&limit=5000&action=history |
Kpando Municipal | /wiki/Kpando_Municipal_District | https://en.wikipedia.org/w/index.php?title=Kpando_Municipal_District&offset=&limit=5000&action=history |
North Dayi | /wiki/North_Dayi_District | https://en.wikipedia.org/w/index.php?title=North_Dayi_District&offset=&limit=5000&action=history |
North Tongu | /wiki/North_Tongu_District | https://en.wikipedia.org/w/index.php?title=North_Tongu_District&offset=&limit=5000&action=history |
South Dayi | /wiki/South_Dayi_District | https://en.wikipedia.org/w/index.php?title=South_Dayi_District&offset=&limit=5000&action=history |
South Tongu | /wiki/South_Tongu_District | https://en.wikipedia.org/w/index.php?title=South_Tongu_District&offset=&limit=5000&action=history |
Ahanta West | /wiki/Ahanta_West_District | https://en.wikipedia.org/w/index.php?title=Ahanta_West_District&offset=&limit=5000&action=history |
Amenfi Central | /wiki/Wassa_Amenfi_Central_(district) | https://en.wikipedia.org/w/index.php?title=Wassa_Amenfi_Central_(district)&offset=&limit=5000&action=history |
Amenfi West | /wiki/Wasa_Amenfi_West_District | https://en.wikipedia.org/w/index.php?title=Wasa_Amenfi_West_District&offset=&limit=5000&action=history |
Effia Kwesimintsim Municipal | /w/index.php?title=Effia_Kwesimintsim_Municipal&action=edit&redlink=1 | https://en.wikipedia.org/w/index.php?title=/w/index.php?title=Effia_Kwesimintsim_Municipal&action=edit&redlink=1&offset=&limit=5000&action=history |
Ellembelle | /wiki/Ellembelle_District | https://en.wikipedia.org/w/index.php?title=Ellembelle_District&offset=&limit=5000&action=history |
Jomoro | /wiki/Jomoro_District | https://en.wikipedia.org/w/index.php?title=Jomoro_District&offset=&limit=5000&action=history |
Mpohor | /wiki/Mpohor_(district) | https://en.wikipedia.org/w/index.php?title=Mpohor_(district)&offset=&limit=5000&action=history |
Nzema East Municipal | /wiki/Nzema_East_Municipal_District | https://en.wikipedia.org/w/index.php?title=Nzema_East_Municipal_District&offset=&limit=5000&action=history |
Prestea-Huni Valley Municipal | /wiki/Prestea-Huni_Valley_District | https://en.wikipedia.org/w/index.php?title=Prestea-Huni_Valley_District&offset=&limit=5000&action=history |
Sekondi Takoradi Metropolitan | /wiki/Sekondi_Takoradi_Metropolitan_Assembly | https://en.wikipedia.org/w/index.php?title=Sekondi_Takoradi_Metropolitan_Assembly&offset=&limit=5000&action=history |
Shama | /wiki/Shama_District | https://en.wikipedia.org/w/index.php?title=Shama_District&offset=&limit=5000&action=history |
Tarkwa-Nsuaem Municipal | /wiki/Tarkwa-Nsuaem_Municipal_District | https://en.wikipedia.org/w/index.php?title=Tarkwa-Nsuaem_Municipal_District&offset=&limit=5000&action=history |
Wassa Amenfi East | /wiki/Wassa_Amenfi_East_District | https://en.wikipedia.org/w/index.php?title=Wassa_Amenfi_East_District&offset=&limit=5000&action=history |
Wassa East | /wiki/Wassa_East_District | https://en.wikipedia.org/w/index.php?title=Wassa_East_District&offset=&limit=5000&action=history |
Aowin | /wiki/Aowin/Suaman_District | https://en.wikipedia.org/w/index.php?title=Aowin/Suaman_District&offset=&limit=5000&action=history |
Bia East | /wiki/Bia_East_District | https://en.wikipedia.org/w/index.php?title=Bia_East_District&offset=&limit=5000&action=history |
Bia West | /wiki/Bia_West_District | https://en.wikipedia.org/w/index.php?title=Bia_West_District&offset=&limit=5000&action=history |
Bibiani Anhwiaso Bekwai | /wiki/Bibiani/Anhwiaso/Bekwai_District | https://en.wikipedia.org/w/index.php?title=Bibiani/Anhwiaso/Bekwai_District&offset=&limit=5000&action=history |
Bodi | /wiki/Bodi_(district) | https://en.wikipedia.org/w/index.php?title=Bodi_(district)&offset=&limit=5000&action=history |
Juaboso | /wiki/Juaboso_(district) | https://en.wikipedia.org/w/index.php?title=Juaboso_(district)&offset=&limit=5000&action=history |
Sefwi Akontombra | /wiki/Sefwi_Akontombra_District | https://en.wikipedia.org/w/index.php?title=Sefwi_Akontombra_District&offset=&limit=5000&action=history |
Sefwi-Wiawso Municipal | /wiki/Sefwi-Wiawso_Municipal_District | https://en.wikipedia.org/w/index.php?title=Sefwi-Wiawso_Municipal_District&offset=&limit=5000&action=history |
Suaman | /wiki/Suaman_(district) | https://en.wikipedia.org/w/index.php?title=Suaman_(district)&offset=&limit=5000&action=history |
With the links set up, I can now actually start the web scraping. I did run into some issues while trying to do so, but all could be fixed easily.
- Some of the districts are redirected to new pages. this was problematic in the web scraping For example, Tano South links to
https://en.wikipedia.org/wiki/Tano_South_District
, but if you go to that page, you are automatically redirected tohttps://en.wikipedia.org/wiki/Tano_South_Municipal_District
. However, if you go to the edits history ofhttps://en.wikipedia.org/wiki/Tano_South_District
, there is only one edit, which is the redirection to the new page. All the actually edit history is transferred to the Tano_South_Municipal_District page. Therefore I built in a little logical test. This tests whether the page name is, which is web scraped from the URL, is the same as the original page name. If they are the same, no problem, but if they are different a new page_name is created.
logical_redirect <- function(x) {
link_check <- read_html(paste0("https://en.wikipedia.org", x))
link_check %>%
html_nodes('head') %>%
html_text() %>%
as.character() %>%
stringr::str_extract_all('(?<=wgPageName).+(?=wgTitle)') %>%
gsub("[^-_/()a-zA-Z\\s]" , "" , . , perl = TRUE) %>%
paste0("/wiki/", .) == x
}
Now I loop over all the 260 districts and for every district loop over all the edits and record in which year they were made, and how long an article was after the edit. The speed of this loop is mostly limited by my internet speed and the timeouts on the web scraping of Wikipedia, so the fact that for loops might not be the most efficient coding here does not matter that much.
list_results <- list()
for (i in 1:nrow(districts)) {
if (districts$page_available[i]) {
if (logical_redirect(districts$District_link[i])) {
webpage_main <- read_html(districts$link_to_hist[i])
} else{
link_check <-
read_html(paste0("https://en.wikipedia.org", districts$District_link[i]))
new_link <- link_check %>%
html_nodes('head') %>%
html_text() %>%
as.character() %>%
stringr::str_extract_all('(?<=wgPageName).+(?=wgTitle)') %>%
# remove most, but not all special characters
gsub("[^-_/()a-zA-Z\\s]" , "" , . , perl = TRUE) %>%
paste0(
"https://en.wikipedia.org/w/index.php?title=",
.,
"&offset=&limit=5000&action=history"
)
# there is one rogue comma that needs to be added to this link, I fixed that this way, by manually overriding it
new_link <-
ifelse(
new_link == "https://en.wikipedia.org/w/index.php?title=Banda_District_Ghana&offset=&limit=5000&action=history",
"https://en.wikipedia.org/w/index.php?title=Banda_District,_Ghana&action=history",
new_link
)
webpage_main <- read_html(new_link)
}
table_with_hist <- tibble(
district = webpage_main %>%
html_nodes('[class="mw-changeslist-date"]') %>%
html_attr("title"),
ref_to_hist = webpage_main %>%
html_nodes('[class="mw-changeslist-date"]') %>%
html_attr("href"),
date = webpage_main %>%
html_nodes('[class="mw-changeslist-date"]') %>%
html_text() %>%
parse_date_time(
orders = "%H:%M, %d %B %Y",
locale = "UK",
tz = "GMT"
)
)
number_words <- c()
for (j in 1:nrow(table_with_hist)) {
# this allows for setting a time out
# (https://stackoverflow.com/questions/48722076/how-to-set-timeout-in-rvest)
tryCatch(
number_words[j] <-
GET(
paste0(
"https://en.wikipedia.org/",
table_with_hist$ref_to_hist[j]
),
timeout(1000)
) %>%
read_html %>%
#html_nodes('body') %>%
html_nodes('p') %>%
html_text() %>%
paste0(collapse = " ") %>%
stringr::str_replace_all("[\r\n]" , "") %>%
# remove the warning message
# to prevent it from being part of the word count
str_replace("This is an old revision.*the current revision.", "") %>%
str_replace(
"This is the current revision of this page.*link to this version.",
""
) %>%
stringi::stri_count_words(),
error = function(e) {
number_words[j] <<- "Timed out!"
}
)
print(glue(
"collected word count for {j} out of {nrow(table_with_hist)} pages"
))
}
table_with_hist$number_words <- unlist(number_words)
list_results[[i]] <- table_with_hist
} else{
list_results[[i]] <- tibble(
district = districts$District[i],
ref_to_hist = NA,
date = NA,
number_words = NA
)
}
# I save after every run
saveRDS(list_results, "list_results_wiki_entries.RDS")
print(glue(
"collected information for {i} out of {nrow(districts)} districts"
))
}
Data preparation
Now I can load in all the scraped data and process it to make it ready for the plotting
list_results <- readRDS( "list_results_wiki_entries.RDS")
districts <- readRDS("districts_in_Ghana.RDS")
results_df <- do.call(rbind, list_results)
Calculate for every district when it was first published
order_of_entry <- results_df %>%
group_by(district) %>%
summarise(first_date = min(date))
order_of_entry
district | first_date |
---|---|
Ablekuma Central | NA |
Ablekuma North | NA |
Ablekuma West | NA |
Abuakwa North Municipal | NA |
Abura/Asebu/Kwamankese District | 2006-02-20 16:26:00 |
Accra Metropolitan District | 2006-02-20 19:05:00 |
Achiase District | 2020-07-08 20:45:00 |
Ada East District | 2017-11-15 11:16:00 |
Ada West District | 2017-11-15 11:28:00 |
Adaklu District | 2013-05-12 20:09:00 |
Adansi Asokwa | NA |
Adansi North District | 2006-02-21 14:33:00 |
Adansi South District | 2006-02-21 14:41:00 |
Adenta Municipal District | 2011-04-25 14:28:00 |
Afadzato South District | 2015-06-14 12:06:00 |
Afigya Kwabre District | 2011-04-25 15:42:00 |
Afigya Kwabre North | NA |
Agona East District | 2011-04-25 14:51:00 |
Agona West Municipal District | 2011-04-25 21:03:00 |
Agotime Ziope District | 2018-04-28 16:08:00 |
Ahafo Ano North Municipal District | 2006-02-20 19:06:00 |
Ahafo Ano South District | 2006-02-20 19:06:00 |
Ahafo Ano South East District | NA |
Ahanta West District | 2006-02-20 19:09:00 |
Ajumako/Enyan/Essiam District | 2006-02-20 19:10:00 |
Akatsi North District | 2013-08-01 13:01:00 |
Akatsi South District | 2013-10-10 14:46:00 |
Akrofuom | NA |
Akuapim North Municipal District | 2006-02-20 19:12:00 |
Akuapim South Municipal District | 2006-02-20 19:12:00 |
Akyemansa District | 2011-04-25 14:39:00 |
Amansie Central District | 2006-02-21 14:43:00 |
Amansie South | NA |
Amansie West District | 2006-02-20 19:14:00 |
Anloga District | 2020-07-21 01:32:00 |
Aowin/Suaman District | 2006-02-20 19:14:00 |
Asante Akim Central Municipal District | 2018-03-10 13:58:00 |
Asante Akim North District | 2009-08-18 01:51:00 |
Asante Akim South Municipal District | 2006-02-20 19:15:00 |
Asene Manso Akroso | NA |
Ashaiman Municipal | 2011-04-25 14:30:00 |
Asikuma/Odoben/Brakwa District | 2006-02-20 19:16:00 |
Asokore Mampong (municipal district) | 2018-06-08 23:36:00 |
Asokwa Municipal | NA |
Assin Central Municipal | NA |
Assin North Municipal District | 2011-04-25 21:18:00 |
Assin South District | 2007-02-24 23:57:00 |
Asunafo North Municipal District | 2011-04-25 19:00:00 |
Asunafo South District | 2006-02-22 09:28:00 |
Asuogyaman District | 2006-02-20 19:17:00 |
Asutifi North (district) | 2018-06-08 23:36:00 |
Asutifi South (district) | 2018-06-08 23:36:00 |
Atebubu-Amantin District | 2006-02-20 19:18:00 |
Atiwa East District | 2019-01-29 18:05:00 |
Atiwa West District | 2019-02-15 18:10:00 |
Atwima Kwanwoma District | 2011-04-25 15:43:00 |
Atwima Mponua District | 2006-02-21 14:44:00 |
Atwima Nwabiagya Municipal District | 2006-02-21 15:08:00 |
Atwima Nwabiagya North | NA |
Awutu Senya East (municipal district) | 2018-06-08 23:36:00 |
Awutu Senya West (district) | 2018-06-08 23:36:00 |
Ayawaso Central Municipal District | 2020-12-31 22:30:00 |
Ayawaso East | NA |
Ayawaso North Municipal District | 2019-02-15 18:14:00 |
Ayawaso West | NA |
Ayensuano (district) | 2018-06-08 23:36:00 |
Banda District, Ghana | 2015-03-19 12:05:00 |
Bawku Municipal District | 2007-02-25 00:37:00 |
Bawku West District | 2007-02-25 00:37:00 |
Bekwai Municipal Assembly | 2006-02-20 19:13:00 |
Berekum East Municipal District | 2011-04-25 19:03:00 |
Berekum West District | 2020-12-30 02:07:00 |
Bia East District | 2014-05-03 09:39:00 |
Bia West District | 2014-05-01 11:34:00 |
Biakoye District | 2009-08-14 16:57:00 |
Bibiani/Anhwiaso/Bekwai District | 2007-02-25 00:50:00 |
Binduri (district) | 2018-06-08 23:36:00 |
Birim Central Municipal District | 2010-09-05 01:58:00 |
Birim North District | 2007-02-25 00:00:00 |
Birim South District | 2006-02-20 19:46:00 |
Bodi (district) | 2018-06-08 23:36:00 |
Bole District | 2006-02-07 03:29:00 |
Bolgatanga East District | 2020-02-03 20:26:00 |
Bolgatanga Municipal District | 2006-02-20 19:49:00 |
Bongo District | 2006-02-12 18:23:00 |
Bosome Freho District | 2011-04-25 15:43:00 |
Bosomtwe District | 2006-02-21 14:49:00 |
Builsa North District | 2006-02-20 19:49:00 |
Builsa South (district) | 2018-06-08 23:36:00 |
Bunkpurugu Nyankpanduri | NA |
Cape Coast Metropolitan Assembly | 2011-04-25 21:07:00 |
Central Gonja District | 2007-02-25 00:31:00 |
Central Tongu District | 2018-03-02 11:28:00 |
Chereponi District | 2011-04-25 15:11:00 |
Daffiama Bussie Issa (district) | 2018-06-08 23:36:00 |
Denkyembour | 2018-06-08 23:36:00 |
Dormaa Central Municipal | NA |
Dormaa East District | 2011-04-25 15:04:00 |
Dormaa West (district) | 2018-06-08 23:36:00 |
East Akim Municipal District | 2006-02-20 19:51:00 |
East Gonja Municipal District | 2006-02-20 19:51:00 |
East Mamprusi Municipal Assembly | 2006-02-20 19:52:00 |
Effia Kwesimintsim Municipal | NA |
Effutu Municipal District | 2011-04-25 21:10:00 |
Ejisu-Juaben Municipal District | 2006-02-20 19:52:00 |
Ejura Sekyedumase Municipal District | 2006-02-20 19:53:00 |
Ekumfi District | 2017-12-22 12:29:00 |
Ellembelle District | 2011-04-25 12:25:00 |
Fanteakwa District | 2006-02-20 19:53:00 |
Fanteakwa South | NA |
Ga Central Municipal District | 2013-10-17 12:51:00 |
Ga East Municipal District | 2011-04-25 20:53:00 |
Ga North Municipal District | 2019-02-15 18:16:00 |
Ga South Municipal District | 2011-04-25 14:32:00 |
Ga West Municipal District | 2011-04-25 20:55:00 |
Garu District | 2007-02-25 00:38:00 |
Gomoa Central | NA |
Gomoa East District | 2011-04-25 21:12:00 |
Gomoa West District | 2011-04-25 21:14:00 |
Gushegu District | 2007-02-25 00:31:00 |
Ho Municipal | 2006-02-20 20:46:00 |
Ho West District | 2018-04-28 16:22:00 |
Hohoe Municipal | 2006-02-20 20:47:00 |
Jaman North District | 2006-02-22 08:31:00 |
Jaman South Municipal District | 2006-02-22 08:31:00 |
Jasikan District | 2006-02-20 20:48:00 |
Jirapa Municipal | 2011-04-25 13:43:00 |
Jomoro District | 2006-02-20 20:50:00 |
Juaben Municipal | NA |
Juaboso (district) | 2018-06-08 23:36:00 |
Kadjebi District | 2006-02-20 20:52:00 |
Karaga District | 2007-02-25 00:32:00 |
Kassena Nankana East District | 2011-04-25 15:29:00 |
Kassena Nankana West District | 2011-04-25 15:25:00 |
Keta Municipal | 2006-02-20 20:54:00 |
Ketu North Municipal District | 2009-08-14 12:49:00 |
Ketu South Municipal District | 2014-04-27 18:34:00 |
Kintampo North Municipal District | 2011-04-25 19:06:00 |
Kintampo South District | 2006-02-22 08:54:00 |
Komenda/Edina/Eguafo/Abirem Municipal District | 2006-02-20 21:01:00 |
Korle Klottey | NA |
Kpandai District | 2011-04-25 15:33:00 |
Kpando Municipal District | 2006-02-20 21:02:00 |
Kpone Katamanso Municipal District | 2019-02-15 18:16:00 |
Krachi East Municipal District | 2006-09-29 13:55:00 |
Krachi Nchumuru (district) | 2018-06-08 23:36:00 |
Krachi West District | 2006-02-20 21:03:00 |
Krowor | NA |
Kumasi Metropolitan Assembly | 2006-02-20 21:05:00 |
Kumbungu District | 2015-04-10 15:37:00 |
Kwabre East Municipal District | 2021-01-01 19:41:00 |
Kwadaso Municipal | NA |
Kwaebibirem Municipal District | 2006-02-20 21:06:00 |
Kwahu Afram Plains North (district) | 2011-04-26 19:27:00 |
Kwahu Afram Plains South (district) | 2018-06-08 23:36:00 |
Kwahu East District | 2009-01-27 11:54:00 |
Kwahu South District | 2006-02-20 21:08:00 |
Kwahu West Municipal District | 2011-04-26 19:30:00 |
La Dade Kotopon Municipal District | 2017-11-03 18:26:00 |
La Nkwantanang Madina Municipal District | 2017-12-31 20:51:00 |
Lambussie Karni District | 2011-04-25 13:44:00 |
Lawra District | 2006-02-20 21:08:00 |
Ledzokuku | NA |
Lower Manya Krobo Municipal District | 2011-04-26 19:32:00 |
Mampong Municipal District | 2006-02-20 21:41:00 |
Mamprugu Moagduri District | 2015-04-10 21:27:00 |
Mfantsiman Municipal District | 2010-12-28 02:33:00 |
Mion District | 2015-04-10 21:14:00 |
Mpohor (district) | 2018-06-08 23:36:00 |
Nabdam (district) | 2018-06-08 23:36:00 |
Nadowli District | 2006-02-20 21:12:00 |
Nandom (district) | 2018-06-08 23:36:00 |
Nanton District | 2019-02-15 18:18:00 |
Nanumba North Municipal | NA |
Nanumba South District | 2007-02-25 00:32:00 |
New Juaben Municipal District | 2006-02-20 21:13:00 |
New Juaben North Municipal Assembly | 2020-01-11 14:52:00 |
Ningo Prampram District | 2017-12-31 20:28:00 |
Nkoranza North District | 2011-04-25 15:02:00 |
Nkoranza South Municipal District | 2011-04-25 19:07:00 |
Nkwanta North District | 2009-10-10 08:28:00 |
Nkwanta South Municipal District | 2006-02-20 21:18:00 |
North Dayi District | 2018-04-25 23:07:00 |
North East Gonja District | 2015-04-10 17:47:00 |
North Gonja (district) | 2018-06-08 23:36:00 |
North Tongu District | 2006-02-20 21:19:00 |
Nsawam Adoagyire (municipal district) | 2018-06-08 23:36:00 |
Nzema East Municipal District | 2011-04-25 12:49:00 |
Obuasi East | NA |
Obuasi Municipal District | 2006-02-21 14:52:00 |
Offinso Municipal District | 2006-02-20 21:22:00 |
Offinso North District | 2011-04-25 15:43:00 |
Oforikrom | NA |
Okaikwei North | NA |
Okere | NA |
Old Tafo | NA |
Prestea-Huni Valley District | 2011-04-25 12:56:00 |
Pru East District | 2021-01-11 13:58:00 |
Pru West District | 2021-01-10 01:51:00 |
Pusiga (district) | 2018-06-08 23:36:00 |
Saboba District | 2015-04-10 20:53:00 |
Sagnarigu District | 2015-04-10 15:15:00 |
Savelugu-Nanton District | 2006-02-20 21:25:00 |
Sawla-Tuna-Kalba District | 2007-02-25 00:32:00 |
Sefwi-Wiawso Municipal District | 2006-02-20 21:37:00 |
Sefwi Akontombra District | 2011-04-25 13:06:00 |
Sekondi Takoradi Metropolitan Assembly | 2011-08-11 09:49:00 |
Sekyere Afram Plains District | 2011-04-25 15:44:00 |
Sekyere Central District | 2011-04-25 15:43:00 |
Sekyere East District | 2006-02-20 21:38:00 |
Sekyere Kumawu (district) | 2018-06-08 23:36:00 |
Sekyere South District | 2006-02-20 19:06:00 |
Sene East (district) | 2018-06-08 23:36:00 |
Sene West (district) | 2018-06-08 23:36:00 |
Shai Osudoku District | 2015-02-14 15:58:00 |
Shama District | 2011-04-25 13:08:00 |
Sissala East Municipal | NA |
Sissala West District | 2007-02-25 00:44:00 |
South Dayi District | 2006-08-29 02:51:00 |
South Tongu District | 2006-02-20 21:48:00 |
Suaman (district) | 2018-06-08 23:36:00 |
Suame | NA |
Suhum Municipal | NA |
Sunyani Municipal District | 2012-06-15 07:50:00 |
Sunyani West District | 2011-04-25 14:56:00 |
Tain District | 2006-02-22 08:22:00 |
Talensi (district) | 2018-06-08 23:36:00 |
Tamale Metropolitan District | 2006-02-20 21:51:00 |
Tano North Municipal District | 2006-02-28 12:40:00 |
Tano South Municipal District | 2006-02-28 12:40:00 |
Tarkwa-Nsuaem Municipal District | 2011-04-25 09:12:00 |
Tatale Sangule District | 2015-04-10 18:18:00 |
Techiman Municipal District | 2006-02-20 21:51:00 |
Techiman North District | 2015-01-31 15:47:00 |
Tema Metropolitan District | 2006-02-20 21:52:00 |
Tema West | NA |
Tempane District | 2020-02-03 20:36:00 |
Twifo-Ati Morkwa (district) | 2018-06-08 23:36:00 |
Twifo/Heman/Lower Denkyira District | 2007-02-24 23:57:00 |
Upper Denkyira East Municipal District | 2011-04-25 21:16:00 |
Upper Denkyira West District | 2011-04-25 14:43:00 |
Upper Manya Krobo District | 2011-04-25 14:37:00 |
Upper West Akim (district) | 2018-06-08 23:36:00 |
Wa East District | 2007-02-25 00:44:00 |
Wa Municipal District | 2007-02-25 00:44:00 |
Wa West District | 2007-02-25 00:44:00 |
Wasa Amenfi East District | 2007-02-25 00:50:00 |
Wasa Amenfi West District | 2007-02-25 00:50:00 |
Wassa Amenfi Central (district) | 2018-06-08 23:36:00 |
Wassa East District | 2006-02-20 21:11:00 |
Weija Gbawe | NA |
Wenchi Municipal District | 2010-02-15 09:50:00 |
West Akim Municipal District | 2006-02-21 12:51:00 |
West Gonja Municipal District | 2006-02-21 12:51:00 |
West Mamprusi Municipal Assembly | 2006-02-21 12:52:00 |
Yendi Municipal District | 2011-04-26 19:33:00 |
Yilo Krobo Municipal District | 2006-02-21 12:53:00 |
Yunyoo-Nasuan | NA |
Zabzugu District | 2015-04-10 18:00:00 |
From this data, I can now calculate both the number of edits per year and the net number of words added in a year (number of words on the last date of the year a page was edited minus the number of words at the start of the year)
# calculate number of edits in a year
complete_df_1 <- results_df %>%
mutate(year_report = year(date)) %>%
group_by(district, year_report) %>%
summarise(n = n()) %>%
ungroup() %>%
complete(district, nesting(year_report)) %>%
filter(!is.na(year_report))
## `summarise()` has grouped output by 'district'. You can override using the `.groups` argument.
# calculate number of words added in a year
complete_df_2 <- results_df %>%
mutate(year_report = year(date)) %>%
group_by(district, year_report) %>%
summarise(last_entry = number_words[which.max(date)]) %>%
group_by(district) %>%
arrange(district, year_report) %>%
mutate(net_words_added = last_entry - lag(last_entry, 1)) %>%
ungroup() %>%
mutate(net_words_added = ifelse(is.na(net_words_added),
last_entry,
net_words_added)) %>%
complete(district, nesting(year_report))
## `summarise()` has grouped output by 'district', 'year_report'. You can override using the `.groups` argument.
# combine both statistics.
complete_df <- left_join(complete_df_1, complete_df_2,
by = c("district", "year_report")) %>%
left_join(order_of_entry, by = "district") %>%
mutate(district = as.factor(district))%>%
mutate(district = fct_reorder(district, first_date))
Now that the data is ready, I can prepare some parameters and set some custom functions that are needed to create the final plot. The fact that I wanted to use a circular type of heatmap, complicated considerably
- Because the plot uses a polar coordinate system, drawing slightly curved and straight annotations lines is not possible with base
ggplot
. A solution to this was provided by Stackoverflow. - I wanted to curve some text ‘around’ the heatmap. To do this I used the
ggfittext
package. - To add the Wikipedia logo and to add the legend I will create separately to the plot, I used the
patchwork
package. - To create this bivariate legend (showing both the number of edits and words added per year), I used the
bivariate
package and particularly some code I sourced from https://github.com/R4IDSR/epichecks, that was needed to extend the bivariate’s 3x3 matrix to a 5x5 matrix. - To add the year labels at the 12 o’clock position of the plot, I needed to add some white space and make sure that the circular heatmap did not close on itself at that position.
- I wanted to make a distinction between data that was missing for a year (so a Wikipedia that does exist, but was simply not edited for a whole year) and districts for which no Wikipedia page existed (yet) in a given year. I created this distinction by overlapping the heatmap with another bar chart that has the exact same colour as the background, This way the plot cleanly merges into the background of the plot.
These are some plot wide parameter
# number of empty columns to be added for the years
n_white_gaps <- 5
# this is the plot I want to use
font_add_google(name = "Trirong")
showtext_auto()
plot_font <- "Trirong"
# This is the colors I am using
background_col <- "#fcfbe3"
col_arrows_and_lines <- "#8a7586"
These are combinations of year and districts for which no Wikipedia page was created at that time. As explained above, these are removed from the plot.
white_bars <- complete_df %>%
arrange(first_date) %>%
group_by(district) %>%
summarise(min = min(year(first_date))) %>%
mutate(min = replace_na(min, 2022)) %>%
ungroup()
These are the labels surrounding the plot. This code was inspired by the code of Greta vega and Estefanía Casal.
label_data <- complete_df %>%
select(district) %>%
distinct() %>%
# clean the names of districts a bit
mutate(label = gsub('District', "",district),
label = gsub('Municipal', "", label),
label = gsub('district', "", label),
label = gsub('municipal', "", label),
label = gsub("Assembly", "", label),
label = gsub('[()]', "", label),
label = trimws(label)) %>%
mutate(angle = 90 - 360 * (as.numeric(district)-0.5) / (n() + n_white_gaps)) %>%
mutate(hjust = ifelse(angle < -90, 1, 0)) %>%
mutate(angle = ifelse(angle < -90, angle+180, angle))
This is the function needed to draw straight lines in a polar coordinated plot. This code takes the geom_curve()
function from ggplot2
and alters this function so that it ignores whether a coordinate system is linear or not.
geom_curve_polar <- function(...) {
layer <- geom_curve(...)
new_layer <- ggproto(NULL, layer)
old_geom <- new_layer$geom
geom <- ggproto(
NULL, old_geom,
draw_panel = function(data, panel_params, coord,
curvature = 0.5, angle = 90, ncp = 5,
arrow = NULL, arrow.fill = NULL,
lineend = "butt", linejoin = "round",
na.rm = FALSE) {
data <- ggplot2:::remove_missing(
data, na.rm = na.rm, c("x", "y", "xend", "yend",
"linetype", "size", "shape")
)
if (ggplot2:::empty(data)) {
return(zeroGrob())
}
coords <- coord$transform(data, panel_params)
ends <- transform(data, x = xend, y = yend)
ends <- coord$transform(ends, panel_params)
arrow.fill <- if (!is.null(arrow.fill)) arrow.fill else coords$colour
return(grid::curveGrob(
coords$x, coords$y, ends$x, ends$y,
default.units = "native", gp = grid::gpar(
col = alpha(coords$colour, coords$alpha),
fill = alpha(arrow.fill, coords$alpha),
lwd = coords$size * .pt,
lty = coords$linetype,
lineend = lineend,
linejoin = linejoin
),
curvature = curvature, angle = angle, ncp = ncp,
square = FALSE, squareShape = 1, inflect = FALSE, open = TRUE,
arrow = arrow
))
}
)
new_layer$geom <- geom
return(new_layer)
}
As explained above, I sourced code to create a bivariate 5x5 legend.
source("https://raw.githubusercontent.com/R4IDSR/epichecks/master/R/bivarcolours.R")
Now I sourced the make_colours()
function from Github and now I create 26 different colours (5 times 5 + a colour for the missing data). Then I create 5 different n-tiles for both the number of words added and the numbers of edits. These will be plotted using scale_fill_identity()
in the plot.
cols2 <- make_colours(
num1 = 5,
num2 = 5,
og_pal1 = "Teal" ,
og_pal2 = "Peach"
) %>%
mutate(merger = str_glue("{rws}-{cls}")) %>%
add_row(merger = "NA-NA", clrs = "#f5f5f5")
complete_df <- complete_df %>%
mutate(quant_n = ntile(n, 5),
quant_net_words_added = ntile(net_words_added , 5)) %>%
mutate(merger = str_glue("{quant_n}-{quant_net_words_added}")) %>%
left_join(cols2, "merger")
complete_df %>%
sample_n(20) %>%
kable() %>%
kable_styling(c("striped", "hover", "condensed")) %>%
scroll_box(width = "100%", height = "200px")
district | year_report | n | last_entry | net_words_added | first_date | quant_n | quant_net_words_added | merger | rws | cls | clrs |
---|---|---|---|---|---|---|---|---|---|---|---|
Offinso Municipal District | 2018 | 6 | 281 | 0 | 2006-02-20 21:22:00 | 5 | 3 | 5-3 | 5 | 3 | #595367 |
Mpohor (district) | 2015 | NA | NA | NA | 2018-06-08 23:36:00 | NA | NA | NA-NA | NA | NA | #f5f5f5 |
Bosomtwe District | 2019 | NA | NA | NA | 2006-02-21 14:49:00 | NA | NA | NA-NA | NA | NA | #f5f5f5 |
Mfantsiman Municipal District | 2015 | NA | NA | NA | 2010-12-28 02:33:00 | NA | NA | NA-NA | NA | NA | #f5f5f5 |
Tatale Sangule District | 2016 | NA | NA | NA | 2015-04-10 18:18:00 | NA | NA | NA-NA | NA | NA | #f5f5f5 |
Birim South District | 2009 | 5 | 20 | 7 | 2006-02-20 19:46:00 | 4 | 4 | 4-4 | 4 | 4 | #915C5C |
Techiman Municipal District | 2021 | 2 | 118 | 42 | 2006-02-20 21:51:00 | 3 | 5 | 3-5 | 3 | 5 | #BA4E49 |
West Akim Municipal District | 2012 | 6 | 25 | -41 | 2006-02-21 12:51:00 | 5 | 1 | 5-1 | 5 | 1 | #2A5676 |
Atiwa West District | 2015 | NA | NA | NA | 2019-02-15 18:10:00 | NA | NA | NA-NA | NA | NA | #f5f5f5 |
Komenda/Edina/Eguafo/Abirem Municipal District | 2014 | 4 | 23 | 0 | 2006-02-20 21:01:00 | 4 | 2 | 4-2 | 4 | 2 | #6F6F79 |
Afadzato South District | 2006 | NA | NA | NA | 2015-06-14 12:06:00 | NA | NA | NA-NA | NA | NA | #f5f5f5 |
East Mamprusi Municipal Assembly | 2006 | 3 | 13 | 13 | 2006-02-20 19:52:00 | 3 | 4 | 3-4 | 3 | 4 | #B16658 |
Dormaa Central Municipal | 2012 | NA | NA | NA | NA | NA | NA | NA-NA | NA | NA | #f5f5f5 |
Mpohor (district) | 2016 | NA | NA | NA | 2018-06-08 23:36:00 | NA | NA | NA-NA | NA | NA | #f5f5f5 |
Awutu Senya West (district) | 2012 | NA | NA | NA | 2018-06-08 23:36:00 | NA | NA | NA-NA | NA | NA | #f5f5f5 |
Berekum West District | 2010 | NA | NA | NA | 2020-12-30 02:07:00 | NA | NA | NA-NA | NA | NA | #f5f5f5 |
North East Gonja District | 2009 | NA | NA | NA | 2015-04-10 17:47:00 | NA | NA | NA-NA | NA | NA | #f5f5f5 |
Asokwa Municipal | 2016 | NA | NA | NA | NA | NA | NA | NA-NA | NA | NA | #f5f5f5 |
Adansi North District | 2019 | NA | NA | NA | 2006-02-21 14:33:00 | NA | NA | NA-NA | NA | NA | #f5f5f5 |
Yendi Municipal District | 2010 | NA | NA | NA | 2011-04-26 19:33:00 | NA | NA | NA-NA | NA | NA | #f5f5f5 |
Now I am creating some extra dataframes that will be used to annotate the final visualization.
# some overall summary statistics.
summary_edits <- complete_df %>%
summarise(max_words_added = max(net_words_added, na.rm = T),
year_max_word_added = year_report[which.max(net_words_added)],
district_max_word_added = district[which.max(net_words_added)],
max_edits = max(n, na.rm = T),
year_max_edits = year_report[which.max(n)],
district_max_edits= district[which.max(n)])
# calculate the height and the colour of the column charts on the outer edge of the circlular plot
summary_min_and_max_words_2021 <- results_df %>%
group_by(district) %>%
summarise(words_2021 = number_words[which.max(date)],
n_edits = n())%>%
ungroup() %>%
mutate(quant_n = ntile(n_edits,5),
quant_net_words_added = ntile(words_2021 ,5))%>%
mutate(merger = str_glue("{quant_n}-{quant_net_words_added}")) %>%
left_join(cols2, "merger")
bars_on_top <- left_join(white_bars, summary_min_and_max_words_2021, by = "district") %>%
mutate(words_2021 = replace_na(words_2021, 0))%>%
# redo the factor reordering
left_join(order_of_entry, by = "district") %>%
mutate(district = as.factor(district))%>%
mutate(district = fct_reorder(district, first_date))
To make the plot visually more appealing, I trimmed off the tops of the bar to the 97th percentile.
max_val <- as.numeric(quantile(bars_on_top$words_2021, c(.97)))
deviding_factor <- max_val/(40-24)
Now that all the data is prepared, the fun can start…
circle <- ggplot() +
# add the tiles
geom_tile(
data = complete_df,
aes(x = district,
y = year_report - 1998,
fill = clrs),
colour = "grey60",
inherit.aes = F,
na.value = 'red'
) +
# add the proper colours
scale_fill_identity(drop = FALSE) +
# mask the year-district combinations for whihch no data excisted yet
geom_rect(
data = white_bars,
aes(
xmin = as.numeric(district) - 0.5,
xmax = as.numeric(district) + .5 ,
ymin = 2005.5 - 1998,
ymax = min - 1998.5
),
fill = background_col,
col = background_col,
alpha = 1,
inherit.aes = F
) +
# add an inner and outer circle
scale_y_continuous(limits = c(-7, 40), expand = c(0, -7)) +
# add some white space to put the year labels in
scale_x_discrete(limits = c(levels(complete_df$district),
paste0("NA", 1:n_white_gaps))) +
# change the coordinate system to polar
coord_polar(start = 0, clip = "off") +
# add bar charts to outer circle
geom_rect(
data = bars_on_top,
aes(
xmin = as.numeric(district) - 0.5,
xmax = as.numeric(district) + .5 ,
ymin = 24,
fill = clrs ,
ymax = 24 + (
ifelse(words_2021 > max_val, max_val, words_2021) / deviding_factor
)
),
alpha = .5
) +
# add the labels
geom_text(
data = label_data,
aes(
x = district,
y = 24,
label = label,
hjust = hjust
),
color = "black",
fontface = "bold",
family = plot_font,
alpha = 0.6,
size = 2,
angle = label_data$angle,
inherit.aes = FALSE
) +
# add a black line around the inner part of the plot
geom_step(
data = white_bars,
aes(x = as.numeric(district) - 0.5,
y = min - 1998.5),
col = "black",
size = .5,
alpha = 1,
inherit.aes = F
) +
# add a black line on the ouer pary of the plot
geom_hline(yintercept = 2021 - 1997.5,
size = .5,
col = "black") +
# add the year labels
geom_text(
data = tibble(
y = c(2021:2006) - 1998,
x = 0.5,
labels = 2021:2006
),
aes(x = x ,
y = y,
label = labels),
hjust = 1,
size = 2.5,
family = plot_font,
inherit.aes = F
) +
# add a curved arrow to indicate direction
# of reading the plot
geom_segment(
aes(
x = white_bars$district[1],
y = 2005.2 - 1998,
xend = white_bars$district[70],
yend = 2005.2 - 1998
),
size = .5,
col = col_arrows_and_lines,
arrow = arrow(length = unit(0.15, "cm"))
) +
# add an annotation thi this line
geom_fit_text(
data = tibble(
ymin = c(2003.7) - 1997.5,
ymax = c(2004.3) - 1997.5,
xmin = 0,
xmax = 80,
labels = "districts ordered by date first Wiki entry"
),
aes(
ymin = ymin,
ymax = ymax,
xmin = xmin,
xmax = xmax,
label = labels
),
family = plot_font,
min.size = 3,
grow = TRUE,
padding.x = grid::unit(0, "mm"),
padding.y = grid::unit(0, "mm"),
fullheight = TRUE,
inherit.aes = F
) +
# add annotation showing how many
# districts do not yet have a wikipedia page
geom_fit_text(
data = tibble(
ymin = c(2020) - 1997.6,
ymax = c(2021) - 1997.6,
xmin = white_bars$district[sum(white_bars$min != 2022) + 2],
xmax = white_bars$district[nrow(white_bars)],
labels = paste0(
sum(white_bars$min == 2022),
" districts do not yet have a Wiki entry"
)
),
aes(
ymin = ymin,
ymax = ymax,
xmin = xmin,
xmax = xmax,
label = labels
),
min.size = 1,
grow = TRUE,
padding.x = grid::unit(0, "mm"),
padding.y = grid::unit(0, "mm"),
family = plot_font,
fullheight = TRUE,
inherit.aes = F
) +
# add annotation (arrow and text)
# to point to some interesting data
geom_curve_polar(
aes(
x = summary_edits$district_max_word_added,
y = summary_edits$year_max_word_added - 1998,
yend = 2010.5 - 1998,
xend = 'Akatsi South District'
),
arrow = arrow(length = unit(0.2, "cm")),
col = col_arrows_and_lines,
curvature = -.3,
angle = -90,
size = .5
) +
annotate(
"text",
x = 'Akatsi South District',
y = 2010 - 1998,
label = str_glue(
"In 2017, {comma(summary_edits$max_words_added, digits = 0)} new words\nwere added to the Wikipedia\npage of {summary_edits$district_max_word_added}"
),
vjust = 0,
family = plot_font,
size = 2.5,
lineheight = .9
) +
# add arrow pointing towards district that was added last
geom_curve_polar(
aes(
x = white_bars$district[sum(white_bars$min != 2022) + 2],
y = 2017 - 1998,
yend = 2021 - 1998,
xend = white_bars$district[sum(white_bars$min != 2022)]
),
arrow = arrow(length = unit(0.2, "cm")),
col = col_arrows_and_lines ,
curvature = -.3,
angle = -90,
size = .5
) +
# add arrow pointing towards Accra Metropolitan District
geom_curve_polar(
aes(
x = which(white_bars$district == "Accra Metropolitan District") + 2.5,
y = 2038 - 1998,
yend = 2038 - 1998,
xend = which(white_bars$district == "Accra Metropolitan District")
),
arrow = arrow(length = unit(0.2, "cm")),
col = col_arrows_and_lines,
curvature = .3,
angle = -90,
size = .5
) +
# add label with information on district that was added last
annotate(
"text",
x = white_bars$district[sum(white_bars$min != 2022)],
y = 2016 - 1998,
label = str_glue(
"On {format(as_date(ymd_hms(max(results_df$date, na.rm = T))), '%d %B %Y')}, \n{white_bars$district[sum(white_bars$min != 2022) ]}\nwas the latest district to get\na Wikipedia page"
),
vjust = 0,
hjust = 0,
family = plot_font,
size = 2.5,
lineheight = .9
) +
# add label with information on Accra Metropolitan District
annotate(
"text",
x = which(white_bars$district == "Accra Metropolitan District") + 3,
y = 2037 - 1998,
label = str_glue(
"Accra Metropolitan District\nis the district with the longest\nWiki entry page (24,743 words)"
),
vjust = 0,
family = plot_font,
size = 2.5,
hjust = 0,
lineheight = .9
) +
# add annotation layer explaining plot
annotate(
"text",
x = 235,
y =39,
label = str_wrap(str_glue(
"The gradient from blues to reds indicate the number of words that were added to a given page,\\
while the darker shades of corresponding colors represent the number of edits that were made to these pages. \\
In this visualization, too many dimensions are plotted at once. Admittedly, a simple bar chart would have been clearer. \\
However, form over function is not always a bad thing and sometimes a visualization should just be nice to look at. \\
The data for the project was scraped in the first week of March 2021, so it might be outdated by now. \\
The bivariate colour mapping is inspired by the biscale package and to implement the 5x5 matrix it sourced code from: \\
https://github.com/R4IDSR/epichecks."
), 55),
vjust = -0.05,
family = plot_font,
size = 2.1,
hjust = 0,
lineheight = .9
) +
# add scale on top of plot
geom_errorbar(
aes(
xmax = 265,
ymax = 24,
ymin = 40,
x = 265,
y = 30
),
col = col_arrows_and_lines,
) +
# add text to this scale
geom_text(
aes(y = 24, x = 265, label = "0"),
hjust = 1,
size = 2,
nudge_x = -.5,
family = plot_font
) +
geom_text(
aes(
y = 40,
x = 265,
label = glue("{ceiling(max_val/100)*100}+")
),
hjust = 1,
size = 2,
nudge_x = -.5,
family = plot_font
) +
# add label to axis
geom_text(
aes(y = mean(c(24, 40)),
x = 265,
label = "total number of words"),
hjust = .5,
nudge_x = -.7,
angle = 90,
size = 2,
family = plot_font
) +
# add base theme
theme_void() +
# make some adjustments to theme
theme(
panel.background = element_rect(
fill = background_col,
colour = NA,
size = 0
),
plot.background = element_rect(
fill = background_col,
colour = NA,
size = 0
),
panel.border = element_blank(),
axis.title = element_blank(),
panel.grid = element_blank(),
plot.title = element_text(
family = plot_font,
face = "bold",
hjust = .5,
size = 16
),
plot.subtitle = element_text(
family = plot_font,
color = col_arrows_and_lines,
hjust = .5,
size = 9
),
plot.caption = element_text(
family = plot_font,
hjust =1,
size = 8
),
panel.spacing = unit(0, "lines"),
plot.margin = margin(0, 0, 0, 0, unit = "cm"),
axis.text.x = element_blank(),
axis.ticks = element_blank(),
axis.text.y = element_blank(),
legend.position = "none"
) +
# add title and labels to plot
labs(title = "Visualizing Contributions to the Wikipedia Pages of Ghana's 260 Districts",
subtitle = paste0(str_wrap(
glue(
"This infographic shows the results of web-scraped Wikipedia data on the 260 districts in Ghana.\\
It shows both the number of edits and the net number of words added per year per district.\\
Over other dimensions, it also shows the total length of each district's Wikipedia article \\
and in which year a page was first created.\n\n"
),
140
), "\n\n"),
caption = "visualization by Laurent Smeets")
# dowload wikipedia logo
logo <- png::readPNG("https://upload.wikimedia.org/wikipedia/en/thumb/8/80/Wikipedia-logo-v2.svg/1122px-Wikipedia-logo-v2.svg.png", native = TRUE)
# add wikipedia logo to plot
circle_logo <- circle +
inset_element(
p = logo,
left = 0.45,
bottom = 0.45,
right = 0.55,
top = 0.55,
align_to = 'panel'
) +
theme_void()
# create a custom legend
legend_square <- ggplot(data = cols2,
mapping = aes(x = cls,
y = rws,
fill = clrs)) +
geom_tile(alpha = 1) +
scale_fill_identity() +
scale_x_continuous(breaks = c(0:5)) +
scale_y_continuous(breaks = c(0:5)) +
labs(x = substitute(paste("more words added", "" %->% "")),
y = substitute(paste("more revisions", "" %->% ""))) +
theme(
plot.margin = margin(0, 0, 0, 0, unit = "cm"),
panel.grid.major.x = element_blank(),
panel.grid.minor.x = element_blank(),
panel.grid.major.y = element_blank(),
axis.text = element_blank(),
panel.grid.minor.y = element_blank(),
strip.background = element_rect(color = "transparent", fill = "transparent"),
plot.background = element_rect(color = "transparent", fill = "transparent"),
panel.background = element_rect(color = "transparent", fill = "transparent"),
panel.border = element_blank(),
axis.title.x = element_text(
margin = margin(-0.1, 0 , 0, 0, unit = "cm"),
family = plot_font,
size = 13
),
axis.title.y = element_text(
margin = margin(0,-0.1, 0, 0, unit = "cm"),
family = plot_font,
size = 13
)
)
# add legend to plot
circle_logo_legend <-
circle_logo +
inset_element(
p = legend_square,
left = 0.01,
bottom = 0.83,
right = 0.18,
top = 1,
align_to = 'panel'
) +
theme_minimal() +
theme(
panel.grid.major.x = element_blank(),
panel.grid.minor.x = element_blank(),
panel.grid.major.y = element_blank(),
axis.text = element_blank(),
axis.title.x = element_text(
margin = margin(-0.1, 0 , 0, 0, unit = "cm"),
family = plot_font,
hjust = 0.5,
size = 9
),
axis.title.y = element_text(
margin = margin(0, -0.1, 0, 0, unit = "cm"),
family = plot_font,
hjust = 0.5,
size = 9
)
) +
coord_fixed(expand = F)
circle_logo_legend
This short video shows how this plot was actually built in ggplot (hosted on Vimeo).
Valuable Information and Tutorials
These are some further valuable sources on analysis of these kinds:
- Harvesting the web with rvest
- Web Scraping in R: rvest Tutorial
- Multivariate Mapping
- Bivariate Choropleth Maps: A How-to Guide (for a good explanation of bivariate maps)