This vignette shows how to replicate and extend the charts in chapter 2 of my book Non-democratic Politics: Authoritarianism, Dictatorships, and Democratization (Palgrave Macmillan, 2016). It assumes that you have downloaded the replication package as follows:
if(!require(devtools)) { install.packages("devtools") } devtools::install_github('xmarquez/AuthoritarianismBook')
It also assumes you have the dplyr
, ggplot2
, scales
, forcats
, and knitr
packages installed:
if(!require(dplyr)) { install.packages("dplyr") } if(!require(ggplot2)) { install.packages("ggplot2") } if(!require(scales)) { install.packages("forcats") } if(!require(forcats)) { install.packages("scales") } if(!require(knitr)) { install.packages("knitr") }
knitr::opts_chunk$set(fig.height = 7, fig.width = 7)
This figure shows the proportion of the world's population living under a constitution claiming to be democratic. The data on mentions of democracy in constitutions is from texts gatherd by the Comparative Constitutions Project, with mentions extracted by me and put in the approrpiate format; population data is from @Gleditsch2010 and the World Bank.
library(AuthoritarianismBook) library(dplyr) library(ggplot2) library(forcats) data <- left_join(democracy_mentions_yearly , population_data %>% select(-cown:-in_system)) %>% mutate(has_mention_na = ifelse(!has_constitution, "No constitution", ifelse(has_mention, "Yes", "No")), has_mention_na = fct_relevel(has_mention_na, "No constitution")) ggplot(data = data %>% filter(year > 1815), aes(x=year,fill = has_mention_na, weight = prop)) + geom_bar(width=1) + theme_bw() + theme(legend.position = "bottom") + labs(fill = "Does the constitution mention democracy?", x = "Year", y = "Percent of the world's population\nliving in independent states") + guides(fill = guide_legend(title.position = "top")) + scale_y_continuous(breaks = seq(from=0, to=1,by=0.1), label = scales::percent)
We can visualize all mentions of democracy in every country:
data <- democracy_mentions_yearly %>% mutate(constitutional.event = fct_lump(constitutional.event, 2)) %>% group_by(country_name) %>% mutate(year_first_mention = ifelse(any(has_mention), min(year[ has_mention ]), NA), year_first_mention = ifelse(year_first_mention == year, year_first_mention, NA)) %>% ungroup() ggplot(data = data %>% filter(in_system), aes(x=fct_rev(reorder(country_name,year,FUN = min)), y = year)) + geom_tile(aes(fill = has_mention)) + geom_point(aes(shape = constitutional.event), alpha = 0.3) + geom_text(aes(y = year_first_mention, label = year_first_mention), check_overlap = TRUE, size = 2) + coord_flip() + labs(x = "", shape = "Constitutional\nevent", fill = "Does it mention democracy?") + theme_bw() + theme(legend.position = "top") + guides(fill = guide_legend(title.position = "top"), shape = guide_legend(title.position = "top"))
This figure shows the number of states with democratic and non-democractic regimes. Democracy data is from Pemstein, Meserve, and Melton [@Pemstein2010], extended by the author to the 19th century and transformed to a probability scale [@Marquez2016]. Values close to one indicate that the country is almost certainly a democracy according to current scholarly standards, values close to zero that it is almost certainly not a democracy, and values in between that the regime may have characteristics of both democracy and non-democracy, and as a result there is disagreement among scholars as to how democratic the regime is, or whether it is democratic.
data <- extended_uds %>% filter(in_system) %>% mutate(category = cut(index, breaks = c(0,0.2,0.4,0.6,0.8,1), labels = c("0-0.2, clearly undemocratic", "0.2-0.4", "0.4-0.6, hybrid or ambiguous", "0.6-0.8", "0.8-1, clearly democratic"), include.lowest = TRUE)) ggplot(data = data, aes(x=year, fill = category)) + geom_bar(width=1) + theme_bw() + theme(legend.position = "bottom") + labs(fill = "Democracy score \n(extended Unified Democracy Scores, probability scale)", x = "Year", y = "Number of independent states\nin the international system") + guides(fill = guide_legend(title.position = "top", nrow = 2)) + scale_fill_brewer(type = "div", palette = "RdBu")
Since the number of states in the international system varies over time, it might also be useful to visualize the same information as a proportion of the number of states in the international system. (The actual membership of the "system of states" is contentious; see @Gleditsch1999, as well as the vignette on "State system membership"):
ggplot(data = data, aes(x=year, fill = category)) + geom_bar(width=1, position = "fill") + theme_bw() + theme(legend.position = "bottom") + labs(fill = "Democracy score \n(extended Unified Democracy Scores, probability scale)", x = "Year", y = "Proportion of independent states\nin the international system") + guides(fill = guide_legend(title.position = "top", nrow = 2)) + scale_fill_brewer(type = "div", palette = "RdBu") + scale_y_continuous(labels = scales::percent)
Since states vary in population, it is also useful to visualize the same data weighted by population:
data <- left_join(data, population_data %>% select(country_name, GWn, year, prop)) ggplot(data = data, aes(x=year, fill = category, weight = prop)) + geom_bar(width=1) + theme_bw() + theme(legend.position = "bottom") + labs(fill = "Democracy score \n(extended Unified Democracy Scores, probability scale)", x = "Year", y = "Population of states\nin the international system") + guides(fill = guide_legend(title.position = "top", nrow = 2)) + scale_fill_brewer(type = "div", palette = "RdBu")
It is also possible to visualize this data for each country in the dataset separately, including for periods when they are not in the international system:
data <- extended_uds %>% mutate(country_name = fct_rev(reorder(as.factor(country_name), year, FUN = min))) ggplot(data = data, aes(x = country_name, y = year)) + geom_point(data = data, aes(color = index, size = in_system), shape = 15) + scale_color_gradient2(midpoint = 0.5) + coord_flip() + labs(x = "", color = "UD Score", size = "In system of states") + theme(legend.position = "top") + scale_size_discrete(range = c(1,3)) + scale_y_continuous(breaks = unique(c(data$year[ data$year %% 25 == 0], max(data$year), min(data$year))))
Figure 2.3 uses data from Google Ngrams. Run the same query here.
Figure 2.4 uses the PIPE dataset [@Przeworski2013]. Some countries with franchise rules set at the sub-national level (e.g., the USA in the 19th century) are excluded.
data <- PIPE %>% filter(!is.na(f_simple)) ggplot(data = data, aes(x=year, fill=f_simple)) + geom_bar(width=1) + theme_bw()+ theme(legend.position="bottom") + labs(fill="Type of franchise", x="Year", y= "Number of states") + guides(fill=guide_legend(nrow=3,title.position="top")) + scale_fill_brewer(type = "div", palette = "RdBu")
It is possible to use the information in the PIPE dataset to produce a disaggregated look at franchise rules in every country in the world. The figure below shows these restrictions, along with the date where the country first arrived at "universal" suffrage, if any (countries at the top achieved universal sudffrage earlier):
data <- PIPE %>% group_by(country_name) %>% arrange(year) %>% mutate(total_elections = preselec + legelec, total_elections = ifelse(is.na(total_elections) & !is.na(f), 0, total_elections)) %>% filter(!is.na(total_elections)) %>% mutate(cumulative_elections = cumsum(total_elections), f = ifelse(max(cumulative_elections) == 0 & is.na(f), 0, f)) %>% ungroup() %>% mutate(f_male = ifelse(f < 10, f, round(f/10)), f_female = ifelse(f < 10, 0, f %% 10), f_male = ifelse(f_male %in% c(0,1), f_male, f_male + 1), f_male = ifelse(is.na(f_male) & (cumulative_elections >= 1), 2, f_male), f_female = ifelse(f_male == 2, 0, f_female), f_female = factor(f_female, labels = c("0-No inclusion / not indicated", "1-Narrower than men", "2-Equal to men")), f_male = factor(f_male, labels = c("0-No suffrage", "1-Estate", "2-Subnational", "3-Property only", "4-(Property OR income OR taxes OR exercise of profession OR educational titles) AND literacy", "5-Property OR income OR taxes OR exercise of profession OR educational titles", "6-Literacy only OR (Literacy OR property OR income OR taxes OR exercise of profession OR educational titles)", "7-All the economically independent", "8-All"), ordered = TRUE)) %>% group_by(country_name) %>% mutate(year_universal = min(year[ f == 72 ], na.rm = TRUE), year_universal = ifelse(year_universal == year, year_universal, NA)) %>% ungroup() ggplot(data = data, aes(x = fct_rev(reorder(country_name, year_universal, FUN = min, na.rm = TRUE)), y = year)) + geom_tile(aes(fill = f_male, alpha = f_female)) + geom_text(aes(label = year_universal, y = year_universal), size = 2, check_overlap = TRUE) + scale_fill_brewer(type = "div", palette = "RdBu") + labs(x = "", alpha = "Female inclusion", fill = "Type of franchise") + theme_bw() + theme(legend.position = "top") + guides(fill = guide_legend(title.position = "top", ncol = 1), alpha = guide_legend(title.position = "top", ncol = 2)) + scale_y_continuous(breaks = unique(c(PIPE$year[ PIPE$year %% 25 == 0], max(PIPE$year), min(PIPE$year)))) + scale_alpha_discrete(range = c(0.3,1)) + coord_flip()
Figure 2.5 uses the LIED dataset [@SkaaningGerring2015], which extends and corrects the PIPE dataset. It is worth noting that LIED is inconsistent with PIPE for the following country-years:
data <- full_join(PIPE %>% select(country_name,GWn,year,f_simple,f), lied %>% select(country_name,GWn,year,male_suffrage,female_suffrage)) %>% mutate(inconsistent = (male_suffrage == 1 & female_suffrage == 1 & f != 72) | (male_suffrage == 1 & female_suffrage == 0 & !(f %in% c(7,71,NA)))) data %>% filter(inconsistent) %>% group_by(country_name, f_simple, f, male_suffrage, female_suffrage) %>% summarise(min_year = min(year), max_year = max(year), num_years = n()) %>% knitr::kable(col.names = c("Country", "PIPE franchise (simplified)", "PIPE franchise (full)", "LIED male suffrage", "LIED female suffrage", "Min year", "Max year", "Num. years"))
To recreate the figure, we join the LIED data with the population data from Gleditsch [@Gleditsch2010], extended with World Bank data:
data <- left_join(lied, population_data %>% select(country_name:prop)) data <- data %>% mutate(regime2 = ifelse(lexical_index == 0 & male_suffrage == 1 & female_suffrage == 0, "2 No elections, but constitutional male suffrage", (ifelse(lexical_index == 0 & male_suffrage == 0, "1 No elections or provisions for suffrage", as.character(regime)))), regime2 = ifelse(lexical_index == 0 & male_suffrage == 1 & female_suffrage == 1, "3 No elections, but constitutional universal suffrage", as.character(regime2)), regime2 = ifelse(lexical_index > 0 & male_suffrage == 0, "4 Elections with class-limited suffrage", regime2), regime2 = ifelse(lexical_index > 0 & male_suffrage == 1 & female_suffrage == 1 & lexical_index < 6, "6 Limited competition elections with universal suffrage", regime2), regime2 = ifelse(lexical_index > 0 & male_suffrage == 1 & female_suffrage == 0 & lexical_index < 6, "5 Limited competition elections with full male suffrage", regime2), regime2 = ifelse(regime == "Male democracy", "7 Competitive elections with full male suffrage", regime2), regime2 = ifelse(regime == "Electoral democracy", "8 Competitive elections with universal suffrage", regime2)) %>% filter(year > 1815) ggplot(data = data, aes(x=year, fill = regime2, weight = prop)) + geom_bar(width=1) + theme_bw()+ theme(legend.position="bottom") + labs(fill="", x="Year", y= "Proportion of the world's population") + guides(fill=guide_legend(ncol=1,title.position="top")) + scale_fill_brewer(type = "div", palette = "RdBu") + scale_y_continuous(label=scales::percent)
As in other figures, we can visualize the data by looking at it in terms of the number of states in the international system:
ggplot(data = data, aes(x=year, fill = regime2)) + geom_bar(width=1) + theme_bw()+ theme(legend.position="bottom") + labs(fill="", x="Year", y= "Number of states") + guides(fill=guide_legend(ncol=1,title.position="top")) + scale_fill_brewer(type = "div", palette = "RdBu")
Or we can visualize it in terms of the proportion of states in the international system:
ggplot(data = data, aes(x=year, fill = regime2)) + geom_bar(width = 1, position = "fill") + theme_bw()+ theme(legend.position="bottom") + labs(fill="", x="Year", y= "Proportion of states in the international system") + guides(fill = guide_legend(ncol = 1, title.position = "top")) + scale_fill_brewer(type = "div", palette = "RdBu") + scale_y_continuous(label=scales::percent)
Or per country, ordered by earliest date of universal suffrage:
data <- data %>% filter(!is.na(regime2)) %>% group_by(country_name) %>% mutate(universal_suffrage_date = ifelse(male_suffrage + female_suffrage == 2, min(year[ male_suffrage + female_suffrage == 2 ]), NA), universal_suffrage_date = ifelse(universal_suffrage_date == year, universal_suffrage_date, NA)) %>% ungroup() ggplot(data = data, aes(x = fct_rev(reorder(as.factor(country_name), universal_suffrage_date, FUN = min, na.rm = TRUE)), y = year)) + geom_tile(data = data, aes(fill = regime2)) + geom_text(aes(label = universal_suffrage_date, y = universal_suffrage_date), size = 2, check_overlap = TRUE) + theme_bw() + scale_fill_brewer(type = "div", palette = "RdBu") + coord_flip() + labs(x = "", fill = "Type of franchise") + theme(legend.position = "top") + guides(fill = guide_legend(ncol = 1, title.position="top"))
Note that the first date of universal suffrage differs between PIPE and LIED: LIED gives Australia as the first country to have universal suffrage, whereas PIPE gives New Zealand. This is because LIED has more stringent vcriteria for when a country enters the international system (counts as "independent"); by their criteria, New Zealand is not an independent country until 1907. See the vignette on "State system membership" for more discussion of these differences.
This figure uses the Polity IV data on executive recruitment [@Marshall2010], excluding periods of anarchy, transition, foreign occupation, and executive-led transition.
polity_annual$exrec2 <- plyr::mapvalues(polity_annual$exrec, from = sort(unique(polity_annual$exrec)), to = c(NA, NA, NA, "1-Hereditary", "2-Hereditary plus narrow elite", "4-Narrow elite selection", "5-Self-selection (coup or successful rebellion)", NA, "3-Hereditary plus election", "6-Election", "6-Election")) data <- polity_annual ggplot(data = data, aes(x= year, fill= exrec2) )+ geom_bar(width=1) + theme_bw() + theme(legend.position="bottom") + labs(fill="", x="Year", y= "Number of states") + guides(fill = guide_legend(ncol = 1, title.position="top")) + scale_fill_brewer(type = "div", palette = "RdBu")
As usual, we can visualize this data as a proportion of the number of states in the dataset (not identical to the number of states in the world system, since Polity does not count all states):
ggplot(data = data, aes(x= year, fill= exrec2) )+ geom_bar(width=1, position = "fill") + theme_bw() + theme(legend.position="bottom") + labs(fill="", x="Year", y= "Proportion of states") + guides(fill = guide_legend(ncol = 1, title.position="top")) + scale_fill_brewer(type = "div", palette = "RdBu") + scale_y_continuous(labels = scales::percent)
Or weighted by population:
data <- left_join(data, population_data %>% select(country_name:prop)) ggplot(data = data, aes(x= year, fill= exrec2, weight = prop))+ geom_bar(width=1) + theme_bw() + theme(legend.position="bottom") + labs(fill="", x="Year", y= "Proportion of world's population") + guides(fill = guide_legend(ncol = 1, title.position="top")) + scale_fill_brewer(type = "div", palette = "RdBu") + scale_y_continuous(labels = scales::percent)
And we can disaggregate it per country:
ggplot(data = data, aes(x = fct_rev(reorder(as.factor(country_name), year, FUN = min)), y = year)) + geom_tile(data = data, aes(fill = exrec2)) + theme_bw() + scale_fill_brewer(type = "div", palette = "RdBu") + coord_flip() + labs(x = "", fill = "Executive selection type") + theme(legend.position = "top") + guides(fill = guide_legend(ncol = 1, title.position="top"))
The data on democracy for this figure is from Pemstein, Meserve, and Melton [@Pemstein2010], extended by me into the 19th century [@Marquez2016]. The exact beginning and end of each wave depends on how we measure transitions to democracy. Shaded areas indicate Huntington's own periodization of the waves of democracy.
data <- extended_uds %>% group_by(country_name) %>% mutate(change = index - lag(index)) %>% group_by(year) %>% summarise(total_trans = sum(change,na.rm=TRUE)) %>% ungroup() %>% mutate(cumulative_trans = cumsum(total_trans)) ypos <- mean(c(-1,max(data$cumulative_trans))) ggplot(data=data) + geom_rect(aes(xmin = 1828, xmax = 1926, ymin = min(cumulative_trans, na.rm=TRUE) - 1, ymax = max(cumulative_trans, na.rm=TRUE) +1), alpha = 0.02, fill="lightgrey") + geom_rect(aes(xmin = 1943, xmax = 1962, ymin = min(cumulative_trans, na.rm=TRUE) - 1, ymax = max(cumulative_trans, na.rm=TRUE) + 1), alpha = 0.02, fill="lightgrey") + geom_rect(aes(xmin = 1974, xmax = 2008, ymin = min(cumulative_trans,na.rm=TRUE) - 1, ymax = max(cumulative_trans,na.rm=TRUE) + 1), alpha=0.02, fill="lightgrey") + geom_path(aes(x = year, y = cumulative_trans)) + theme_bw() + labs(y = "Cumulative changes in the level of democracy across countries") + annotate(geom = "text", x = c(1850,1950,1990), y = c(ypos, ypos, ypos), label = c("First wave", "Second wave", "Third wave"), angle=90) + coord_cartesian(xlim = c(1800,2010), ylim = c(-1, max(data$cumulative_trans)))
The figure does not show full transitions to democracy, but tracks the overall movement upwards movement of democracy indicator. Other ways of constructing it are possible. For example, using LIED, wean construct a figure that counts only transitions to a LIED index of 4 or above:
data <- lied %>% mutate(democ = as.numeric(lexical_index >= 4)) %>% group_by(country_name) %>% mutate(change = democ - lag(democ)) %>% group_by(year) %>% summarise(total_trans = sum(change,na.rm=TRUE)) %>% ungroup() %>% mutate(cumulative_trans = cumsum(total_trans)) ypos <- mean(c(-1,max(data$cumulative_trans))) ggplot(data=data) + geom_rect(aes(xmin = 1828, xmax = 1926, ymin = min(cumulative_trans, na.rm=TRUE) - 1, ymax = max(cumulative_trans, na.rm=TRUE) +1), alpha = 0.02, fill="lightgrey") + geom_rect(aes(xmin = 1943, xmax = 1962, ymin = min(cumulative_trans, na.rm=TRUE) - 1, ymax = max(cumulative_trans, na.rm=TRUE) + 1), alpha = 0.02, fill="lightgrey") + geom_rect(aes(xmin = 1974, xmax = 2008, ymin = min(cumulative_trans,na.rm=TRUE) - 1, ymax = max(cumulative_trans,na.rm=TRUE) + 1), alpha=0.02, fill="lightgrey") + geom_path(aes(x = year, y = cumulative_trans)) + theme_bw() + labs(y = "Cumulative transitions to democracy across countries") + annotate(geom = "text", x = c(1850,1950,1990), y = c(ypos, ypos, ypos), label = c("First wave", "Second wave", "Third wave"), angle=90) + coord_cartesian(xlim = c(1800,2010), ylim = c(-1, max(data$cumulative_trans)))
Other measures give slightly different answers. Here are Huntington's waves using the Boix-Miller-Rosato measure [@BoixMillerRosato2007], included in the democracy
dataset:
data <- democracy %>% group_by(country_name) %>% mutate(change = bmr_democracy - lag(bmr_democracy)) %>% group_by(year) %>% summarise(total_trans = sum(change,na.rm=TRUE)) %>% ungroup() %>% mutate(cumulative_trans = cumsum(total_trans)) ypos <- mean(c(-1,max(data$cumulative_trans))) ggplot(data=data) + geom_rect(aes(xmin = 1828, xmax = 1926, ymin = min(cumulative_trans, na.rm=TRUE) - 1, ymax = max(cumulative_trans, na.rm=TRUE) +1), alpha = 0.02, fill="lightgrey") + geom_rect(aes(xmin = 1943, xmax = 1962, ymin = min(cumulative_trans, na.rm=TRUE) - 1, ymax = max(cumulative_trans, na.rm=TRUE) + 1), alpha = 0.02, fill="lightgrey") + geom_rect(aes(xmin = 1974, xmax = 2008, ymin = min(cumulative_trans,na.rm=TRUE) - 1, ymax = max(cumulative_trans,na.rm=TRUE) + 1), alpha=0.02, fill="lightgrey") + geom_path(aes(x = year, y = cumulative_trans)) + theme_bw() + labs(y = "Cumulative transitions to democracy across countries") + annotate(geom = "text", x = c(1850,1950,1990), y = c(ypos, ypos, ypos), label = c("First wave", "Second wave", "Third wave"), angle=90) + coord_cartesian(xlim = c(1800,2010), ylim = c(-1, max(data$cumulative_trans)))
The figure uses Polity annual data:
polity_annual$exconst2 <- plyr::mapvalues(polity_annual$exconst, from = sort(unique(polity_annual$exconst)), to = c(NA, NA, NA, "0-Unlimited", "1", "2", "3", "4", "5", "6-Executive parity or subordination")) ggplot(data=polity_annual, aes(x = year, fill = exconst2))+ geom_bar(width=1) + theme_bw()+ theme(legend.position="bottom") + labs(fill = "Constraints on the executive", x = "Year", y= "Number of independent states")+ guides(fill = guide_legend(nrow = 1, title.position="top")) + scale_fill_brewer(type = "div", palette = "RdBu")
Extensions are left as an exercise for the reader.
This figure uses data from Geddes, Wright, and Frantz [@GeddesWrightFrantz2014].
data <- all_gwf %>% mutate(gwf_simplified = ifelse(grepl("military",gwf_full_regimetype), "Non-democratic with significant military participation", ifelse(grepl("democracy", gwf_full_regimetype), "Democracy", "Other non-democratic"))) data$gwf_simplified <- forcats::fct_relevel(as.factor(data$gwf_simplified), "Non-democratic with significant military participation", "Other non-democratic") ggplot(data = data, aes(x = year, fill = gwf_simplified))+ geom_bar(width=1, position="fill") + theme_bw()+ theme(legend.position="bottom") + labs(fill = "Regime type", x = "Year", y = "Proportion of independent states with populations greater than 500,000 people") + guides(fill=guide_legend(nrow=1,title.position="top")) + scale_fill_brewer(type = "div", palette = "RdBu") + scale_y_continuous(labels = scales::percent) + guides(fill=guide_legend(ncol = 1, title.position = "top"))
We can also look at the distribution in terms of the number of actual countries:
ggplot(data = data, aes(x = year, fill = gwf_simplified))+ geom_bar(width = 1) + theme_bw()+ theme(legend.position="bottom") + labs(fill = "Regime type", x = "Year", y = "Proportion of independent states\nwith populations greater than 500,000 people") + guides(fill=guide_legend(nrow=1,title.position="top")) + scale_fill_brewer(type = "div", palette = "RdBu") + guides(fill=guide_legend(ncol = 1, title.position = "top"))
And of course we can disaggregate these numbers by state:
ggplot(data = data, aes(x = fct_rev(reorder(as.factor(country_name), year, FUN = min)), y = year)) + geom_tile(data = data, aes(fill = gwf_simplified)) + theme_bw() + coord_flip() + labs(x = "", fill = "Regime type") + theme(legend.position = "top") + guides(fill = guide_legend(ncol = 1, title.position="top")) + scale_y_continuous(breaks = unique(c(data$year[ data$year %% 10 == 0], max(data$year), min(data$year))))
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.