diff --git a/_projects/2024/100432719/100432719.Rmd b/_projects/2024/100432719/100432719.Rmd new file mode 100644 index 00000000..0f18e4eb --- /dev/null +++ b/_projects/2024/100432719/100432719.Rmd @@ -0,0 +1,274 @@ +--- +title: "Where do 8 billion people live?" +description: "Replica and improvement of a map to show how the world population is distributed among different countries" +categories: "2024" +author: "Alba García-Vega" +date: "`r Sys.Date()`" +output: + distill::distill_article: + self_contained: false + toc: true +--- + +```{r setup, include=FALSE} +library(showtext) +knitr::opts_chunk$set(out.width="100%", fig.showtext = TRUE, fig.dpi = 150) +``` + +## Introduction + +When I was thinking about this project, I ran directly into this map: + +The first thing I thought was: *wow! A graph were my 3 disciplines merge together: sociology, international relations and, now, programming!*. So I decided to use it for this project, replicate it and then improve it. This is a map that was published in the social media Reddit, where we can see how the world population is distributed by countries: those with the bigger circles represent a bigger proportion of the world population and vice versa. + +![Original graph.](originalmap.jpg){.external width="100%"} + +## Replica + +First of all, I have created the data base "population_data", where I have recorded every single country in the world, their respective populations, continents, latitude, longitude and the percentage of the world population their own population represents. This has been a key part of the project not only because it made it easier to fit the circles later on, but because there were **no data bases online with all these data**, and also because in the original map, some countries were not shown or taken into consideration. Even in my replica, I have wanted to show as many countries as possible as an initial improvement. + + +```{r} +population_data <- read.csv("population_data.csv") +``` + + +```{r} +head(population_data) +``` +I also had to create a new data base, a very simple one, called population_by_continent. In this data base, I have only the name of the continent and the percentage (normal and scaled) that each continent´s population represent worldly. + +```{r} +library(xfun) +library(dplyr) +library(forcats) +population_by_continent <- population_data |> group_by(continent) |> + summarize(total_population = sum(circle_size)) |> + mutate(percentage = total_population / sum(total_population)*100, + continent = fct_reorder(continent, -percentage)) +``` + +```{r} +head(population_by_continent) +``` + +Let´s go with the replica itself! Now that I have all the data I may need, I will explain step by step how I have created the map. + +First of all, let´s load all the packages I needed: + +```{r} +library(ggplot2) +library(sf) +library(ggrepel) +library(cowplot) +library(permute) +library(plotly) +library(patchwork) +library(extrafont) +``` + +Now, I changed some of the data in population_data. Originally I had thought that the best option was to divide America in 3 parts, instead of the 2 proposed by the original map: North America, Central America and South America. Nevertheless, Central America represented a very small percentage of the population as was barely visible. Also, it induced some problems in order to create the replica. Finally, I decided to change all Central America countries to South America ones because Central America *is not considered a continent*, while some authors say that South America is itself a continent. + +```{r} +population_data <- population_data |> + mutate(continent = case_when( + continent == "Central America" ~ "South America", + TRUE ~ continent + )) +``` + +I had written incorrectly South America in some of the countries, because I created the data base manually, so I had to fix it: + +```{r} +population_data <- population_data |> + mutate(continent = case_when(continent == "South Amrica" ~ "South America", TRUE ~ continent)) + +population_by_continent <- population_by_continent |> + mutate(continent = case_when(continent == "Central America" ~ "South America", TRUE ~ continent)) +``` + +Here, I started to design the map itself, not only the data that was going to be shown in it. First of all, I created a new variable inside of population_data, circle_size and circle_sized_adjusted, where I designed the desirable size of the circles in general, but also of the "big 5" specifically. These 5 countries, China, India, USA, Brazil and Nigeria, were **not** proportional in the original map. They were much bigger than other countries´ circles, even when those countries´ percentage of the world population was not that much smaller. Because of this, I designed these circles as circle_size_adjusted, so that every circle is bigger than in the original variable, circle_size (where every size was directly proportional to the percentage of the population), so that every country´s circle was augmented 60 times, while the big 5 had their circles augmented 150 times. + +```{r} +population_data <- population_data |> + mutate(circle_size = as.numeric(circle_size)) + +population_data <- population_data |> + mutate(circle_size_adjusted = case_when( + country %in% c("China", "India", "USA", "Brazil", "Nigeria") ~ circle_size * 150, + TRUE ~ circle_size * 60 + )) + +``` + +After a couple of first trials, I decided that **not every country should be included as a label in the map**. In the original map they were not, and this makes sense in order to keep some... Well, some order :). So I chose the most visible countries from the original map and created the vector countries_labelled, which collects the countries that would get a label. It is important to note that **every country has a different circle**, but not all of them are labelled. + +```{r} +countries_labelled <- c( + "Canada", "United States", "Mexico", "Cuba", "Guatemala", "Haiti", "Dominican Republic", + "Colombia", "Venezuela", "Ecuador", "Peru", "Bolivia", "Brazil", "Uruguay", + "Paraguay", "Argentina", "Chile", "United Kingdom", "Greenland", "Spain", + "Portugal", "France", "Italy", "Germany", "Poland", "Ukraine", "Turkey", + "Iraq", "Syria", "Pakistan", "Iran", "Russia", "China", "India", "Bangladesh", + "Vietnam", "Indonesia", "Philippines", "Japan", "Australia", "Nigeria", + "Morocco", "Algeria", "Congo, Dem. Rep.", "Ethiopia", "Egypt", + "Tanzania", "Kenya", "South Africa", "Russian Federation") +``` + +I faced some problems with Kenya, that was not considered as Africa in the original data base; and also with the new variable, circle_size_adjusted, that was not considered as numeric data. I fixed both problems in this chunk: + +```{r} +population_data <- population_data |> + mutate(circle_size_adjusted = as.numeric(circle_size_adjusted)) +population_data <- population_data |> + mutate(continent = ifelse(country == "Kenya", "Africa", continent)) +``` + +Then I grouped the data by continent and created the variable of percentage_scaled. This would be used in order to create the legend bar. + +```{r} +population_by_continent <- population_data |> + group_by(continent) |> + summarize(percentage = sum(percentage)) |> + mutate(percentage_scaled = percentage * 1.5) +``` + +Also in order to create the legend bar, I created the data base population_by_continent_summarized. I built this new data base by using population_by_continent and its new variable, percentage_scaled. What I did here was to create two variables inside population_by_continent_summmarized: cumulative and label_position. The most important one out of these two is label_position, which has allowed me to situate the labels in the legend bar correctly. The idea is that the whole bar is a vector, and each label must be situated in position that results from substracting from the whole vector (cumulative, that represents all the continent data) half of the value of percentage_scaled. + +```{r} +population_by_continent_summarized <- population_by_continent |> + arrange(percentage_scaled) |> + mutate( + cumulative = cumsum(percentage_scaled), + label_position = cumulative - percentage_scaled / 2 + ) |> mutate(continent = factor(continent, levels = continent)) +``` + +Now, I could finally create the legend_bar, which is the first step in the creation of the replica. And, once I had the legend bar, I could create the replica map itself: + +```{r, fig.width = 30, fig.height = 20, preview=TRUE} +# Creation of the legend bar: + +legend_bar <- ggplot(population_by_continent_summarized) + + aes(x = 1, y = percentage_scaled, fill = reorder(continent, -percentage_scaled)) + + geom_bar(stat = "identity", width = 2, color = "black") + + geom_text( + aes( + label = ifelse(continent == "Oceania", "", + paste0(continent, ":", round(percentage_scaled, 1), "%")), + size = percentage_scaled + ), + color = "white", + fontface = "bold", + family = "Arial", + position = position_stack(vjust = 0.5) + ) + + scale_size_continuous(range = c(0.5, 20)) + + coord_flip() + + scale_fill_manual( + values = c( + "Asia" = "#00a3e0", "Africa" = "#009639", "Europe" = "#FF9E1B", + "North America" = "#aa0061", "South America" = "#F7EA48", + "Oceania" = "pink" + ), + name = "Continent" + ) + + labs(x = NULL, y = NULL) + + theme_minimal() + + theme( + axis.text = element_blank(), + axis.ticks = element_blank(), + panel.grid = element_blank(), + legend.position = "none", + plot.margin = margin(0, 0, 0, 0), + legend.title = element_text(family = "Arial", face = "bold", size = 16), + legend.text = element_text(family = "Arial", size = 12) + ) + +# Creation of the replica + + +map <- ggplot() + + borders("world", colour = "gray95", fill = "gray95") + + geom_sf(fill = "white", color = "gray80") + + coord_sf(crs = "+proj=robin") + + geom_point( + data = population_data, + aes(x = adjusted_long, y = adjusted_lat, + size = circle_size_adjusted, fill = continent), + alpha = 1, + shape = 21, + color = "black", + stroke = 1.2 + ) + + geom_label( + data = population_data |> filter(country %in% countries_labelled), + aes(x = adjusted_long, y = adjusted_lat, + label = paste0(country, "\n", round(percentage, 1), "%"), + size = ifelse(country %in% c("India", "China"), 20, 6)), + fontface = "bold", family = "Arial", color = "black", fill = NA, label.size = 0) + + scale_size_identity() + + scale_size_continuous(range = c(5, 95), name = "Population(%)") + + scale_fill_manual( + values = c( "Asia" = "#00a3e0", "Africa" = "#009639", "Europe" = "#FF9E1B", + "North America" = "#aa0061", "South America" = "#F7EA48", "Oceania" = "pink"), + name = "Continent" + ) + + labs( + title = "Where do 8 billion people live?", + x = NULL, + y = NULL + ) + + theme_minimal() + + theme( + plot.title = element_text(size = 80, face = "bold", hjust = 0.5), + legend.position = "none", + legend.title = element_text(size = 50, face = "bold", family = "Arial"), + legend.text = element_text(size = 15, family = "Arial") + ) + +final_plot <- map / legend_bar + plot_layout(heights = c(0.85, 0.15)) + +final_plot + +``` + + +## Improvement + +Now, which were the main problems in the original map? In my opinion, the main problem was that the information gets diluted in the whole map. If the idea is to inform people of which countries represent the biggest percentages of population in the world, it is not important to know where the country is, mainly what´s its population, how big their proportion of the world population is compared to that of other countries, and in which continent they can be found (so we can know which continent is the most populated). So I have decided to create a **treemap** where you will be able to see all of this information. In this case you will be able to see the total population of each country, not the proportion of the world population they represent, since that information is already provided by the size of their square in the treemap. + +```{r, fig.width = 30, fig.height = 25} +library(ggplot2) +library(treemapify) +library(treemapify) +library(extrafont) + +population_data$continent[population_data$continent == "Central America"] <- "South America" + +treemap <- ggplot(data = population_data, + aes(area = population, fill = continent, + label = paste0(country, "\n", round(population / 1e6, 1), "M"))) + + geom_treemap(color = "black", size = 1) + + geom_treemap_text(fontface = "bold", color = "white", place = "center", grow = TRUE) + + scale_fill_manual(values = c( + "Africa" = "#FF5733", + "Asia" = "#3498DB", + "Europe" = "#2ECC71", + "North America" = "#9B59B6", + "South America" = "#F1C40F", + "Oceania" = "pink" + )) + + theme_minimal() + + labs(title = "Where do 8 billion people live?", + subtitle = "Population distribution by country and continent", + fill = "Continent") + + theme(plot.title = element_text(size = 50, face = "bold", hjust = 0.5), + plot.subtitle = element_text(size = 30, hjust = 0.5), + legend.title = element_text(size = 35), + legend.text = element_text(size = 35)) + +treemap +``` + + diff --git a/_projects/2024/100432719/100432719.html b/_projects/2024/100432719/100432719.html new file mode 100644 index 00000000..3f869c57 --- /dev/null +++ b/_projects/2024/100432719/100432719.html @@ -0,0 +1,1863 @@ + + + + +
+ + + + + + + + + + + + + + + +Replica and improvement of a map to show how the world population is distributed among different countries
+When I was thinking about this project, I ran directly into this map:
+The first thing I thought was: wow! A graph were my 3 disciplines merge together: sociology, international relations and, now, programming!. So I decided to use it for this project, replicate it and then improve it. This is a map that was published in the social media Reddit, where we can see how the world population is distributed by countries: those with the bigger circles represent a bigger proportion of the world population and vice versa.
+ +First of all, I have created the data base “population_data”, where I have recorded every single country in the world, their respective populations, continents, latitude, longitude and the percentage of the world population their own population represents. This has been a key part of the project not only because it made it easier to fit the circles later on, but because there were no data bases online with all these data, and also because in the original map, some countries were not shown or taken into consideration. Even in my replica, I have wanted to show as many countries as possible as an initial improvement.
+population_data <- read.csv("population_data.csv")
+head(population_data)
+ X country population continent lat long
+1 1 Aruba 106277 South America 12.50 -69.97
+2 2 Afghanistan 42239854 Asia 33.00 65.00
+3 3 Albania 2745972 Europe 41.00 20.00
+4 4 Algeria 45606480 Africa 28.00 3.00
+5 5 American Samoa 43914 Oceania -14.33 -170.00
+6 6 Andorra 80088 Europe 42.50 1.50
+ percentage text_size circle_size population_percentage
+1 0.0013295966 0.0007091182 0.0010636773 0.0013295966
+2 0.5284489166 0.2818394222 0.4227591333 0.5284489166
+3 0.0343539523 0.0183221079 0.0274831618 0.0343539523
+4 0.5705676669 0.3043027557 0.4564541335 0.5705676669
+5 0.0005493936 0.0002930099 0.0004395149 0.0005493936
+6 0.0010019546 0.0005343758 0.0008015637 0.0010019546
+ population_millions adjusted_long adjusted_lat
+1 0.106277 -69.97 12.50
+2 42.239854 65.00 33.00
+3 2.745972 20.00 41.00
+4 45.606480 3.00 28.00
+5 0.043914 -170.00 -14.33
+6 0.080088 1.50 42.50
+I also had to create a new data base, a very simple one, called population_by_continent. In this data base, I have only the name of the continent and the percentage (normal and scaled) that each continent´s population represent worldly.
+head(population_by_continent)
+# A tibble: 6 × 3
+ continent total_population percentage
+ <fct> <dbl> <dbl>
+1 Africa 16.4 15.1
+2 Asia 71.6 65.8
+3 Central America 1.76 1.62
+4 Europe 7.95 7.31
+5 North America 4.14 3.81
+6 Oceania 0.455 0.419
+Let´s go with the replica itself! Now that I have all the data I may need, I will explain step by step how I have created the map.
+First of all, let´s load all the packages I needed:
+Now, I changed some of the data in population_data. Originally I had thought that the best option was to divide America in 3 parts, instead of the 2 proposed by the original map: North America, Central America and South America. Nevertheless, Central America represented a very small percentage of the population as was barely visible. Also, it induced some problems in order to create the replica. Finally, I decided to change all Central America countries to South America ones because Central America is not considered a continent, while some authors say that South America is itself a continent.
+I had written incorrectly South America in some of the countries, because I created the data base manually, so I had to fix it:
+Here, I started to design the map itself, not only the data that was going to be shown in it. First of all, I created a new variable inside of population_data, circle_size and circle_sized_adjusted, where I designed the desirable size of the circles in general, but also of the “big 5” specifically. These 5 countries, China, India, USA, Brazil and Nigeria, were not proportional in the original map. They were much bigger than other countries´ circles, even when those countries´ percentage of the world population was not that much smaller. Because of this, I designed these circles as circle_size_adjusted, so that every circle is bigger than in the original variable, circle_size (where every size was directly proportional to the percentage of the population), so that every country´s circle was augmented 60 times, while the big 5 had their circles augmented 150 times.
+After a couple of first trials, I decided that not every country should be included as a label in the map. In the original map they were not, and this makes sense in order to keep some… Well, some order :). So I chose the most visible countries from the original map and created the vector countries_labelled, which collects the countries that would get a label. It is important to note that every country has a different circle, but not all of them are labelled.
+countries_labelled <- c(
+ "Canada", "United States", "Mexico", "Cuba", "Guatemala", "Haiti", "Dominican Republic",
+ "Colombia", "Venezuela", "Ecuador", "Peru", "Bolivia", "Brazil", "Uruguay",
+ "Paraguay", "Argentina", "Chile", "United Kingdom", "Greenland", "Spain",
+ "Portugal", "France", "Italy", "Germany", "Poland", "Ukraine", "Turkey",
+ "Iraq", "Syria", "Pakistan", "Iran", "Russia", "China", "India", "Bangladesh",
+ "Vietnam", "Indonesia", "Philippines", "Japan", "Australia", "Nigeria",
+ "Morocco", "Algeria", "Congo, Dem. Rep.", "Ethiopia", "Egypt",
+ "Tanzania", "Kenya", "South Africa", "Russian Federation")
+I faced some problems with Kenya, that was not considered as Africa in the original data base; and also with the new variable, circle_size_adjusted, that was not considered as numeric data. I fixed both problems in this chunk:
+population_data <- population_data |>
+ mutate(circle_size_adjusted = as.numeric(circle_size_adjusted))
+population_data <- population_data |>
+ mutate(continent = ifelse(country == "Kenya", "Africa", continent))
+Then I grouped the data by continent and created the variable of percentage_scaled. This would be used in order to create the legend bar.
+Also in order to create the legend bar, I created the data base population_by_continent_summarized. I built this new data base by using population_by_continent and its new variable, percentage_scaled. What I did here was to create two variables inside population_by_continent_summmarized: cumulative and label_position. The most important one out of these two is label_position, which has allowed me to situate the labels in the legend bar correctly. The idea is that the whole bar is a vector, and each label must be situated in position that results from substracting from the whole vector (cumulative, that represents all the continent data) half of the value of percentage_scaled.
+Now, I could finally create the legend_bar, which is the first step in the creation of the replica. And, once I had the legend bar, I could create the replica map itself:
+# Creation of the legend bar:
+
+legend_bar <- ggplot(population_by_continent_summarized) +
+ aes(x = 1, y = percentage_scaled, fill = reorder(continent, -percentage_scaled)) +
+ geom_bar(stat = "identity", width = 2, color = "black") +
+ geom_text(
+ aes(
+ label = ifelse(continent == "Oceania", "",
+ paste0(continent, ":", round(percentage_scaled, 1), "%")),
+ size = percentage_scaled
+ ),
+ color = "white",
+ fontface = "bold",
+ family = "Arial",
+ position = position_stack(vjust = 0.5)
+ ) +
+ scale_size_continuous(range = c(0.5, 20)) +
+ coord_flip() +
+ scale_fill_manual(
+ values = c(
+ "Asia" = "#00a3e0", "Africa" = "#009639", "Europe" = "#FF9E1B",
+ "North America" = "#aa0061", "South America" = "#F7EA48",
+ "Oceania" = "pink"
+ ),
+ name = "Continent"
+ ) +
+ labs(x = NULL, y = NULL) +
+ theme_minimal() +
+ theme(
+ axis.text = element_blank(),
+ axis.ticks = element_blank(),
+ panel.grid = element_blank(),
+ legend.position = "none",
+ plot.margin = margin(0, 0, 0, 0),
+ legend.title = element_text(family = "Arial", face = "bold", size = 16),
+ legend.text = element_text(family = "Arial", size = 12)
+ )
+
+# Creation of the replica
+
+
+map <- ggplot() +
+ borders("world", colour = "gray95", fill = "gray95") +
+ geom_sf(fill = "white", color = "gray80") +
+ coord_sf(crs = "+proj=robin") +
+ geom_point(
+ data = population_data,
+ aes(x = adjusted_long, y = adjusted_lat,
+ size = circle_size_adjusted, fill = continent),
+ alpha = 1,
+ shape = 21,
+ color = "black",
+ stroke = 1.2
+ ) +
+ geom_label(
+ data = population_data |> filter(country %in% countries_labelled),
+ aes(x = adjusted_long, y = adjusted_lat,
+ label = paste0(country, "\n", round(percentage, 1), "%"),
+ size = ifelse(country %in% c("India", "China"), 20, 6)),
+ fontface = "bold", family = "Arial", color = "black", fill = NA, label.size = 0) +
+ scale_size_identity() +
+ scale_size_continuous(range = c(5, 95), name = "Population(%)") +
+ scale_fill_manual(
+ values = c( "Asia" = "#00a3e0", "Africa" = "#009639", "Europe" = "#FF9E1B",
+ "North America" = "#aa0061", "South America" = "#F7EA48", "Oceania" = "pink"),
+ name = "Continent"
+ ) +
+ labs(
+ title = "Where do 8 billion people live?",
+ x = NULL,
+ y = NULL
+ ) +
+ theme_minimal() +
+ theme(
+ plot.title = element_text(size = 80, face = "bold", hjust = 0.5),
+ legend.position = "none",
+ legend.title = element_text(size = 50, face = "bold", family = "Arial"),
+ legend.text = element_text(size = 15, family = "Arial")
+ )
+
+final_plot <- map / legend_bar + plot_layout(heights = c(0.85, 0.15))
+
+final_plot
+Now, which were the main problems in the original map? In my opinion, the main problem was that the information gets diluted in the whole map. If the idea is to inform people of which countries represent the biggest percentages of population in the world, it is not important to know where the country is, mainly what´s its population, how big their proportion of the world population is compared to that of other countries, and in which continent they can be found (so we can know which continent is the most populated). So I have decided to create a treemap where you will be able to see all of this information. In this case you will be able to see the total population of each country, not the proportion of the world population they represent, since that information is already provided by the size of their square in the treemap.
+library(ggplot2)
+library(treemapify)
+library(treemapify)
+library(extrafont)
+
+population_data$continent[population_data$continent == "Central America"] <- "South America"
+
+treemap <- ggplot(data = population_data,
+ aes(area = population, fill = continent,
+ label = paste0(country, "\n", round(population / 1e6, 1), "M"))) +
+ geom_treemap(color = "black", size = 1) +
+ geom_treemap_text(fontface = "bold", color = "white", place = "center", grow = TRUE) +
+ scale_fill_manual(values = c(
+ "Africa" = "#FF5733",
+ "Asia" = "#3498DB",
+ "Europe" = "#2ECC71",
+ "North America" = "#9B59B6",
+ "South America" = "#F1C40F",
+ "Oceania" = "pink"
+ )) +
+ theme_minimal() +
+ labs(title = "Where do 8 billion people live?",
+ subtitle = "Population distribution by country and continent",
+ fill = "Continent") +
+ theme(plot.title = element_text(size = 50, face = "bold", hjust = 0.5),
+ plot.subtitle = element_text(size = 30, hjust = 0.5),
+ legend.title = element_text(size = 35),
+ legend.text = element_text(size = 35))
+
+treemap
+
`,e.githubCompareUpdatesUrl&&(t+=`View all changes to this article since it was first published.`),t+=` + If you see mistakes or want to suggest changes, please create an issue on GitHub.
+ `);const n=e.journal;return'undefined'!=typeof n&&'Distill'===n.title&&(t+=` +Diagrams and text are licensed under Creative Commons Attribution CC-BY 4.0 with the source available on GitHub, unless noted otherwise. The figures that have been reused from other sources don’t fall under this license and can be recognized by a note in their caption: “Figure from …”.
+ `),'undefined'!=typeof e.publishedDate&&(t+=` +For attribution in academic contexts, please cite this work as
+${e.concatenatedAuthors}, "${e.title}", Distill, ${e.publishedYear}.+
BibTeX citation
+${m(e)}+ `),t}var An=Math.sqrt,En=Math.atan2,Dn=Math.sin,Mn=Math.cos,On=Math.PI,Un=Math.abs,In=Math.pow,Nn=Math.LN10,jn=Math.log,Rn=Math.max,qn=Math.ceil,Fn=Math.floor,Pn=Math.round,Hn=Math.min;const zn=['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],Bn=['Jan.','Feb.','March','April','May','June','July','Aug.','Sept.','Oct.','Nov.','Dec.'],Wn=(e)=>10>e?'0'+e:e,Vn=function(e){const t=zn[e.getDay()].substring(0,3),n=Wn(e.getDate()),i=Bn[e.getMonth()].substring(0,3),a=e.getFullYear().toString(),d=e.getUTCHours().toString(),r=e.getUTCMinutes().toString(),o=e.getUTCSeconds().toString();return`${t}, ${n} ${i} ${a} ${d}:${r}:${o} Z`},$n=function(e){const t=Array.from(e).reduce((e,[t,n])=>Object.assign(e,{[t]:n}),{});return t},Jn=function(e){const t=new Map;for(var n in e)e.hasOwnProperty(n)&&t.set(n,e[n]);return t};class Qn{constructor(e){this.name=e.author,this.personalURL=e.authorURL,this.affiliation=e.affiliation,this.affiliationURL=e.affiliationURL,this.affiliations=e.affiliations||[]}get firstName(){const e=this.name.split(' ');return e.slice(0,e.length-1).join(' ')}get lastName(){const e=this.name.split(' ');return e[e.length-1]}}class Gn{constructor(){this.title='unnamed article',this.description='',this.authors=[],this.bibliography=new Map,this.bibliographyParsed=!1,this.citations=[],this.citationsCollected=!1,this.journal={},this.katex={},this.publishedDate=void 0}set url(e){this._url=e}get url(){if(this._url)return this._url;return this.distillPath&&this.journal.url?this.journal.url+'/'+this.distillPath:this.journal.url?this.journal.url:void 0}get githubUrl(){return this.githubPath?'https://github.com/'+this.githubPath:void 0}set previewURL(e){this._previewURL=e}get previewURL(){return this._previewURL?this._previewURL:this.url+'/thumbnail.jpg'}get publishedDateRFC(){return Vn(this.publishedDate)}get updatedDateRFC(){return Vn(this.updatedDate)}get publishedYear(){return this.publishedDate.getFullYear()}get publishedMonth(){return Bn[this.publishedDate.getMonth()]}get publishedDay(){return this.publishedDate.getDate()}get publishedMonthPadded(){return Wn(this.publishedDate.getMonth()+1)}get publishedDayPadded(){return Wn(this.publishedDate.getDate())}get publishedISODateOnly(){return this.publishedDate.toISOString().split('T')[0]}get volume(){const e=this.publishedYear-2015;if(1>e)throw new Error('Invalid publish date detected during computing volume');return e}get issue(){return this.publishedDate.getMonth()+1}get concatenatedAuthors(){if(2
tag. We found the following text: '+t);const n=document.createElement('span');n.innerHTML=e.nodeValue,e.parentNode.insertBefore(n,e),e.parentNode.removeChild(e)}}}}).observe(this,{childList:!0})}}var Ti='undefined'==typeof window?'undefined'==typeof global?'undefined'==typeof self?{}:self:global:window,_i=f(function(e,t){(function(e){function t(){this.months=['jan','feb','mar','apr','may','jun','jul','aug','sep','oct','nov','dec'],this.notKey=[',','{','}',' ','='],this.pos=0,this.input='',this.entries=[],this.currentEntry='',this.setInput=function(e){this.input=e},this.getEntries=function(){return this.entries},this.isWhitespace=function(e){return' '==e||'\r'==e||'\t'==e||'\n'==e},this.match=function(e,t){if((void 0==t||null==t)&&(t=!0),this.skipWhitespace(t),this.input.substring(this.pos,this.pos+e.length)==e)this.pos+=e.length;else throw'Token mismatch, expected '+e+', found '+this.input.substring(this.pos);this.skipWhitespace(t)},this.tryMatch=function(e,t){return(void 0==t||null==t)&&(t=!0),this.skipWhitespace(t),this.input.substring(this.pos,this.pos+e.length)==e},this.matchAt=function(){for(;this.input.length>this.pos&&'@'!=this.input[this.pos];)this.pos++;return!('@'!=this.input[this.pos])},this.skipWhitespace=function(e){for(;this.isWhitespace(this.input[this.pos]);)this.pos++;if('%'==this.input[this.pos]&&!0==e){for(;'\n'!=this.input[this.pos];)this.pos++;this.skipWhitespace(e)}},this.value_braces=function(){var e=0;this.match('{',!1);for(var t=this.pos,n=!1;;){if(!n)if('}'==this.input[this.pos]){if(0 =k&&(++x,i=k);if(d[x]instanceof n||d[T-1].greedy)continue;w=T-x,y=e.slice(i,k),v.index-=i}if(v){g&&(h=v[1].length);var S=v.index+h,v=v[0].slice(h),C=S+v.length,_=y.slice(0,S),L=y.slice(C),A=[x,w];_&&A.push(_);var E=new n(o,u?a.tokenize(v,u):v,b,v,f);A.push(E),L&&A.push(L),Array.prototype.splice.apply(d,A)}}}}}return d},hooks:{all:{},add:function(e,t){var n=a.hooks.all;n[e]=n[e]||[],n[e].push(t)},run:function(e,t){var n=a.hooks.all[e];if(n&&n.length)for(var d,r=0;d=n[r++];)d(t)}}},i=a.Token=function(e,t,n,i,a){this.type=e,this.content=t,this.alias=n,this.length=0|(i||'').length,this.greedy=!!a};if(i.stringify=function(e,t,n){if('string'==typeof e)return e;if('Array'===a.util.type(e))return e.map(function(n){return i.stringify(n,t,e)}).join('');var d={type:e.type,content:i.stringify(e.content,t,n),tag:'span',classes:['token',e.type],attributes:{},language:t,parent:n};if('comment'==d.type&&(d.attributes.spellcheck='true'),e.alias){var r='Array'===a.util.type(e.alias)?e.alias:[e.alias];Array.prototype.push.apply(d.classes,r)}a.hooks.run('wrap',d);var l=Object.keys(d.attributes).map(function(e){return e+'="'+(d.attributes[e]||'').replace(/"/g,'"')+'"'}).join(' ');return'<'+d.tag+' class="'+d.classes.join(' ')+'"'+(l?' '+l:'')+'>'+d.content+''+d.tag+'>'},!t.document)return t.addEventListener?(t.addEventListener('message',function(e){var n=JSON.parse(e.data),i=n.language,d=n.code,r=n.immediateClose;t.postMessage(a.highlight(d,a.languages[i],i)),r&&t.close()},!1),t.Prism):t.Prism;var d=document.currentScript||[].slice.call(document.getElementsByTagName('script')).pop();return d&&(a.filename=d.src,document.addEventListener&&!d.hasAttribute('data-manual')&&('loading'===document.readyState?document.addEventListener('DOMContentLoaded',a.highlightAll):window.requestAnimationFrame?window.requestAnimationFrame(a.highlightAll):window.setTimeout(a.highlightAll,16))),t.Prism}();e.exports&&(e.exports=n),'undefined'!=typeof Ti&&(Ti.Prism=n),n.languages.markup={comment://,prolog:/<\?[\w\W]+?\?>/,doctype://i,cdata://i,tag:{pattern:/<\/?(?!\d)[^\s>\/=$<]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\\1|\\?(?!\1)[\w\W])*\1|[^\s'">=]+))?)*\s*\/?>/i,inside:{tag:{pattern:/^<\/?[^\s>\/]+/i,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=(?:('|")[\w\W]*?(\1)|[^\s>]+)/i,inside:{punctuation:/[=>"']/}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:/?[\da-z]{1,8};/i},n.hooks.add('wrap',function(e){'entity'===e.type&&(e.attributes.title=e.content.replace(/&/,'&'))}),n.languages.xml=n.languages.markup,n.languages.html=n.languages.markup,n.languages.mathml=n.languages.markup,n.languages.svg=n.languages.markup,n.languages.css={comment:/\/\*[\w\W]*?\*\//,atrule:{pattern:/@[\w-]+?.*?(;|(?=\s*\{))/i,inside:{rule:/@[\w-]+/}},url:/url\((?:(["'])(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1|.*?)\)/i,selector:/[^\{\}\s][^\{\};]*?(?=\s*\{)/,string:{pattern:/("|')(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1/,greedy:!0},property:/(\b|\B)[\w-]+(?=\s*:)/i,important:/\B!important\b/i,function:/[-a-z0-9]+(?=\()/i,punctuation:/[(){};:]/},n.languages.css.atrule.inside.rest=n.util.clone(n.languages.css),n.languages.markup&&(n.languages.insertBefore('markup','tag',{style:{pattern:/(
+
+
+ ${e.map(l).map((e)=>`
`)}}const Mi=`
+d-citation-list {
+ contain: layout style;
+}
+
+d-citation-list .references {
+ grid-column: text;
+}
+
+d-citation-list .references .title {
+ font-weight: 500;
+}
+`;class Oi extends HTMLElement{static get is(){return'd-citation-list'}connectedCallback(){this.hasAttribute('distill-prerendered')||(this.style.display='none')}set citations(e){x(this,e)}}var Ui=f(function(e){var t='undefined'==typeof window?'undefined'!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{}:window,n=function(){var e=/\blang(?:uage)?-(\w+)\b/i,n=0,a=t.Prism={util:{encode:function(e){return e instanceof i?new i(e.type,a.util.encode(e.content),e.alias):'Array'===a.util.type(e)?e.map(a.util.encode):e.replace(/&/g,'&').replace(/e.length)break tokenloop;if(!(y instanceof n)){c.lastIndex=0;var v=c.exec(y),w=1;if(!v&&f&&x!=d.length-1){if(c.lastIndex=i,v=c.exec(e),!v)break;for(var S=v.index+(g?v[1].length:0),C=v.index+v[0].length,T=x,k=i,p=d.length;T
+
+`);class Ni extends ei(Ii(HTMLElement)){renderContent(){if(this.languageName=this.getAttribute('language'),!this.languageName)return void console.warn('You need to provide a language attribute to your
Footnotes
+
+`,!1);class Fi extends qi(HTMLElement){connectedCallback(){super.connectedCallback(),this.list=this.root.querySelector('ol'),this.root.style.display='none'}set footnotes(e){if(this.list.innerHTML='',e.length){this.root.style.display='';for(const t of e){const e=document.createElement('li');e.id=t.id+'-listing',e.innerHTML=t.innerHTML;const n=document.createElement('a');n.setAttribute('class','footnote-backlink'),n.textContent='[\u21A9]',n.href='#'+t.id,e.appendChild(n),this.list.appendChild(e)}}else this.root.style.display='none'}}const Pi=ti('d-hover-box',`
+
+
+