Introduction

This project explores how a country’s political status—categorized as Free, Partially Free, or Not Free—affects various socio-economic indicators such as life expectancy, birth rates, death rates, infant mortality, and migration. By merging data from the CIA Factbook and the Freedom dataset, we use data visualization to uncover patterns between political freedom and demographic factors. This analysis aims to highlight how political structures impact health, development, and migration trends across different regions, offering insights into the broader effects of political status on socio-economic outcomes.

Data Setup

Before conducting our analysis, we need to set up the environment by removing existing variables and loading the necessary libraries.

# Remove existing variables
rm(list = ls())

# Load required libraries
library(data.table)
library(ggplot2)

Data Acquisition

We retrieve two datasets from tidytuesday: one from the CIA Factbook, containing basic country-level statistics, and another from the Freedom dataset, which categorizes countries as Free, Partially Free, or Not Free.

# Load data from sources
cia_factbook <- readr::read_csv('https://raw.githubusercontent.com/rfordatascience/tidytuesday/main/data/2024/2024-10-22/cia_factbook.csv')
## Rows: 259 Columns: 11
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr  (1): country
## dbl (10): area, birth_rate, death_rate, infant_mortality_rate, internet_user...
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
freedom <- readr::read_csv('https://raw.githubusercontent.com/rfordatascience/tidytuesday/main/data/2022/2022-02-22/freedom.csv')
## Rows: 4979 Columns: 8
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (3): country, Status, Region_Name
## dbl (5): year, CL, PR, Region_Code, is_ldc
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Data Merging

To analyze the relationship between political status and socio-economic factors, we merge the two datasets on the common country column.

# Merge datasets
merged_data <- merge(cia_factbook, freedom, by = "country", all = FALSE)

Life Expectancy Analysis

Life expectancy is a key indicator of health and development. Here, we analyze the average life expectancy by region and political status. First we have to group the data by region and than visualize it with a bar chart.

# Aggregate data
life_expectancy_summary <- aggregate(
  life_exp_at_birth ~ Region_Name + Status, 
  data = merged_data, 
  FUN = mean, 
  na.rm = TRUE
)
print(life_expectancy_summary)
##    Region_Name Status life_exp_at_birth
## 1       Africa      F          61.13374
## 2     Americas      F          75.15067
## 3         Asia      F          75.64714
## 4       Europe      F          79.44419
## 5      Oceania      F          72.52595
## 6       Africa     NF          61.57435
## 7     Americas     NF          75.17029
## 8         Asia     NF          71.11781
## 9       Europe     NF          72.31077
## 10      Africa     PF          59.28764
## 11    Americas     PF          73.26599
## 12        Asia     PF          73.32947
## 13      Europe     PF          74.95241
## 14     Oceania     PF          72.08582
# Visualization
status_colors <- c("F" = "#fee0d2", "PF" = "#fc9272", "NF" = "#de2d26")
status_labels <- c("F" = "Free", "PF" = "Partially Free", "NF" = "Not Free")

ggplot(life_expectancy_summary, aes(x = reorder(Region_Name, life_exp_at_birth), 
                                    y = life_exp_at_birth, fill = Status)) +
  geom_bar(stat = "identity", position = position_dodge()) +
  coord_flip() + 
  scale_fill_manual(values = status_colors, labels = status_labels) + 
  geom_text(aes(label = round(life_exp_at_birth, 1)), 
            position = position_dodge(width = 0.8), hjust = -0.1, 
            color = "black", size = 3, fontface = "bold") +
  labs(title = "Average Life Expectancy by Region and Political Status",
       x = "Region", y = "Average Life Expectancy", fill = "Status") +
  theme_minimal() +
  theme(panel.grid = element_blank(), axis.text.x = element_blank()) +
  geom_hline(yintercept = 0, color = "black", size = 1)
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

Analysis: We can see that the politically free European countries have the highest average life expectancy while African countries have the lowest. In most of the regions the political status doesn’t make much difference in life expectancy. The only exception is Europe.

Birth Rate Analysis

The birth rate is another crucial demographic factor. Here, we analyze and visualize the average birth rate across different regions and political statuses.To create the visualisation we have to do the same steps as in our previous graph.

birth_rate_summary <- aggregate(
  birth_rate ~ Region_Name + Status, 
  data = merged_data, 
  FUN = mean, 
  na.rm = TRUE
)

ggplot(birth_rate_summary, aes(x = reorder(Region_Name, birth_rate), y = birth_rate, fill = Status)) +
  geom_bar(stat = "identity", position = position_dodge()) +
  scale_fill_manual(values = status_colors, labels = status_labels) +
  coord_flip() +
  geom_text(aes(label = round(birth_rate, 1)), position = position_dodge(width = 0.8), hjust = -0.1, 
            color = "black", size = 3, fontface = "bold") +
  labs(title = "Average Birth Rate by Region and Political Status",
       x = "Region", y = "Average Birth Rate", fill = "Status") +
  theme_minimal() +
  theme(plot.margin = margin(1, 2, 1, 1, "cm"), axis.text.y = element_text(size = 8),
        panel.grid = element_blank(), axis.text.x = element_blank()) +
  geom_hline(yintercept = 0, color = "black", size = 1)

Analysis: In the graph we can see that the highest birth rate is in Africa while the lowest is in Europe, although in Europe the political status have no effect on birth rate while in Africa the free countries have significantly lower birth rate on average.

Population Growth vs Birth and Death Rate Analysis

We analyze how birth and death rates impact population growth. To do that we create two scatter plots. The first one shows the birth rate vs population growth, while the second show the death rate and the population growth.

ggplot(merged_data, aes(x = birth_rate, y = population_growth_rate, color = Status)) +
  geom_point() +
  geom_smooth(method = "loess", se = FALSE, color = "black", linetype = "solid") +
  scale_color_manual(values = status_colors, labels = status_labels) +
  labs(title = "Birth Rate vs. Population Growth Rate by Political Status (LOESS)",
       x = "Birth Rate", y = "Population Growth Rate", color = "Status") +
  theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'

Analysis: We can see that there is a positive correlation with birth rate and population growth just as we expect. On the other hand we can also see that the free countries have a low birth rate and also a low population growth.

ggplot(merged_data, aes(x = death_rate, y = population_growth_rate, color = Status)) +
  geom_point() +
  geom_smooth(method = "loess", se = FALSE, color = "black", linetype = "solid") +
  scale_color_manual(values = status_colors, labels = status_labels) +
  labs(title = "Death Rate vs. Population Growth Rate by Political Status (LOESS)",
       x = "Death Rate", y = "Population Growth Rate", color = "Status") +
  theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'

Analysis: In this case we also got the result what we expected, because as the death rate rises the population growth shrinks down. In this case we cannot find any patterns in connection with the political status.

Infant Mortality Analysis

Infant mortality rate is a key health indicator that reflects a country’s healthcare quality and socio-economic conditions. Here, we analyze how it varies across different political statuses. We will visualize this first with a bar chart and than with a box plot.

# Calculate average infant mortality rate by political status (Status)
infant_mortality_summary <- aggregate(
  infant_mortality_rate ~ Status, 
  data = merged_data, 
  FUN = mean, 
  na.rm = TRUE
)

# Bar plot of infant mortality rate by Status
ggplot(infant_mortality_summary, aes(x = Status, y = infant_mortality_rate, fill = Status)) +
  geom_bar(stat = "identity") +
  geom_hline(yintercept = 0, color = "black", size = 1) +
  geom_text(aes(label = round(infant_mortality_rate, 1), 
                y = infant_mortality_rate + 2),  # Move text slightly above bars
            color = "black", size = 4, fontface = "bold") + 
  scale_fill_manual(
    values = status_colors,
    labels = status_labels
  ) +
  labs(
    title = "Average Infant Mortality Rate by Political Status",
    x = "Political Status",
    y = "Average Infant Mortality Rate"
  ) +
  theme_minimal() +
  theme(
    axis.text = element_blank(),
    axis.ticks = element_blank(),  
    panel.grid = element_blank()  
  )

Analysis: In this bar chart we can see that the infant mortality rate is significantly lower in the free countries than the not free and partially free countries, although we cannot see a big difference in the average of partially free and not free countries.

# Box plot of infant mortality rate by Status
ggplot(merged_data, aes(x = Status, y = infant_mortality_rate, fill = Status)) +
  geom_boxplot() +
  geom_hline(yintercept = 0, color = "black", size = 1) +
  scale_fill_manual(
    values = status_colors,
    labels = status_labels
  ) +
  labs(
    title = "Infant Mortality Rate Distribution by Political Status",
    x = "Political Status",
    y = "Infant Mortality Rate"
  ) +
  theme_minimal() +
  theme(
    axis.text.x = element_blank(),
    panel.grid.major.x = element_blank(),  # Remove major vertical grid lines
    panel.grid.minor.x = element_blank(),  # Remove minor vertical grid lines
    panel.grid.major.y = element_line(color = "gray80"),  # Keep major horizontal grid lines
    panel.grid.minor.y = element_blank()   # Optionally remove minor horizontal grid lines
  )
## Warning: Removed 15 rows containing non-finite outside the scale range
## (`stat_boxplot()`).

Analysis: The boxplot reveals that there is a bigger difference in the median values of not free and partially free countries although the third quartile is around three times wider than the second.

Migration Analysis

In our last analysis we analyze the migration trends by political status.

migration_summary <- aggregate(
  net_migration_rate ~ Status, 
  data = merged_data, 
  FUN = mean, 
  na.rm = TRUE
)

ggplot(migration_summary, aes(x = Status, y = net_migration_rate, fill = Status)) +
  geom_bar(stat = "identity") +
  scale_fill_manual(
    values = status_colors,
    labels = status_labels
    ) +
  geom_hline(yintercept = 0, color = "black", size = 1) +
  geom_text(aes(label = round(net_migration_rate, 2), 
                y = ifelse(net_migration_rate > 0, net_migration_rate + 0.1, net_migration_rate - 0.1)), 
            color = "black", size = 4, fontface = "bold", hjust = 0.5) +  # Add values to bars
  labs(
    title = "Average Net Migration Rate by Political Status",
    x = "Political Status",
    y = "Average Net Migration Rate"
  ) +
  theme_minimal() +
  theme(
    axis.text = element_blank(),
    axis.ticks = element_blank(),  
    panel.grid = element_blank()  
  )

Analysis: In this case the result is also what we expected, because the net migration rate is negative in free countries, in partially free countries it is positive but moderate and in the not free cathegory the net migration rate is nearly ten times higher than in the partially free group.

Conclusion

The analysis reveals that political freedom significantly affects socio-economic indicators such as life expectancy, infant mortality, and migration. Free countries tend to have higher life expectancy and lower infant mortality, while partially free and not free countries experience higher birth rates and migration. In terms of population growth, free countries have lower birth rates and slower growth, whereas higher death rates are linked to lower growth across the board. Overall, political status plays a key role in shaping health outcomes and migration trends.