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)
DistrictDistrict_linklink_to_hist
Asunafo North/wiki/Asunafo_North_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Asunafo_North_Municipal_District&offset=&limit=5000&action=history
Asunafo South/wiki/Asunafo_South_Districthttps://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_Districthttps://en.wikipedia.org/w/index.php?title=Tano_North_Municipal_District&offset=&limit=5000&action=history
Tano South/wiki/Tano_South_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Tano_South_Municipal_District&offset=&limit=5000&action=history
Adansi Asokwa/wiki/Adansi_Asokwa_Districthttps://en.wikipedia.org/w/index.php?title=Adansi_Asokwa_District&offset=&limit=5000&action=history
Adansi North/wiki/Adansi_North_Districthttps://en.wikipedia.org/w/index.php?title=Adansi_North_District&offset=&limit=5000&action=history
Adansi South/wiki/Adansi_South_Districthttps://en.wikipedia.org/w/index.php?title=Adansi_South_District&offset=&limit=5000&action=history
Afigya-Kwabre North/wiki/Afigya_Kwabre_North_Districthttps://en.wikipedia.org/w/index.php?title=Afigya_Kwabre_North_District&offset=&limit=5000&action=history
Afigya-Kwabre South/wiki/Afigya_Kwabre_South_Districthttps://en.wikipedia.org/w/index.php?title=Afigya_Kwabre_South_District&offset=&limit=5000&action=history
Ahafo-Ano North/wiki/Ahafo_Ano_North_Municipal_Districthttps://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_Districthttps://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_Districthttps://en.wikipedia.org/w/index.php?title=Ahafo_Ano_South_District&offset=&limit=5000&action=history
Akrofuom/wiki/Akrofuom_Districthttps://en.wikipedia.org/w/index.php?title=Akrofuom_District&offset=&limit=5000&action=history
Amansie Central/wiki/Amansie_Central_Districthttps://en.wikipedia.org/w/index.php?title=Amansie_Central_District&offset=&limit=5000&action=history
Amansie West/wiki/Amansie_West_Districthttps://en.wikipedia.org/w/index.php?title=Amansie_West_District&offset=&limit=5000&action=history
Amansie South/wiki/Amansie_South_Districthttps://en.wikipedia.org/w/index.php?title=Amansie_South_District&offset=&limit=5000&action=history
Asante-Akim Central/wiki/Asante_Akim_Central_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Asante_Akim_Central_Municipal_District&offset=&limit=5000&action=history
Asante-Akim North/wiki/Asante_Akim_North_Districthttps://en.wikipedia.org/w/index.php?title=Asante_Akim_North_District&offset=&limit=5000&action=history
Asante-Akim South/wiki/Asante_Akim_South_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Asante_Akim_South_Municipal_District&offset=&limit=5000&action=history
Asokore-Mampong/wiki/Asokore_Mampong_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Asokore_Mampong_Municipal_District&offset=&limit=5000&action=history
Asokwa/wiki/Asokwa_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Asokwa_Municipal_District&offset=&limit=5000&action=history
Atwima-Kwanwoma/wiki/Atwima_Kwanwoma_Districthttps://en.wikipedia.org/w/index.php?title=Atwima_Kwanwoma_District&offset=&limit=5000&action=history
Atwima-Mponua/wiki/Atwima_Mponua_Districthttps://en.wikipedia.org/w/index.php?title=Atwima_Mponua_District&offset=&limit=5000&action=history
Atwima-Nwabiagya/wiki/Atwima_Nwabiagya_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Atwima_Nwabiagya_Municipal_District&offset=&limit=5000&action=history
Atwima-Nwabiagya North/wiki/Atwima_Nwabiagya_North_Districthttps://en.wikipedia.org/w/index.php?title=Atwima_Nwabiagya_North_District&offset=&limit=5000&action=history
Bekwai/wiki/Bekwai_Municipal_Assemblyhttps://en.wikipedia.org/w/index.php?title=Bekwai_Municipal_Assembly&offset=&limit=5000&action=history
Bosome Freho/wiki/Bosome_Freho_Districthttps://en.wikipedia.org/w/index.php?title=Bosome_Freho_District&offset=&limit=5000&action=history
Bosomtwe/wiki/Bosomtwe_Districthttps://en.wikipedia.org/w/index.php?title=Bosomtwe_District&offset=&limit=5000&action=history
Ejisu/wiki/Ejisu_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Ejisu_Municipal_District&offset=&limit=5000&action=history
Ejura/Sekyedumase/wiki/Ejura/Sekyedumase_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Ejura/Sekyedumase_Municipal_District&offset=&limit=5000&action=history
Juaben/wiki/Juaben_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Juaben_Municipal_District&offset=&limit=5000&action=history
Kumasi/wiki/Kumasi_Metropolitan_Assemblyhttps://en.wikipedia.org/w/index.php?title=Kumasi_Metropolitan_Assembly&offset=&limit=5000&action=history
Kwabre East/wiki/Kwabre_East_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Kwabre_East_Municipal_District&offset=&limit=5000&action=history
Kwadaso/wiki/Kwadaso_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Kwadaso_Municipal_District&offset=&limit=5000&action=history
Mampong/wiki/Mampong_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Mampong_Municipal_District&offset=&limit=5000&action=history
Obuasi East/wiki/Obuasi_East_Districthttps://en.wikipedia.org/w/index.php?title=Obuasi_East_District&offset=&limit=5000&action=history
Obuasi/wiki/Obuasi_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Obuasi_Municipal_District&offset=&limit=5000&action=history
Offinso/wiki/Offinso_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Offinso_Municipal_District&offset=&limit=5000&action=history
Offinso North/wiki/Offinso_North_Districthttps://en.wikipedia.org/w/index.php?title=Offinso_North_District&offset=&limit=5000&action=history
Oforikrom/wiki/Oforikrom_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Oforikrom_Municipal_District&offset=&limit=5000&action=history
Old Tafo/wiki/Old_Tafo_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Old_Tafo_Municipal_District&offset=&limit=5000&action=history
Sekyere Afram Plains/wiki/Sekyere_Afram_Plains_Districthttps://en.wikipedia.org/w/index.php?title=Sekyere_Afram_Plains_District&offset=&limit=5000&action=history
Sekyere Central/wiki/Sekyere_Central_Districthttps://en.wikipedia.org/w/index.php?title=Sekyere_Central_District&offset=&limit=5000&action=history
Sekyere East/wiki/Sekyere_East_Districthttps://en.wikipedia.org/w/index.php?title=Sekyere_East_District&offset=&limit=5000&action=history
Sekyere Kumawu/wiki/Sekyere_Kumawu_Districthttps://en.wikipedia.org/w/index.php?title=Sekyere_Kumawu_District&offset=&limit=5000&action=history
Sekyere South/wiki/Sekyere_South_Districthttps://en.wikipedia.org/w/index.php?title=Sekyere_South_District&offset=&limit=5000&action=history
Suame/wiki/Suame_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Suame_Municipal_District&offset=&limit=5000&action=history
Banda/wiki/Banda_District,_Ghanahttps://en.wikipedia.org/w/index.php?title=Banda_District,_Ghana&offset=&limit=5000&action=history
Berekum East/wiki/Berekum_East_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Berekum_East_Municipal_District&offset=&limit=5000&action=history
Berekum West/wiki/Berekum_West_Districthttps://en.wikipedia.org/w/index.php?title=Berekum_West_District&offset=&limit=5000&action=history
Dormaa Central/wiki/Dormaa_Central_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Dormaa_Central_Municipal_District&offset=&limit=5000&action=history
Dormaa East/wiki/Dormaa_East_Districthttps://en.wikipedia.org/w/index.php?title=Dormaa_East_District&offset=&limit=5000&action=history
Dormaa West/wiki/Dormaa_West_Districthttps://en.wikipedia.org/w/index.php?title=Dormaa_West_District&offset=&limit=5000&action=history
Jaman North/wiki/Jaman_North_Districthttps://en.wikipedia.org/w/index.php?title=Jaman_North_District&offset=&limit=5000&action=history
Jaman South/wiki/Jaman_South_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Jaman_South_Municipal_District&offset=&limit=5000&action=history
Sunyani/wiki/Sunyani_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Sunyani_Municipal_District&offset=&limit=5000&action=history
Sunyani West/wiki/Sunyani_West_Districthttps://en.wikipedia.org/w/index.php?title=Sunyani_West_District&offset=&limit=5000&action=history
Tain/wiki/Tain_Districthttps://en.wikipedia.org/w/index.php?title=Tain_District&offset=&limit=5000&action=history
Wenchi/wiki/Wenchi_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Wenchi_Municipal_District&offset=&limit=5000&action=history
Atebubu-Amantin/wiki/Atebubu-Amantin_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Atebubu-Amantin_Municipal_District&offset=&limit=5000&action=history
Kintampo North/wiki/Kintampo_North_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Kintampo_North_Municipal_District&offset=&limit=5000&action=history
Kintampo South/wiki/Kintampo_South_Districthttps://en.wikipedia.org/w/index.php?title=Kintampo_South_District&offset=&limit=5000&action=history
Nkoranza North/wiki/Nkoranza_North_Districthttps://en.wikipedia.org/w/index.php?title=Nkoranza_North_District&offset=&limit=5000&action=history
Nkoranza South/wiki/Nkoranza_South_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Nkoranza_South_Municipal_District&offset=&limit=5000&action=history
Pru East/wiki/Pru_East_Districthttps://en.wikipedia.org/w/index.php?title=Pru_East_District&offset=&limit=5000&action=history
Pru West/wiki/Pru_West_Districthttps://en.wikipedia.org/w/index.php?title=Pru_West_District&offset=&limit=5000&action=history
Sene East/wiki/Sene_East_Districthttps://en.wikipedia.org/w/index.php?title=Sene_East_District&offset=&limit=5000&action=history
Sene West/wiki/Sene_West_Districthttps://en.wikipedia.org/w/index.php?title=Sene_West_District&offset=&limit=5000&action=history
Techiman/wiki/Techiman_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Techiman_Municipal_District&offset=&limit=5000&action=history
Techiman North/wiki/Techiman_North_Districthttps://en.wikipedia.org/w/index.php?title=Techiman_North_District&offset=&limit=5000&action=history
Abura/Asebu/Kwamankese/wiki/Abura/Asebu/Kwamankese_Districthttps://en.wikipedia.org/w/index.php?title=Abura/Asebu/Kwamankese_District&offset=&limit=5000&action=history
Agona East/wiki/Agona_East_Districthttps://en.wikipedia.org/w/index.php?title=Agona_East_District&offset=&limit=5000&action=history
Agona West Municipal/wiki/Agona_West_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Agona_West_Municipal_District&offset=&limit=5000&action=history
Ajumako/Enyan/Essiam/wiki/Ajumako/Enyan/Essiam_Districthttps://en.wikipedia.org/w/index.php?title=Ajumako/Enyan/Essiam_District&offset=&limit=5000&action=history
Asikuma Odoben Brakwa/wiki/Asikuma/Odoben/Brakwa_Districthttps://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=1https://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_Districthttps://en.wikipedia.org/w/index.php?title=Assin_North_District&offset=&limit=5000&action=history
Assin South/wiki/Assin_South_Districthttps://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_Assemblyhttps://en.wikipedia.org/w/index.php?title=Cape_Coast_Metropolitan_Assembly&offset=&limit=5000&action=history
Effutu Municipal/wiki/Effutu_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Effutu_Municipal_District&offset=&limit=5000&action=history
Ekumfi/wiki/Ekumfi_Districthttps://en.wikipedia.org/w/index.php?title=Ekumfi_District&offset=&limit=5000&action=history
Gomoa East/wiki/Gomoa_East_Districthttps://en.wikipedia.org/w/index.php?title=Gomoa_East_District&offset=&limit=5000&action=history
Gomoa Central/wiki/Gomoa_Central_Districthttps://en.wikipedia.org/w/index.php?title=Gomoa_Central_District&offset=&limit=5000&action=history
Gomoa West/wiki/Gomoa_West_Districthttps://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_Districthttps://en.wikipedia.org/w/index.php?title=Komenda/Edina/Eguafo/Abirem_Municipal_District&offset=&limit=5000&action=history
Mfantsiman Municipal/wiki/Mfantsiman_Municipal_Districthttps://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_Districthttps://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_Districthttps://en.wikipedia.org/w/index.php?title=Upper_Denkyira_East_Municipal_District&offset=&limit=5000&action=history
Upper Denkyira West/wiki/Upper_Denkyira_West_Districthttps://en.wikipedia.org/w/index.php?title=Upper_Denkyira_West_District&offset=&limit=5000&action=history
Abuakwa North/wiki/Abuakwa_North_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Abuakwa_North_Municipal_District&offset=&limit=5000&action=history
Abuakwa South/wiki/Abuakwa_South_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Abuakwa_South_Municipal_District&offset=&limit=5000&action=history
Achiase/wiki/Achiase_Districthttps://en.wikipedia.org/w/index.php?title=Achiase_District&offset=&limit=5000&action=history
Akuapim North/wiki/Akuapim_North_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Akuapim_North_Municipal_District&offset=&limit=5000&action=history
Akuapim South/wiki/Akuapim_South_Districthttps://en.wikipedia.org/w/index.php?title=Akuapim_South_District&offset=&limit=5000&action=history
Akyemansa/wiki/Akyemansa_Districthttps://en.wikipedia.org/w/index.php?title=Akyemansa_District&offset=&limit=5000&action=history
Asene Manso Akroso/wiki/Asene_Manso_Akroso_Districthttps://en.wikipedia.org/w/index.php?title=Asene_Manso_Akroso_District&offset=&limit=5000&action=history
Asuogyaman/wiki/Asuogyaman_Districthttps://en.wikipedia.org/w/index.php?title=Asuogyaman_District&offset=&limit=5000&action=history
Atiwa East/wiki/Atiwa_East_Districthttps://en.wikipedia.org/w/index.php?title=Atiwa_East_District&offset=&limit=5000&action=history
Atiwa West/wiki/Atiwa_West_Districthttps://en.wikipedia.org/w/index.php?title=Atiwa_West_District&offset=&limit=5000&action=history
Ayensuano/wiki/Ayensuano_Districthttps://en.wikipedia.org/w/index.php?title=Ayensuano_District&offset=&limit=5000&action=history
Birim Central/wiki/Birim_Central_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Birim_Central_Municipal_District&offset=&limit=5000&action=history
Birim North/wiki/Birim_North_Districthttps://en.wikipedia.org/w/index.php?title=Birim_North_District&offset=&limit=5000&action=history
Birim South/wiki/Birim_South_Districthttps://en.wikipedia.org/w/index.php?title=Birim_South_District&offset=&limit=5000&action=history
Denkyembour/wiki/Denkyembour_Districthttps://en.wikipedia.org/w/index.php?title=Denkyembour_District&offset=&limit=5000&action=history
Fanteakwa North/wiki/Fanteakwa_North_Districthttps://en.wikipedia.org/w/index.php?title=Fanteakwa_North_District&offset=&limit=5000&action=history
Fanteakwa South/wiki/Fanteakwa_South_Districthttps://en.wikipedia.org/w/index.php?title=Fanteakwa_South_District&offset=&limit=5000&action=history
Kwaebibirem/wiki/Kwaebibirem_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Kwaebibirem_Municipal_District&offset=&limit=5000&action=history
Kwahu Afram Plains North/wiki/Kwahu_Afram_Plains_North_Districthttps://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_Districthttps://en.wikipedia.org/w/index.php?title=Kwahu_Afram_Plains_South_District&offset=&limit=5000&action=history
Kwahu East/wiki/Kwahu_East_Districthttps://en.wikipedia.org/w/index.php?title=Kwahu_East_District&offset=&limit=5000&action=history
Kwahu South/wiki/Kwahu_South_Districthttps://en.wikipedia.org/w/index.php?title=Kwahu_South_District&offset=&limit=5000&action=history
Kwahu West/wiki/Kwahu_West_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Kwahu_West_Municipal_District&offset=&limit=5000&action=history
Lower Manya Krobo/wiki/Lower_Manya_Krobo_Municipal_Districthttps://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_Assemblyhttps://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_Assemblyhttps://en.wikipedia.org/w/index.php?title=New_Juaben_South_Municipal_Assembly&offset=&limit=5000&action=history
Nsawam Adoagyire/wiki/Nsawam_Adoagyire_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Nsawam_Adoagyire_Municipal_District&offset=&limit=5000&action=history
Okere/wiki/Okere_Districthttps://en.wikipedia.org/w/index.php?title=Okere_District&offset=&limit=5000&action=history
Suhum/wiki/Suhum_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Suhum_Municipal_District&offset=&limit=5000&action=history
Upper Manya Krobo/wiki/Upper_Manya_Krobo_Districthttps://en.wikipedia.org/w/index.php?title=Upper_Manya_Krobo_District&offset=&limit=5000&action=history
Upper West Akim/wiki/Upper_West_Akim_Districthttps://en.wikipedia.org/w/index.php?title=Upper_West_Akim_District&offset=&limit=5000&action=history
West Akim/wiki/West_Akim_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=West_Akim_Municipal_District&offset=&limit=5000&action=history
Yilo-Krobo/wiki/Yilo_Krobo_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Yilo_Krobo_Municipal_District&offset=&limit=5000&action=history
Ablekuma Central/wiki/Ablekuma_Central_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Ablekuma_Central_Municipal_District&offset=&limit=5000&action=history
Ablekuma North/wiki/Ablekuma_North_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Ablekuma_North_Municipal_District&offset=&limit=5000&action=history
Ablekuma West/wiki/Ablekuma_West_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Ablekuma_West_Municipal_District&offset=&limit=5000&action=history
Accra/wiki/Accra_Metropolitan_Districthttps://en.wikipedia.org/w/index.php?title=Accra_Metropolitan_District&offset=&limit=5000&action=history
Ada East/wiki/Ada_East_Districthttps://en.wikipedia.org/w/index.php?title=Ada_East_District&offset=&limit=5000&action=history
Ada West/wiki/Ada_West_Districthttps://en.wikipedia.org/w/index.php?title=Ada_West_District&offset=&limit=5000&action=history
Adenta/wiki/Adenta_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Adenta_Municipal_District&offset=&limit=5000&action=history
Ashaiman/wiki/Ashaiman_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Ashaiman_Municipal_District&offset=&limit=5000&action=history
Ayawaso Central/wiki/Ayawaso_Central_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Ayawaso_Central_Municipal_District&offset=&limit=5000&action=history
Ayawaso East/wiki/Ayawaso_East_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Ayawaso_East_Municipal_District&offset=&limit=5000&action=history
Ayawaso North/wiki/Ayawaso_North_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Ayawaso_North_Municipal_District&offset=&limit=5000&action=history
Ayawaso West/wiki/Ayawaso_West_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Ayawaso_West_Municipal_District&offset=&limit=5000&action=history
Ga Central/wiki/Ga_Central_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Ga_Central_Municipal_District&offset=&limit=5000&action=history
Ga East/wiki/Ga_East_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Ga_East_Municipal_District&offset=&limit=5000&action=history
Ga North/wiki/Ga_North_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Ga_North_Municipal_District&offset=&limit=5000&action=history
Ga South/wiki/Ga_South_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Ga_South_Municipal_District&offset=&limit=5000&action=history
Ga West/wiki/Ga_West_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Ga_West_Municipal_District&offset=&limit=5000&action=history
Korle-Klottey/wiki/Korle_Klottey_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Korle_Klottey_Municipal_District&offset=&limit=5000&action=history
Kpone-Katamanso/wiki/Kpone_Katamanso_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Kpone_Katamanso_Municipal_District&offset=&limit=5000&action=history
Krowor/wiki/Krowor_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Krowor_Municipal_District&offset=&limit=5000&action=history
La-Dade-Kotopon/wiki/La_Dade_Kotopon_Municipal_Districthttps://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_Districthttps://en.wikipedia.org/w/index.php?title=La_Nkwantanang_Madina_Municipal_District&offset=&limit=5000&action=history
Ledzokuku/wiki/Ledzokuku_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Ledzokuku_Municipal_District&offset=&limit=5000&action=history
Ningo-Prampram/wiki/Ningo_Prampram_Districthttps://en.wikipedia.org/w/index.php?title=Ningo_Prampram_District&offset=&limit=5000&action=history
Okaikwei North/wiki/Okaikwei_North_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Okaikwei_North_Municipal_District&offset=&limit=5000&action=history
Shai-Osudoku/wiki/Shai_Osudoku_Districthttps://en.wikipedia.org/w/index.php?title=Shai_Osudoku_District&offset=&limit=5000&action=history
Tema Metropolitan/wiki/Tema_Metropolis_Districthttps://en.wikipedia.org/w/index.php?title=Tema_Metropolis_District&offset=&limit=5000&action=history
Tema West/wiki/Tema_West_Municipal_Districthttps://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=1https://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_Districthttps://en.wikipedia.org/w/index.php?title=Gushegu_District&offset=&limit=5000&action=history
Karaga/wiki/Karaga_Districthttps://en.wikipedia.org/w/index.php?title=Karaga_District&offset=&limit=5000&action=history
Kpandai/wiki/Kpandai_Districthttps://en.wikipedia.org/w/index.php?title=Kpandai_District&offset=&limit=5000&action=history
Kumbungu/wiki/Kumbungu_Districthttps://en.wikipedia.org/w/index.php?title=Kumbungu_District&offset=&limit=5000&action=history
Mion/wiki/Mion_Districthttps://en.wikipedia.org/w/index.php?title=Mion_District&offset=&limit=5000&action=history
Nanton/wiki/Nanton_Districthttps://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=1https://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_Districthttps://en.wikipedia.org/w/index.php?title=Nanumba_South_District&offset=&limit=5000&action=history
Saboba/wiki/Saboba_Districthttps://en.wikipedia.org/w/index.php?title=Saboba_District&offset=&limit=5000&action=history
Sagnarigu Municipal/wiki/Sagnarigu_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Sagnarigu_Municipal_District&offset=&limit=5000&action=history
Savelugu Municipal/wiki/Savelugu_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Savelugu_Municipal_District&offset=&limit=5000&action=history
Tamale Metropolitan/wiki/Tamale_Metropolitan_Districthttps://en.wikipedia.org/w/index.php?title=Tamale_Metropolitan_District&offset=&limit=5000&action=history
Tatale Sanguli/wiki/Tatale_Sangule_Districthttps://en.wikipedia.org/w/index.php?title=Tatale_Sangule_District&offset=&limit=5000&action=history
Tolon/wiki/Tolon_Districthttps://en.wikipedia.org/w/index.php?title=Tolon_District&offset=&limit=5000&action=history
Yendi Municipal/wiki/Yendi_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Yendi_Municipal_District&offset=&limit=5000&action=history
Zabzugu/wiki/Zabzugu_Districthttps://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=1https://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_Districthttps://en.wikipedia.org/w/index.php?title=Chereponi_District&offset=&limit=5000&action=history
East Mamprusi/wiki/East_Mamprusi_Municipal_Assemblyhttps://en.wikipedia.org/w/index.php?title=East_Mamprusi_Municipal_Assembly&offset=&limit=5000&action=history
Mamprugu Moagduri/wiki/Mamprugu_Moagduri_Districthttps://en.wikipedia.org/w/index.php?title=Mamprugu_Moagduri_District&offset=&limit=5000&action=history
West Mamprusi/wiki/West_Mamprusi_Districthttps://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=1https://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_Districthttps://en.wikipedia.org/w/index.php?title=Biakoye_District&offset=&limit=5000&action=history
Jasikan/wiki/Jasikan_Districthttps://en.wikipedia.org/w/index.php?title=Jasikan_District&offset=&limit=5000&action=history
Kadjebi/wiki/Kadjebi_Districthttps://en.wikipedia.org/w/index.php?title=Kadjebi_District&offset=&limit=5000&action=history
Krachi East/wiki/Krachi_East_Districthttps://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_Districthttps://en.wikipedia.org/w/index.php?title=Krachi_West_District&offset=&limit=5000&action=history
Nkwanta North/wiki/Nkwanta_North_Districthttps://en.wikipedia.org/w/index.php?title=Nkwanta_North_District&offset=&limit=5000&action=history
Nkwanta South/wiki/Nkwanta_South_Districthttps://en.wikipedia.org/w/index.php?title=Nkwanta_South_District&offset=&limit=5000&action=history
Bole/wiki/Bole_Districthttps://en.wikipedia.org/w/index.php?title=Bole_District&offset=&limit=5000&action=history
Central Gonja/wiki/Central_Gonja_Districthttps://en.wikipedia.org/w/index.php?title=Central_Gonja_District&offset=&limit=5000&action=history
East Gonja Municipal/wiki/East_Gonja_Municipal_Districthttps://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_Districthttps://en.wikipedia.org/w/index.php?title=North_East_Gonja_District&offset=&limit=5000&action=history
Sawla-Tuna-Kalba/wiki/Sawla-Tuna-Kalba_Districthttps://en.wikipedia.org/w/index.php?title=Sawla-Tuna-Kalba_District&offset=&limit=5000&action=history
West Gonja/wiki/West_Gonja_Districthttps://en.wikipedia.org/w/index.php?title=West_Gonja_District&offset=&limit=5000&action=history
Bawku Municipal/wiki/Bawku_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Bawku_Municipal_District&offset=&limit=5000&action=history
Bawku West/wiki/Bawku_West_Districthttps://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_Districthttps://en.wikipedia.org/w/index.php?title=Bolgatanga_East_District&offset=&limit=5000&action=history
Bolgatanga Municipal/wiki/Bolgatanga_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Bolgatanga_Municipal_District&offset=&limit=5000&action=history
Bongo/wiki/Bongo_Districthttps://en.wikipedia.org/w/index.php?title=Bongo_District&offset=&limit=5000&action=history
Builsa North Municipal/wiki/Builsa_North_Districthttps://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_Districthttps://en.wikipedia.org/w/index.php?title=Garu_District&offset=&limit=5000&action=history
Kassena Nankana Municipal/wiki/Kassena_Nankana_East_Districthttps://en.wikipedia.org/w/index.php?title=Kassena_Nankana_East_District&offset=&limit=5000&action=history
Kassena Nankana West/wiki/Kassena_Nankana_West_Districthttps://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_Districthttps://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_Municipalhttps://en.wikipedia.org/w/index.php?title=Jirapa_Municipal&offset=&limit=5000&action=history
Lambussie Karni/wiki/Lambussie_Karni_Districthttps://en.wikipedia.org/w/index.php?title=Lambussie_Karni_District&offset=&limit=5000&action=history
Lawra Municipal/wiki/Lawra_Districthttps://en.wikipedia.org/w/index.php?title=Lawra_District&offset=&limit=5000&action=history
Nadowli Kaleo/wiki/Nadowli_Districthttps://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=1https://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_Districthttps://en.wikipedia.org/w/index.php?title=Sissala_West_District&offset=&limit=5000&action=history
Wa East/wiki/Wa_East_Districthttps://en.wikipedia.org/w/index.php?title=Wa_East_District&offset=&limit=5000&action=history
Wa Municipal/wiki/Wa_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Wa_Municipal_District&offset=&limit=5000&action=history
Wa West/wiki/Wa_West_Districthttps://en.wikipedia.org/w/index.php?title=Wa_West_District&offset=&limit=5000&action=history
Adaklu District/wiki/Adaklu_Districthttps://en.wikipedia.org/w/index.php?title=Adaklu_District&offset=&limit=5000&action=history
Afadzato South/wiki/Afadzato_South_Districthttps://en.wikipedia.org/w/index.php?title=Afadzato_South_District&offset=&limit=5000&action=history
Agotime Ziope/wiki/Agotime_Ziope_Districthttps://en.wikipedia.org/w/index.php?title=Agotime_Ziope_District&offset=&limit=5000&action=history
Akatsi North/wiki/Akatsi_North_Districthttps://en.wikipedia.org/w/index.php?title=Akatsi_North_District&offset=&limit=5000&action=history
Akatsi South/wiki/Akatsi_South_Districthttps://en.wikipedia.org/w/index.php?title=Akatsi_South_District&offset=&limit=5000&action=history
Anloga/wiki/Anloga_Districthttps://en.wikipedia.org/w/index.php?title=Anloga_District&offset=&limit=5000&action=history
Central Tongu/wiki/Central_Tongu_Districthttps://en.wikipedia.org/w/index.php?title=Central_Tongu_District&offset=&limit=5000&action=history
Ho Municipal/wiki/Ho_Municipalhttps://en.wikipedia.org/w/index.php?title=Ho_Municipal&offset=&limit=5000&action=history
Ho West/wiki/Ho_West_Districthttps://en.wikipedia.org/w/index.php?title=Ho_West_District&offset=&limit=5000&action=history
Hohoe Municipal/wiki/Hohoe_Municipalhttps://en.wikipedia.org/w/index.php?title=Hohoe_Municipal&offset=&limit=5000&action=history
Keta Municipal/wiki/Keta_Municipalhttps://en.wikipedia.org/w/index.php?title=Keta_Municipal&offset=&limit=5000&action=history
Ketu North Municipal/wiki/Ketu_North_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Ketu_North_Municipal_District&offset=&limit=5000&action=history
Ketu South Municipal/wiki/Ketu_South_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Ketu_South_Municipal_District&offset=&limit=5000&action=history
Kpando Municipal/wiki/Kpando_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Kpando_Municipal_District&offset=&limit=5000&action=history
North Dayi/wiki/North_Dayi_Districthttps://en.wikipedia.org/w/index.php?title=North_Dayi_District&offset=&limit=5000&action=history
North Tongu/wiki/North_Tongu_Districthttps://en.wikipedia.org/w/index.php?title=North_Tongu_District&offset=&limit=5000&action=history
South Dayi/wiki/South_Dayi_Districthttps://en.wikipedia.org/w/index.php?title=South_Dayi_District&offset=&limit=5000&action=history
South Tongu/wiki/South_Tongu_Districthttps://en.wikipedia.org/w/index.php?title=South_Tongu_District&offset=&limit=5000&action=history
Ahanta West/wiki/Ahanta_West_Districthttps://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_Districthttps://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=1https://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_Districthttps://en.wikipedia.org/w/index.php?title=Ellembelle_District&offset=&limit=5000&action=history
Jomoro/wiki/Jomoro_Districthttps://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_Districthttps://en.wikipedia.org/w/index.php?title=Nzema_East_Municipal_District&offset=&limit=5000&action=history
Prestea-Huni Valley Municipal/wiki/Prestea-Huni_Valley_Districthttps://en.wikipedia.org/w/index.php?title=Prestea-Huni_Valley_District&offset=&limit=5000&action=history
Sekondi Takoradi Metropolitan/wiki/Sekondi_Takoradi_Metropolitan_Assemblyhttps://en.wikipedia.org/w/index.php?title=Sekondi_Takoradi_Metropolitan_Assembly&offset=&limit=5000&action=history
Shama/wiki/Shama_Districthttps://en.wikipedia.org/w/index.php?title=Shama_District&offset=&limit=5000&action=history
Tarkwa-Nsuaem Municipal/wiki/Tarkwa-Nsuaem_Municipal_Districthttps://en.wikipedia.org/w/index.php?title=Tarkwa-Nsuaem_Municipal_District&offset=&limit=5000&action=history
Wassa Amenfi East/wiki/Wassa_Amenfi_East_Districthttps://en.wikipedia.org/w/index.php?title=Wassa_Amenfi_East_District&offset=&limit=5000&action=history
Wassa East/wiki/Wassa_East_Districthttps://en.wikipedia.org/w/index.php?title=Wassa_East_District&offset=&limit=5000&action=history
Aowin/wiki/Aowin/Suaman_Districthttps://en.wikipedia.org/w/index.php?title=Aowin/Suaman_District&offset=&limit=5000&action=history
Bia East/wiki/Bia_East_Districthttps://en.wikipedia.org/w/index.php?title=Bia_East_District&offset=&limit=5000&action=history
Bia West/wiki/Bia_West_Districthttps://en.wikipedia.org/w/index.php?title=Bia_West_District&offset=&limit=5000&action=history
Bibiani Anhwiaso Bekwai/wiki/Bibiani/Anhwiaso/Bekwai_Districthttps://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_Districthttps://en.wikipedia.org/w/index.php?title=Sefwi_Akontombra_District&offset=&limit=5000&action=history
Sefwi-Wiawso Municipal/wiki/Sefwi-Wiawso_Municipal_Districthttps://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 to https://en.wikipedia.org/wiki/Tano_South_Municipal_District. However, if you go to the edits history of https://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
districtfirst_date
Ablekuma CentralNA
Ablekuma NorthNA
Ablekuma WestNA
Abuakwa North MunicipalNA
Abura/Asebu/Kwamankese District2006-02-20 16:26:00
Accra Metropolitan District2006-02-20 19:05:00
Achiase District2020-07-08 20:45:00
Ada East District2017-11-15 11:16:00
Ada West District2017-11-15 11:28:00
Adaklu District2013-05-12 20:09:00
Adansi AsokwaNA
Adansi North District2006-02-21 14:33:00
Adansi South District2006-02-21 14:41:00
Adenta Municipal District2011-04-25 14:28:00
Afadzato South District2015-06-14 12:06:00
Afigya Kwabre District2011-04-25 15:42:00
Afigya Kwabre NorthNA
Agona East District2011-04-25 14:51:00
Agona West Municipal District2011-04-25 21:03:00
Agotime Ziope District2018-04-28 16:08:00
Ahafo Ano North Municipal District2006-02-20 19:06:00
Ahafo Ano South District2006-02-20 19:06:00
Ahafo Ano South East DistrictNA
Ahanta West District2006-02-20 19:09:00
Ajumako/Enyan/Essiam District2006-02-20 19:10:00
Akatsi North District2013-08-01 13:01:00
Akatsi South District2013-10-10 14:46:00
AkrofuomNA
Akuapim North Municipal District2006-02-20 19:12:00
Akuapim South Municipal District2006-02-20 19:12:00
Akyemansa District2011-04-25 14:39:00
Amansie Central District2006-02-21 14:43:00
Amansie SouthNA
Amansie West District2006-02-20 19:14:00
Anloga District2020-07-21 01:32:00
Aowin/Suaman District2006-02-20 19:14:00
Asante Akim Central Municipal District2018-03-10 13:58:00
Asante Akim North District2009-08-18 01:51:00
Asante Akim South Municipal District2006-02-20 19:15:00
Asene Manso AkrosoNA
Ashaiman Municipal2011-04-25 14:30:00
Asikuma/Odoben/Brakwa District2006-02-20 19:16:00
Asokore Mampong (municipal district)2018-06-08 23:36:00
Asokwa MunicipalNA
Assin Central MunicipalNA
Assin North Municipal District2011-04-25 21:18:00
Assin South District2007-02-24 23:57:00
Asunafo North Municipal District2011-04-25 19:00:00
Asunafo South District2006-02-22 09:28:00
Asuogyaman District2006-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 District2006-02-20 19:18:00
Atiwa East District2019-01-29 18:05:00
Atiwa West District2019-02-15 18:10:00
Atwima Kwanwoma District2011-04-25 15:43:00
Atwima Mponua District2006-02-21 14:44:00
Atwima Nwabiagya Municipal District2006-02-21 15:08:00
Atwima Nwabiagya NorthNA
Awutu Senya East (municipal district)2018-06-08 23:36:00
Awutu Senya West (district)2018-06-08 23:36:00
Ayawaso Central Municipal District2020-12-31 22:30:00
Ayawaso EastNA
Ayawaso North Municipal District2019-02-15 18:14:00
Ayawaso WestNA
Ayensuano (district)2018-06-08 23:36:00
Banda District, Ghana2015-03-19 12:05:00
Bawku Municipal District2007-02-25 00:37:00
Bawku West District2007-02-25 00:37:00
Bekwai Municipal Assembly2006-02-20 19:13:00
Berekum East Municipal District2011-04-25 19:03:00
Berekum West District2020-12-30 02:07:00
Bia East District2014-05-03 09:39:00
Bia West District2014-05-01 11:34:00
Biakoye District2009-08-14 16:57:00
Bibiani/Anhwiaso/Bekwai District2007-02-25 00:50:00
Binduri (district)2018-06-08 23:36:00
Birim Central Municipal District2010-09-05 01:58:00
Birim North District2007-02-25 00:00:00
Birim South District2006-02-20 19:46:00
Bodi (district)2018-06-08 23:36:00
Bole District2006-02-07 03:29:00
Bolgatanga East District2020-02-03 20:26:00
Bolgatanga Municipal District2006-02-20 19:49:00
Bongo District2006-02-12 18:23:00
Bosome Freho District2011-04-25 15:43:00
Bosomtwe District2006-02-21 14:49:00
Builsa North District2006-02-20 19:49:00
Builsa South (district)2018-06-08 23:36:00
Bunkpurugu NyankpanduriNA
Cape Coast Metropolitan Assembly2011-04-25 21:07:00
Central Gonja District2007-02-25 00:31:00
Central Tongu District2018-03-02 11:28:00
Chereponi District2011-04-25 15:11:00
Daffiama Bussie Issa (district)2018-06-08 23:36:00
Denkyembour2018-06-08 23:36:00
Dormaa Central MunicipalNA
Dormaa East District2011-04-25 15:04:00
Dormaa West (district)2018-06-08 23:36:00
East Akim Municipal District2006-02-20 19:51:00
East Gonja Municipal District2006-02-20 19:51:00
East Mamprusi Municipal Assembly2006-02-20 19:52:00
Effia Kwesimintsim MunicipalNA
Effutu Municipal District2011-04-25 21:10:00
Ejisu-Juaben Municipal District2006-02-20 19:52:00
Ejura Sekyedumase Municipal District2006-02-20 19:53:00
Ekumfi District2017-12-22 12:29:00
Ellembelle District2011-04-25 12:25:00
Fanteakwa District2006-02-20 19:53:00
Fanteakwa SouthNA
Ga Central Municipal District2013-10-17 12:51:00
Ga East Municipal District2011-04-25 20:53:00
Ga North Municipal District2019-02-15 18:16:00
Ga South Municipal District2011-04-25 14:32:00
Ga West Municipal District2011-04-25 20:55:00
Garu District2007-02-25 00:38:00
Gomoa CentralNA
Gomoa East District2011-04-25 21:12:00
Gomoa West District2011-04-25 21:14:00
Gushegu District2007-02-25 00:31:00
Ho Municipal2006-02-20 20:46:00
Ho West District2018-04-28 16:22:00
Hohoe Municipal2006-02-20 20:47:00
Jaman North District2006-02-22 08:31:00
Jaman South Municipal District2006-02-22 08:31:00
Jasikan District2006-02-20 20:48:00
Jirapa Municipal2011-04-25 13:43:00
Jomoro District2006-02-20 20:50:00
Juaben MunicipalNA
Juaboso (district)2018-06-08 23:36:00
Kadjebi District2006-02-20 20:52:00
Karaga District2007-02-25 00:32:00
Kassena Nankana East District2011-04-25 15:29:00
Kassena Nankana West District2011-04-25 15:25:00
Keta Municipal2006-02-20 20:54:00
Ketu North Municipal District2009-08-14 12:49:00
Ketu South Municipal District2014-04-27 18:34:00
Kintampo North Municipal District2011-04-25 19:06:00
Kintampo South District2006-02-22 08:54:00
Komenda/Edina/Eguafo/Abirem Municipal District2006-02-20 21:01:00
Korle KlotteyNA
Kpandai District2011-04-25 15:33:00
Kpando Municipal District2006-02-20 21:02:00
Kpone Katamanso Municipal District2019-02-15 18:16:00
Krachi East Municipal District2006-09-29 13:55:00
Krachi Nchumuru (district)2018-06-08 23:36:00
Krachi West District2006-02-20 21:03:00
KroworNA
Kumasi Metropolitan Assembly2006-02-20 21:05:00
Kumbungu District2015-04-10 15:37:00
Kwabre East Municipal District2021-01-01 19:41:00
Kwadaso MunicipalNA
Kwaebibirem Municipal District2006-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 District2009-01-27 11:54:00
Kwahu South District2006-02-20 21:08:00
Kwahu West Municipal District2011-04-26 19:30:00
La Dade Kotopon Municipal District2017-11-03 18:26:00
La Nkwantanang Madina Municipal District2017-12-31 20:51:00
Lambussie Karni District2011-04-25 13:44:00
Lawra District2006-02-20 21:08:00
LedzokukuNA
Lower Manya Krobo Municipal District2011-04-26 19:32:00
Mampong Municipal District2006-02-20 21:41:00
Mamprugu Moagduri District2015-04-10 21:27:00
Mfantsiman Municipal District2010-12-28 02:33:00
Mion District2015-04-10 21:14:00
Mpohor (district)2018-06-08 23:36:00
Nabdam (district)2018-06-08 23:36:00
Nadowli District2006-02-20 21:12:00
Nandom (district)2018-06-08 23:36:00
Nanton District2019-02-15 18:18:00
Nanumba North MunicipalNA
Nanumba South District2007-02-25 00:32:00
New Juaben Municipal District2006-02-20 21:13:00
New Juaben North Municipal Assembly2020-01-11 14:52:00
Ningo Prampram District2017-12-31 20:28:00
Nkoranza North District2011-04-25 15:02:00
Nkoranza South Municipal District2011-04-25 19:07:00
Nkwanta North District2009-10-10 08:28:00
Nkwanta South Municipal District2006-02-20 21:18:00
North Dayi District2018-04-25 23:07:00
North East Gonja District2015-04-10 17:47:00
North Gonja (district)2018-06-08 23:36:00
North Tongu District2006-02-20 21:19:00
Nsawam Adoagyire (municipal district)2018-06-08 23:36:00
Nzema East Municipal District2011-04-25 12:49:00
Obuasi EastNA
Obuasi Municipal District2006-02-21 14:52:00
Offinso Municipal District2006-02-20 21:22:00
Offinso North District2011-04-25 15:43:00
OforikromNA
Okaikwei NorthNA
OkereNA
Old TafoNA
Prestea-Huni Valley District2011-04-25 12:56:00
Pru East District2021-01-11 13:58:00
Pru West District2021-01-10 01:51:00
Pusiga (district)2018-06-08 23:36:00
Saboba District2015-04-10 20:53:00
Sagnarigu District2015-04-10 15:15:00
Savelugu-Nanton District2006-02-20 21:25:00
Sawla-Tuna-Kalba District2007-02-25 00:32:00
Sefwi-Wiawso Municipal District2006-02-20 21:37:00
Sefwi Akontombra District2011-04-25 13:06:00
Sekondi Takoradi Metropolitan Assembly2011-08-11 09:49:00
Sekyere Afram Plains District2011-04-25 15:44:00
Sekyere Central District2011-04-25 15:43:00
Sekyere East District2006-02-20 21:38:00
Sekyere Kumawu (district)2018-06-08 23:36:00
Sekyere South District2006-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 District2015-02-14 15:58:00
Shama District2011-04-25 13:08:00
Sissala East MunicipalNA
Sissala West District2007-02-25 00:44:00
South Dayi District2006-08-29 02:51:00
South Tongu District2006-02-20 21:48:00
Suaman (district)2018-06-08 23:36:00
SuameNA
Suhum MunicipalNA
Sunyani Municipal District2012-06-15 07:50:00
Sunyani West District2011-04-25 14:56:00
Tain District2006-02-22 08:22:00
Talensi (district)2018-06-08 23:36:00
Tamale Metropolitan District2006-02-20 21:51:00
Tano North Municipal District2006-02-28 12:40:00
Tano South Municipal District2006-02-28 12:40:00
Tarkwa-Nsuaem Municipal District2011-04-25 09:12:00
Tatale Sangule District2015-04-10 18:18:00
Techiman Municipal District2006-02-20 21:51:00
Techiman North District2015-01-31 15:47:00
Tema Metropolitan District2006-02-20 21:52:00
Tema WestNA
Tempane District2020-02-03 20:36:00
Twifo-Ati Morkwa (district)2018-06-08 23:36:00
Twifo/Heman/Lower Denkyira District2007-02-24 23:57:00
Upper Denkyira East Municipal District2011-04-25 21:16:00
Upper Denkyira West District2011-04-25 14:43:00
Upper Manya Krobo District2011-04-25 14:37:00
Upper West Akim (district)2018-06-08 23:36:00
Wa East District2007-02-25 00:44:00
Wa Municipal District2007-02-25 00:44:00
Wa West District2007-02-25 00:44:00
Wasa Amenfi East District2007-02-25 00:50:00
Wasa Amenfi West District2007-02-25 00:50:00
Wassa Amenfi Central (district)2018-06-08 23:36:00
Wassa East District2006-02-20 21:11:00
Weija GbaweNA
Wenchi Municipal District2010-02-15 09:50:00
West Akim Municipal District2006-02-21 12:51:00
West Gonja Municipal District2006-02-21 12:51:00
West Mamprusi Municipal Assembly2006-02-21 12:52:00
Yendi Municipal District2011-04-26 19:33:00
Yilo Krobo Municipal District2006-02-21 12:53:00
Yunyoo-NasuanNA
Zabzugu District2015-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")
districtyear_reportnlast_entrynet_words_addedfirst_datequant_nquant_net_words_addedmergerrwsclsclrs
Offinso Municipal District2018628102006-02-20 21:22:00535-353#595367
Mpohor (district)2015NANANA2018-06-08 23:36:00NANANA-NANANA#f5f5f5
Bosomtwe District2019NANANA2006-02-21 14:49:00NANANA-NANANA#f5f5f5
Mfantsiman Municipal District2015NANANA2010-12-28 02:33:00NANANA-NANANA#f5f5f5
Tatale Sangule District2016NANANA2015-04-10 18:18:00NANANA-NANANA#f5f5f5
Birim South District200952072006-02-20 19:46:00444-444#915C5C
Techiman Municipal District20212118422006-02-20 21:51:00353-535#BA4E49
West Akim Municipal District2012625-412006-02-21 12:51:00515-151#2A5676
Atiwa West District2015NANANA2019-02-15 18:10:00NANANA-NANANA#f5f5f5
Komenda/Edina/Eguafo/Abirem Municipal District201442302006-02-20 21:01:00424-242#6F6F79
Afadzato South District2006NANANA2015-06-14 12:06:00NANANA-NANANA#f5f5f5
East Mamprusi Municipal Assembly2006313132006-02-20 19:52:00343-434#B16658
Dormaa Central Municipal2012NANANANANANANA-NANANA#f5f5f5
Mpohor (district)2016NANANA2018-06-08 23:36:00NANANA-NANANA#f5f5f5
Awutu Senya West (district)2012NANANA2018-06-08 23:36:00NANANA-NANANA#f5f5f5
Berekum West District2010NANANA2020-12-30 02:07:00NANANA-NANANA#f5f5f5
North East Gonja District2009NANANA2015-04-10 17:47:00NANANA-NANANA#f5f5f5
Asokwa Municipal2016NANANANANANANA-NANANA#f5f5f5
Adansi North District2019NANANA2006-02-21 14:33:00NANANA-NANANA#f5f5f5
Yendi Municipal District2010NANANA2011-04-26 19:33:00NANANA-NANANA#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:

Ghana Data Stuff
Ghana Data Stuff

This website is my hobby project to showcase some of the project I am working one, when I am not working on the official statistics at the Ghana Statistical Service.

Related