Introduction
And here we go…
This is the first analysis article on my website! Personally, I did not want to start with a ready-made dataset and apply a simple machine learning model. I decided to put in a bit more effort and implement the full data analysis cycle, starting from data extraction, moving through tidying, and ending with the analysis itself. In this piece, I want to explore the history of representatives in the Hellenic Parliament and answer some interesting questions. For this research, I will use data published by the Hellenic Parliament website regarding elected members of parliament.
The Greek political landscape has dominated public discourse in recent years, unfortunately for negative reasons, due to the recent economic crisis. A significant part of this dialogue concerns the causes of the crisis, which remain a point of contention to this day. In this article, I will focus on just one aspect of the criticism: that “we always have the same” representatives. Of course, our representatives in Parliament were not appointed by any party; elections were held, so the criticism centers on the idea that the same parties or even the same individual MPs keep getting elected, perhaps out of personal loyalty or benefit. The only exception involves inconclusive elections that produced no government, leading to repeat elections where party lists determine seat allocation. So what actually happened? Is this claim justified? That is what I intend to study here. I will also examine the tendency to favor familiar faces within the same party, and it is equally interesting to investigate this at the constituency level.
Prerequisites
Loading Packages
First, we will load the necessary libraries, depending on the functions I need and the analysis I will perform. Specifically, I will need the tidyverse meta-package to import, manipulate, and visualize data. For building tables I will use the gt package. Finally, to produce charts that render well across all screen types, I will use the highcharter library.
Loading Data
To find which MPs have been elected the most times at the national level, at the party level, and at the constituency level, I need the corresponding data. Fortunately, the Hellenic Parliament website maintains an electronic archive of elected members from 1974 through 2019. The data were scraped using the RSelenium package; I will not go into the collection process here, but anyone interested can find the code on GitHub. I load the already-extracted dataset with read_csv().
Show the code
parliamentGR = read_csv("https://github.com/stesiam/scrape-greek-parl-members-26/releases/download/v1.1.0/parlMembers-el.csv")
parliamentEN = read_csv("https://github.com/stesiam/scrape-greek-parl-members-26/releases/download/v1.1.0/parlMembers-eng.csv")
parliamentEN$abbrNamesEn <- parliamentEN$party |>
fct_recode(
"SPAD" = "Alliance of Progressive and Left Forces",
"ANEL" = "ANEXARTITOI ELLINES (Independent Hellenes) National Patriotic Democratic Alliance",
"ADP" = "ANEXARTITOI DIMOKRATIKOI VOULEFTES",
"ANEL" = "ANEXARTITOI ELLINES (Independent Hellenes)",
"SYRIZA" = "Coalition of the Left and Progress",
"KKE int." = "Communist Party of Greece (Interior)",
"PASOK" = "DEMOCRATIC COALITION (Panhellenic Socialist Movement Democratic Left )",
"DIMAR" = "DHM.AR (Democratic Left)",
"DIANA" = "DI.ANA.",
"DIKKI" = "DI.K.KI.",
"EDA" = "E.D.A. United Democratic Left",
"EDIK" = "E.DI.K.",
"Lysi" = "ELLINIKI LYSI - KYRIAKOS VELOPOULOS",
"Independent" = "INDEPENDENT",
"PASOK" = "KINIMA ALLAGIS",
"KKE" = "KOMMOUNISTIKO KOMMA ELLADAS",
"LAOS" = "LA.O.S.",
"LaE" = "LAIKI ENOTITA",
"GD" = "LAIKOS SYNDESMOS - CHRYSI AVGI (People’s Association – Golden Dawn)",
"EP" = "National Alignment",
"ND" = "NEA DIMOKRATIA",
"KNF" = "Neoliberals party",
"PASOK" = "PA.SO.K. (Panhellenic Socialist Movement)",
"PASOK" = "PASOK-KINAL",
"POLAN" = "POL.A.",
"SYRIZA" = "SYNASPISMOS RIZOSPASTIKIS ARISTERAS",
"SYRIZA" = "SYRIZA-PROODEFTIKI SYMMACHIA",
"River" = "TO POTAMI (The River)",
"AE" = "ΟΟ.ΕΟ."
)Defining Functions
To avoid repeating code, I will define a few helper functions. First, I want tables based on the gt library with certain appearance tweaks to make them look clean. Many tables will therefore use gt_custom() instead of the default gt().
Show the code
gt_custom <- function(data, head_max = 5, use_labels = TRUE) {
data_subset <- as.data.frame(data) %>% head(head_max)
gt_tbl <- data_subset %>%
gt() %>%
cols_align(align = "center", columns = everything()) %>%
tab_style(
style = cell_text(
v_align = "middle",
weight = "bold",
whitespace = "normal"
),
locations = cells_column_labels()
) %>%
tab_options(
row.striping.include_table_body = FALSE,
table.background.color = "transparent",
column_labels.background.color = "transparent",
table.width = pct(100),
table.font.size = px(13),
data_row.padding = px(15),
column_labels.padding = px(15),
table.border.top.style = "none",
table.border.bottom.style = "none",
table_body.hlines.style = "none",
column_labels.border.top.width = px(2),
column_labels.border.top.color = "#757575",
column_labels.border.bottom.width = px(2),
column_labels.border.bottom.color = "#757575",
table_body.border.bottom.width = px(2),
table_body.border.bottom.color = "#757575"
) %>%
opt_css(css = "
.gt_table th, .gt_table td {
text-align: center !important;
vertical-align: middle !important;
}
.gt_table {
margin-left: auto !important;
margin-right: auto !important;
width: 100% !important;
}
.gt_table tr { background-color: transparent !important; }
.gt_row { background-color: transparent !important; }
")
if (use_labels) {
gt_tbl <- gt_tbl %>%
cols_label_with(
fn = function(x) {
html(paste0(
"<b>", english_labels[x], "</b>",
"<br><span style='font-size:10px; color:#777; font-style:italic;'>",
x,
"</span>"
))
}
)
}
return(gt_tbl)
}It would be particularly interesting, given that we have information about MPs and the parliamentary groups they belong to, to build parliament composition diagrams. Since this is a historical overview, I will likely need more than three of them in this article, which justifies creating a dedicated function. The function will be called plot_parliament() and will accept a number indicating which parliamentary term to plot. The data cover from the 1st term (1974 to 1977) through the 19th term (2023A), so the argument accepts values from 1 to 19.
Show the code
# Parliament composition chart function
plot_parliament <- function(data, period_number, lang = "en") {
df_period <- data |>
filter(period_num == period_number)
total_seats <- nrow(df_period)
majority <- ceiling(total_seats / 2)
seats_party <- df_period |>
group_by(abbrNamesEl, abbrNamesEn, fullNamesEl, fullNamesEn, Color) |>
summarise(n = n(), .groups = "drop") |>
mutate(
pct = round(100 * n / total_seats, 1),
lr_position = case_when(
abbrNamesEl %in% c("KKE", "KKE int.", "EDA") ~ 1,
abbrNamesEl %in% c("SYRIZA", "LaE", "DIKKI") ~ 2,
abbrNamesEl %in% c("DIMAR", "SPAD") ~ 3,
abbrNamesEl %in% c("PASOK", "River") ~ 4,
abbrNamesEl %in% c("Independent", "ADP", "MeRA25",
"EDIK", "KIDISO") ~ 5,
abbrNamesEl %in% c("ND", "DIANA", "EP", "KNF") ~ 6,
abbrNamesEl %in% c("ANEL", "LAOS") ~ 7,
abbrNamesEl == "GD" ~ 8,
TRUE ~ 5
)
) |>
arrange(lr_position)
# Use English or Greek labels depending on lang
display_names <- if (lang == "en") seats_party$fullNamesEn else seats_party$fullNamesEl
display_abbr <- if (lang == "en") seats_party$abbrNamesEn else seats_party$abbrNamesEl
title_text <- paste0("Parliament Composition - Term ", period_number)
subtitle_text <- paste0("Total seats: ", total_seats, " · Majority: ", majority)
caption_text <- "Source: Hellenic Parliament"
highchart() |>
hc_chart(type = "item") |>
hc_title(text = title_text) |>
hc_subtitle(text = subtitle_text) |>
hc_caption(text = caption_text, align = "center") |>
hc_legend(
enabled = TRUE,
layout = "horizontal",
align = "center",
labelFormat = "{name} <span style='opacity:0.5;font-size:11px'>{y}</span>"
) |>
hc_tooltip(
useHTML = TRUE,
headerFormat = "",
pointFormat = paste0(
"<span style='color:{point.color}'>●</span> ",
"<b>{point.name}</b><br/>",
"Seats: <b>{point.y}</b> ({point.pct}%)"
)
) |>
hc_add_series(
name = "Seats",
data = purrr::pmap(
list(display_names,
seats_party$n,
seats_party$Color,
display_abbr,
seats_party$pct),
~ list(name = ..1,
y = ..2,
color = ..3,
label = ..4,
pct = ..5)
),
keys = c("name", "y", "color", "label", "pct"),
dataLabels = list(
enabled = TRUE,
format = "{point.label}",
backgroundColor = "#000000",
borderRadius = 3,
padding = 4,
style = list(
color = "#ffffff",
fontSize = "11px",
fontWeight = "bold",
textOutline = "none"
)
),
center = list("50%", "88%"),
size = "170%",
startAngle = -100,
endAngle = 100
) |>
hc_responsive(rules = list(
list(
condition = list(maxWidth = 768),
chartOptions = list(
series = list(list(
dataLabels = list(enabled = FALSE),
center = list("50%", "80%"),
size = "130%"
))
)
)
))
}
gt_parliament <- function(data, period_number) {
df_period <- data %>%
filter(period_num == period_number)
seats_party <- df_period %>%
group_by(abbrNamesEn, fullNamesEn, Color) %>%
summarise(n = n(), .groups = "drop") %>%
arrange(desc(n)) |>
select(abbrNamesEn, n) |>
rename("Party" = "abbrNamesEn", "Seats" = "n")
return(seats_party)
}Data Structure
The collected dataset consists of 7 variables (columns), all of which are qualitative. Of these five, four are categorical and one is ordinal.
| Variable | Variable Type | Description |
|---|---|---|
Full Name |
Qualitative (categorical) | Surname / First name / Father’s name |
Party |
Qualitative (categorical) | Parliamentary group / Party affiliation |
Constituency |
Qualitative (categorical) | Electoral constituency |
Term |
Qualitative (ordinal) | Parliamentary term |
gender |
Qualitative (categorical) | Estimated gender based on first name |
This summary is important, but it is usually helpful to also preview the data itself. Let me print the first rows of the dataset.
|
Full Name name |
Party party |
Constituency region |
Parliamentary Term period_name |
Term Duration dates |
Estimated Gender gender |
NA abbrNamesEn |
|---|---|---|---|---|---|---|
| Agapidaki Eirhni Stylianou | NEA DIMOKRATIA | State | 19th | (28/05/2023 - 29/05/2023) | female | ND |
| Skylakakis Theodoros Stefanou | NEA DIMOKRATIA | State | 19th | (28/05/2023 - 29/05/2023) | male | ND |
| Stylianidis Chrhstos Meli | NEA DIMOKRATIA | State | 19th | (28/05/2023 - 29/05/2023) | male | ND |
| Lytrivi Ioanna Dimitriou | NEA DIMOKRATIA | State | 19th | (28/05/2023 - 29/05/2023) | female | ND |
| Stamatis Georgios Anastasiou | NEA DIMOKRATIA | State | 19th | (28/05/2023 - 29/05/2023) | male | ND |
| Chatziioannidou Maria Nefeli Basileiou | NEA DIMOKRATIA | State | 19th | (28/05/2023 - 29/05/2023) | female | ND |
| Polyzou Maria Athanasiou | NEA DIMOKRATIA | State | 19th | (28/05/2023 - 29/05/2023) | female | ND |
| Iliopoulos Othon Stayrou | SYRIZA-PROODEFTIKI SYMMACHIA | State | 19th | (28/05/2023 - 29/05/2023) | male | SYRIZA |
| Akrita Elena Loukh | SYRIZA-PROODEFTIKI SYMMACHIA | State | 19th | (28/05/2023 - 29/05/2023) | female | SYRIZA |
| Apostolakis Eyaggelos Eyaggelou | SYRIZA-PROODEFTIKI SYMMACHIA | State | 19th | (28/05/2023 - 29/05/2023) | male | SYRIZA |
Data Wrangling
Once the data are loaded, it is good practice to carry out some basic tidying, or a more extensive version of it if the data lack a consistent and organized structure. I will examine each variable in turn, starting with party names (the Party variable). First, let me collect all unique values, that is all parliamentary groups in the history of Parliament that completed a term without dissolving. I notice several problems with party names: abbreviations and full names are mixed together, and the full names can be very long, requiring special handling.
The facade of the Hellenic Parliament, located in Syntagma Square. Construction of the building began in 1836 and was completed in 1843. It was originally intended to serve as a royal palace for King Otto, which is why it is also known as the Old Palace. Since 1935 it has served as the seat of parliament.
Photo credit: Pixabay, 2022 by user Leonhard_Niederwimmer - License: Pixabay Licence
Show the code
data.frame(
"Party" = unique(parliamentEN$party),
"Character count" = str_length(unique(parliamentEN$party)),
check.names = FALSE
) %>%
arrange(-`Character count`) %>%
gt_custom(., 7, use_labels = FALSE)| Party | Character count |
|---|---|
| ANEXARTITOI ELLINES (Independent Hellenes) National Patriotic Democratic Alliance | 83 |
| DEMOCRATIC COALITION (Panhellenic Socialist Movement Democratic Left ) | 71 |
| LAIKOS SYNDESMOS - CHRYSI AVGI (People’s Association – Golden Dawn) | 67 |
| ANEXARTITOI ELLINES (Independent Hellenes) | 42 |
| PA.SO.K. (Panhellenic Socialist Movement) | 41 |
| Alliance of Progressive and Left Forces | 39 |
| Communist Party of Greece (Interior) | 36 |
Beyond the above, I notice that there are multiple entries for the same party, which may have undergone a small name or identity change over the years (Independent Greeks) or larger changes where parties are predecessors or successors of one another (Synaspismos to SYRIZA, or PASOK through several rebrands and back to PASOK). Since these changes are not immediately obvious, it is necessary to create a lookup table so I can group this information and merge it into the main dataset.
Show the code
parties = data.frame(
sourceNamesEL = unique(parliamentGR$party),
fullNamesEn = c(
"New Democracy", "Coalition of the Radical Left",
"Panhellenic Socialistic Movement", "Communist Party of Greece",
"Independent", "Greek Solution",
"Coalition of the Radical Left", "Panhellenic Socialistic Movement",
"European Realistic Disobedience Front", "Golden Dawn",
"Panhellenic Socialistic Movement", "The River", "Popular Unity",
"Independent Greeks", "Panhellenic Socialistic Movement",
"Independent Greeks", "Democratic Left", "Independent Democratic MPs",
"Popular Orthodox Rally", "Coalition of the Radical Left",
"Democratic Social Movement", "Political Spring", "Alternative Ecologists",
"Democratic Renewal", "Communist Party of Greece (interior)",
"Union of the Democratic Centre", "National Alignment",
"Progress and Left Forces Alliance", "Party of New Liberals",
"United Democratic Left"
),
fullNamesEl = c(
"Νέα Δημοκρατία", "Συνασπισμός Ριζοσπαστικής Αριστεράς",
"Πανελλήνιο Σοσιαλιστικό Κίνημα", "Κομμουνιστικό Κόμμα Ελλάδας",
"Ανεξάρτητοι", "Ελληνική Λύση",
"Συνασπισμός Ριζοσπαστικής Αριστεράς", "Πανελλήνιο Σοσιαλιστικό Κίνημα",
"Μέτωπο Ευρωπαϊκής Ρεαλιστικής Ανυπακοής", "Χρυσή Αυγή",
"Πανελλήνιο Σοσιαλιστικό Κίνημα", "Το Ποτάμι", "Λαϊκή Ενότητα",
"Ανεξάρτητοι Έλληνες", "Πανελλήνιο Σοσιαλιστικό Κίνημα",
"Ανεξάρτητοι Έλληνες", "Δημοκρατική Αριστερά",
"Ανεξάρτητοι Δημοκρατικοί Βουλευτές", "Λαϊκός Ορθόδοξος Συναγερμός",
"Συνασπισμός Ριζοσπαστικής Αριστεράς", "Δημοκρατικό Κοινωνικό Κίνημα",
"Πολιτική Άνοιξη", "Εναλλακτικοί Οικολόγοι", "Δημοκρατική Ανανέωση",
"Κομμουνιστικό Κόμμα Ελλάδας Εσωτερικού", "Ένωση Δημοκρατικού Κέντρου",
"Εθνική Παράταξη", "Συμμαχία Προοδευτικών και Αριστερών Δυνάμεων",
"Κόμμα Νεοφιλελευθέρων", "Ενιαία Δημοκρατική Αριστερά"
),
abbrNamesEn = c(
"ND", "SYRIZA", "PASOK", "KKE", "Independent", "Lysi", "SYRIZA", "PASOK",
"MeRA25", "GD", "PASOK", "River", "LaE", "ANEL", "PASOK", "ANEL", "DIMAR",
"ADP", "LAOS", "SYRIZA", "DIKKI", "POLAN", "AE", "DIANA", "KKE int.",
"EDIK", "EP", "SPAD", "KNF", "EDA"
),
abbrNamesEl = c(
"ΝΔ", "ΣΥΡΙΖΑ", "ΠΑΣΟΚ", "ΚΚΕ", "Ανεξάρτητοι", "Λύση", "ΣΥΡΙΖΑ", "ΠΑΣΟΚ",
"ΜέΡΑ25", "ΧΑ", "ΠΑΣΟΚ", "ΠΟΤΑΜΙ", "ΛΑΕ", "ΑΝΕΛ", "ΠΑΣΟΚ", "ΑΝΕΛ", "ΔΗΜΑΡ",
"ΑΔΠ", "ΛΑΟΣ", "ΣΥΡΙΖΑ", "ΔΗΚΚΙ", "ΠΟΛΑΝ", "ΑΕ", "ΔΗΑΝΑ", "ΚΚΕ εσ.",
"ΕΔΗΚ", "ΕΠ", "ΣΠΑΔ", "ΚΝΦ", "ΕΔΑ"
)
) |>
mutate(Color = case_when(
abbrNamesEn == "PASOK" ~ "#95bb72",
abbrNamesEn == "ND" ~ "#0492c2",
abbrNamesEn == "KKE" ~ "#FF6666",
abbrNamesEn == "SYRIZA" ~ "#e27bb1",
abbrNamesEn == "KKE int." ~ "#FF3366",
abbrNamesEn == "DIANA" ~ "orange",
abbrNamesEn == "DIMAR" ~ "#FF4466",
abbrNamesEn == "River" ~ "#5592aa",
TRUE ~ "#808080"
))
parties %>% gt_custom()|
Party name (original) sourceNamesEL |
Party name (English, full) fullNamesEn |
Party name (Greek, full) fullNamesEl |
Abbreviation (English) abbrNamesEn |
Abbreviation (Greek) abbrNamesEl |
Color Color |
|---|---|---|---|---|---|
| ΝΕΑ ΔΗΜΟΚΡΑΤΙΑ | New Democracy | Νέα Δημοκρατία | ND | ΝΔ | #0492c2 |
| ΣΥΝΑΣΠΙΣΜΟΣ ΡΙΖΟΣΠΑΣΤΙΚΗΣ ΑΡΙΣΤΕΡΑΣ - ΠΡΟΟΔΕΥΤΙΚΗ ΣΥΜΜΑΧΙΑ | Coalition of the Radical Left | Συνασπισμός Ριζοσπαστικής Αριστεράς | SYRIZA | ΣΥΡΙΖΑ | #e27bb1 |
| ΠΑΣΟΚ-ΚΙΝΗΜΑ ΑΛΛΑΓΗΣ | Panhellenic Socialistic Movement | Πανελλήνιο Σοσιαλιστικό Κίνημα | PASOK | ΠΑΣΟΚ | #95bb72 |
| ΚΟΜΜΟΥΝΙΣΤΙΚΟ ΚΟΜΜΑ ΕΛΛΑΔΑΣ | Communist Party of Greece | Κομμουνιστικό Κόμμα Ελλάδας | KKE | ΚΚΕ | #FF6666 |
| ΑΝΕΞΑΡΤΗΤΟΙ | Independent | Ανεξάρτητοι | Independent | Ανεξάρτητοι | #808080 |
I am now able to use either the Greek or the English version of party names, and for charts I have mapped the most commonly accepted abbreviation for each. Keeping the full name and abbreviation separate is especially important when building charts, since available space is often limited. That way the reader gets the information they need without being overwhelmed, improving both readability and comprehension. As we saw above, some names are truly railway-length, such as “Independent Greeks” at 16 characters in English, while the shortest, Political Spring, comes in at just 15. On the other hand, the Democratic Coalition (essentially PASOK in alliance with smaller parties such as DIMAR) runs to 22. Before closing this section, I want to note the last column of the table. With so many parties it is clear that I need appropriate colors for each, though the sheer number risks creating confusion. I therefore chose the most representative color from each party’s emblem, at least for the better-known ones.
This closes the parties section and opens one final challenge: MP names. In the data preview, names follow a fairly consistent structure, typically “Surname FirstName FatherName”. Sometimes an MP has two first names or a double surname, separated by a hyphen.
One might ask: what is the problem? It is just a variable containing their names.
True! But I can do better, because that single variable encodes more information. With a little effort I can split the name into three separate variables for surname, first name, and father’s name. This will be useful in any charts where I want to show just the surname and first initial rather than the full name including patronymic.
Show the code
pattern <- "^([^-\\s]+)(?:\\s*-\\s*([^-\\s]+))?\\s+([^-\\s]+)(?:\\s*-\\s*([^-\\s]+))?(?:\\s+([^-\\s]+(?:\\s*(?:-|\\s)\\s*[^-\\s]+)*))?$"
parties_distinct <- parties %>%
group_by(abbrNamesEn) %>%
slice(1) %>%
ungroup() %>%
select(-sourceNamesEL)
mps_clean_names <- parliamentEN %>%
mutate(name = name %>%
str_remove_all("\\s*\\([^)]*\\)") %>%
str_squish()
) %>%
extract(
name,
into = c("surname1", "surname2", "name1", "name2", "father_name"),
regex = pattern,
remove = FALSE
)
mps_clean_names$period_num <- mps_clean_names$period_name |>
fct_recode(
"1" = "1st", "2" = "2nd", "3" = "3nd",
"4" = "4th", "5" = "5th", "6" = "6th",
"7" = "7th", "8" = "8th", "9" = "9th",
"10" = "10th","11" = "11th","12" = "12th",
"13" = "13th","14" = "14th","15" = "15th",
"16" = "16th","17" = "17th","18" = "18th",
"19" = "19th"
) |>
as.character() |>
as.numeric()
# Join με parties_distinct (όχι parties)
clean_dataset <- mps_clean_names %>%
left_join(parties_distinct, by = "abbrNamesEn") %>%
relocate(fullNamesEn, fullNamesEl, abbrNamesEl, Color, .after = abbrNamesEn) %>%
relocate(period_num, .after = period_name)
clean_dataset %>% gt_custom()|
Full Name name |
First Surname surname1 |
Second Surname surname2 |
First Name name1 |
Second Name name2 |
Father's Name father_name |
NA party |
Constituency region |
Term period_name |
Term number period_num |
Term duration dates |
Estimated gender gender |
Party abbreviation (English) abbrNamesEn |
Party name (English, full) fullNamesEn |
Party name (Greek, full) fullNamesEl |
Party abbreviation (Greek) abbrNamesEl |
Party color Color |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Agapidaki Eirhni Stylianou | Agapidaki | Eirhni | Stylianou | NEA DIMOKRATIA | State | 19th | 19 | (28/05/2023 - 29/05/2023) | female | ND | New Democracy | Νέα Δημοκρατία | ΝΔ | #0492c2 | ||
| Skylakakis Theodoros Stefanou | Skylakakis | Theodoros | Stefanou | NEA DIMOKRATIA | State | 19th | 19 | (28/05/2023 - 29/05/2023) | male | ND | New Democracy | Νέα Δημοκρατία | ΝΔ | #0492c2 | ||
| Stylianidis Chrhstos Meli | Stylianidis | Chrhstos | Meli | NEA DIMOKRATIA | State | 19th | 19 | (28/05/2023 - 29/05/2023) | male | ND | New Democracy | Νέα Δημοκρατία | ΝΔ | #0492c2 | ||
| Lytrivi Ioanna Dimitriou | Lytrivi | Ioanna | Dimitriou | NEA DIMOKRATIA | State | 19th | 19 | (28/05/2023 - 29/05/2023) | female | ND | New Democracy | Νέα Δημοκρατία | ΝΔ | #0492c2 | ||
| Stamatis Georgios Anastasiou | Stamatis | Georgios | Anastasiou | NEA DIMOKRATIA | State | 19th | 19 | (28/05/2023 - 29/05/2023) | male | ND | New Democracy | Νέα Δημοκρατία | ΝΔ | #0492c2 |
Number of Parties
With the data tidied, I will begin the analysis with a historical overview of the number of parties represented in the Hellenic Parliament that completed a full term as a parliamentary group. After the fall of the junta, the parties in Parliament were quite few, limited to the historic ones: KKE, New Democracy, and PASOK. As a result, the Parliament of 1981 consisted of only three parties.
Show the code
plot_parliament(clean_dataset, 3, lang = "en")Show the code
gt_parliament(clean_dataset, 3) |>
gt_custom(head_max = Inf, use_labels = FALSE)| Party | Seats |
|---|---|
| PASOK | 172 |
| ND | 115 |
| KKE | 13 |
As the conditions of the post-junta transition matured, room opened for other voices to be heard, which crystallized into new parties. After the 1981 to 1985 term, new forces began appearing in Parliament with small shares. The most significant in terms of seat count was Synaspismos (the precursor to SYRIZA), which maintained a long parliamentary presence, albeit with small and precarious representation.
Show the code
plot_parliament(clean_dataset, 5, lang = "en")Show the code
gt_parliament(clean_dataset, 5) |>
gt_custom(head_max = Inf, use_labels = FALSE)| Party | Seats |
|---|---|
| ND | 145 |
| PASOK | 125 |
| SYRIZA | 28 |
| DIANA | 1 |
| Independent | 1 |
In broad terms, the post-junta period can be divided into three stages with respect to the number of parliamentary groups. The first stage (1974 to 1981) was a transitional period in which the country emerged from dictatorship and the party landscape was still taking shape. The second stage (1981 to 2009) is characterized by relative stability, with between three and five parliamentary groups in each term. The final period (2009 to the present) begins alongside the first signs of the sovereign debt crisis. In parliamentary terms, the public’s frustration with the political system and the policies that led the country into economic difficulty expressed itself in a sharp increase in the number of parliamentary groups. There are at least two readings of this: either the existing voices did not cover a wide enough range of society’s views, or there was enormous disillusionment with the policy decisions of the established parties.
Show the code
plot_parliament(clean_dataset, 13, lang = "en")Show the code
gt_parliament(clean_dataset, 13) |>
gt_custom(head_max = Inf, use_labels = FALSE)| Party | Seats |
|---|---|
| PASOK | 129 |
| ND | 72 |
| Independent | 31 |
| KKE | 21 |
| LAOS | 16 |
| SYRIZA | 12 |
| ANEL | 10 |
| DIMAR | 10 |
The full extent of this destabilization is evident in the composition of the 15th term Parliament, where the number of parliamentary groups reached its highest level in the post-junta era.
Show the code
plot_parliament(clean_dataset, 15, lang = "en")Show the code
gt_parliament(clean_dataset, 15) |>
gt_custom(head_max = Inf, use_labels = FALSE)| Party | Seats |
|---|---|
| ND | 127 |
| SYRIZA | 71 |
| PASOK | 28 |
| ADP | 17 |
| GD | 16 |
| ANEL | 12 |
| KKE | 12 |
| DIMAR | 11 |
| Independent | 7 |
The chart below includes a number of independent MPs classified as such by the Hellenic Parliament website. That period is generally characterized by intense governmental instability, and many of those MPs originally came from Independent Greeks and the Union of Centrists. A large wave of defections from those parties meant they no longer met the threshold to maintain parliamentary group status. As a result, even MPs who did not personally defect were recorded as independents once their group dissolved.
And finally, the complete overhaul of the political landscape, with a party that had once struggled to enter Parliament at all ending up winning the most seats.
Show the code
plot_parliament(clean_dataset, 17, lang = "en")Show the code
gt_parliament(clean_dataset, 17) |>
gt_custom(head_max = Inf, use_labels = FALSE)| Party | Seats |
|---|---|
| SYRIZA | 144 |
| ND | 77 |
| Independent | 25 |
| PASOK | 19 |
| GD | 16 |
| KKE | 15 |
| River | 5 |
All of this is neatly summarized in the time series below, which counts the number of distinct parliamentary groups per term. The three stages I described earlier come through clearly: the early post-junta period, the stable middle era, and the sharp increase in group fragmentation.
Show the code
r <- clean_dataset %>%
distinct(period_num, period_name, dates, abbrNamesEn) %>%
count(period_num, period_name, dates, name = "n") %>%
arrange(period_num)
series_data <- lapply(1:nrow(r), function(i) {
list(name = r$period_name[i], y = r$n[i], dates = r$dates[i])
})
highchart() %>%
hc_chart(type = "spline") %>%
hc_title(
text = "Number of Parliamentary Groups per Term",
style = list(fontWeight = "bold")
) %>%
hc_subtitle(text = "Hellenic Parliament - Post-junta period") %>%
hc_add_series(
name = "Parliamentary Groups",
data = series_data,
color = "#1F3A93",
lineWidth = 2.5,
marker = list(radius = 4, symbol = "circle")
) %>%
hc_xAxis(
type = "category",
title = list(text = "Parliamentary Term"),
labels = list(rotation = 0)
) %>%
hc_yAxis(
title = list(text = "Number of Groups"),
allowDecimals = FALSE,
gridLineColor = "#E6E6E6",
gridLineWidth = 1
) %>%
hc_tooltip(
useHTML = TRUE,
backgroundColor = "white",
borderColor = "#CCCCCC",
formatter = JS(
"function() {
return '<b>Term:</b> ' + this.point.name + '<br/>' +
'<b>Duration:</b> ' + this.point.dates + '<br/>' +
'<b>Groups:</b> ' + this.point.y;
}"
)
) %>%
hc_plotOptions(
series = list(
dataLabels = list(enabled = FALSE),
states = list(hover = list(lineWidthPlus = 0))
)
) %>%
hc_legend(enabled = FALSE) %>%
hc_credits(enabled = FALSE)Show the code
clean_dataset %>%
distinct(period_num, period_name, dates, abbrNamesEn) %>%
count(period_num, period_name, dates, name = "n") %>%
arrange(period_num) %>%
select(period_num, period_name, n) %>%
rename("Term No." = period_num, "Term" = period_name, "Count" = n) %>%
gt_custom(head_max = Inf, use_labels = FALSE)| Term No. | Term | Count |
|---|---|---|
| 1 | 1st | 7 |
| 2 | 2nd | 7 |
| 3 | 3nd | 3 |
| 4 | 4th | 5 |
| 5 | 5th | 5 |
| 6 | 6th | 5 |
| 7 | 7th | 6 |
| 8 | 8th | 4 |
| 9 | 9th | 6 |
| 10 | 10th | 5 |
| 11 | 11th | 5 |
| 12 | 12th | 5 |
| 13 | 13th | 8 |
| 14 | 14th | 7 |
| 15 | 15th | 9 |
| 16 | 16th | 8 |
| 17 | 17th | 7 |
| 18 | 18th | 7 |
| 19 | 19th | 5 |
Note that at this point I have not yet managed to set the left-right positioning of parties in the parliament diagrams. Doing so would allow the chart to convey both the seat count and the general political position of each group. For now, the diagrams should be read solely in terms of seat numbers and not as any indication of political alignment.
Electability
The electoral results were more or less well known; it is always interesting to put your knowledge to the test with R. But now I want to get to the more substantive questions. A common criticism of the political system is that the same people keep getting elected. That criticism, however, cannot be directed solely at politicians; it also applies to the portion of the electorate that keeps voting for them. You cannot expect to see change in the political system if you alternate power between two or three parties, let alone when you persist in re-electing the same individuals. So what actually happened in Greece? Do our MPs change at regular intervals, or are the same faces continuously returned? In this section I will identify the MPs who have been elected the most times.
The calculation requires knowing each person’s election frequency, and it is essential to use the full name including the patronymic, since many surnames are shared. Proper handling of names is particularly important here because the Hellenic Parliament is also known for dynasties, and without distinguishing by full name I could end up attributing extra terms to a single individual.
Show the code
u = clean_dataset |>
select(name, surname1, name1, fullNamesEn, abbrNamesEn, Color) |>
count(name, surname1, name1, fullNamesEn, abbrNamesEn, Color) |>
dplyr::filter(n >= 9) |>
arrange(-n) |>
mutate(
name1 = str_sub(name1, start = 1, end = 1),
surnameAndInitial = paste0(surname1, " ", name1, ".")
) %>%
arrange(desc(n))
highchart() %>%
hc_chart(type = "bar") %>%
hc_title(text = "Most frequently elected MPs") %>%
hc_subtitle(text = "Number of times they represented their party in the Hellenic Parliament") %>%
hc_xAxis(categories = u$surnameAndInitial) %>%
hc_yAxis(title = list(text = "Times elected")) %>%
hc_series(
list(
name = "# Times elected",
data = lapply(1:nrow(u), function(i) {
list(y = u$n[i], affiliate = u$abbrNamesEn[i], color = u$Color[i])
}),
dataLabels = list(
enabled = TRUE,
format = "{y}",
style = list(fontSize = "12px", textOutline = "none", color = "#FFFFFF")
)
)
) %>%
hc_plotOptions(
bar = list(borderRadius = 3, pointPadding = 0.2, groupPadding = 0.1)
) %>%
hc_tooltip(
headerFormat = "",
pointFormat = "<b>{point.category}</b><br/>
Party: <b>{point.affiliate}</b><br/>
Elected: <b>{point.y}</b> times"
) %>%
hc_legend(enabled = FALSE) %>%
hc_caption(
text = "Colors represent different party affiliations",
style = list(fontSize = "12px", color = "#666666")
)Filtering for MPs with 11 or more terms, we find that 8 MPs belong to this group. All of them come from the two major parties, New Democracy and PASOK, with Kaklamanis and Papandreou being the most frequently re-elected PASOK members. To find MPs from other parties we have to lower the bar considerably, to 9 or 10 terms: Papariga was elected 10 times with KKE and Dragasakis 9 times with SYRIZA.
Party-level Electability
So far we have looked at which members of parliament, from 1981 through 2019, were elected the most times according to the party they represented. It would be particularly useful to study this same characteristic within each party separately. This comparison has some limitations, since some parties either had limited parliamentary representation or did not last long enough to accumulate many terms. For that reason I will analyse only the most historically significant parties: KKE, ND, PASOK, and SYRIZA.
As for implementation, using a function here makes sense. The chart type is the same throughout; the only thing that changes is the party being filtered. This avoids repeating code, one of the fundamental principles of programming. The party_plot function accepts six arguments:
-
dataset: The full tidy dataset -
party: Which party to examine (English abbreviation) -
times_elected_min: A threshold I added later. The problem with a single fixed threshold is that there are large differences between parties with long histories and high vote shares versus those with shorter runs or lower support. A high threshold leaves very few observations for smaller parties; a low threshold floods the ND and PASOK charts with entries that become unreadable. -
title_textandsubtitle_text: Custom title and subtitle for each party chart -
party_color: Bar color matching the party’s visual identity
Show the code
party_plot <- function(dataset, party, times_elected_min = 2,
title_text = NULL, subtitle_text = NULL,
party_color = "#1F3A93") {
party_df <- dataset %>%
dplyr::filter(abbrNamesEn == party) %>%
count(name, surname1, name1) %>%
arrange(-n) %>%
drop_na() %>%
dplyr::filter(n >= times_elected_min) %>%
mutate(fullname = paste0(surname1, " ", name1)) %>%
separate(fullname, into = c("lastName", "firstName"), sep = " ", extra = "merge") %>%
mutate(
fullName = paste0(lastName, " ", firstName),
lastNameAndInitial = paste0(lastName, " ", str_sub(firstName, 1, 1), ".")
)
hc <- highchart() %>%
hc_chart(type = "bar", inverted = TRUE) %>%
hc_title(
text = title_text,
style = list(fontWeight = "bold", fontSize = "16px")
) %>%
hc_subtitle(
text = subtitle_text,
style = list(color = "#555555", fontSize = "12px")
) %>%
hc_xAxis(
categories = party_df$lastNameAndInitial,
title = list(text = NULL),
labels = list(
style = list(fontSize = "11px", whiteSpace = "nowrap"),
useHTML = TRUE
)
) %>%
hc_yAxis(
title = list(text = "(#) Times elected"),
allowDecimals = FALSE,
gridLineColor = "#E6E6E6",
gridLineWidth = 1
) %>%
hc_add_series(
name = "Times elected",
data = party_df$n,
color = party_color
) %>%
hc_plotOptions(
bar = list(dataLabels = list(enabled = FALSE))
) %>%
hc_tooltip(
useHTML = TRUE,
headerFormat = "",
pointFormat = paste0(
"<b>{point.category}</b><br/>",
"Party: <b>", party, "</b><br/>",
"Elected: <b>{point.y}</b> times"
)
) %>%
hc_legend(enabled = FALSE) %>%
hc_credits(enabled = FALSE)
return(hc)
}Results are presented in alphabetical order by party name.
KKE
The Communist Party of Greece was founded in November 1918 as the Socialist Labour Movement of Greece (SEKE), in the wake of the October Revolution. In 1920 it joined the Communist International (Comintern) and in 1924 was renamed the Communist Party of Greece (KKE). Under the dictatorship of Ioannis Metaxas, the KKE was banned and many of its members were imprisoned or exiled. During the German occupation (1941 to 1944) the KKE participated in the resistance by founding the National Liberation Front (EAM) and its military wing, ELAS. After liberation, a major conflict culminated in the Civil War (1946 to 1949), which the Democratic Army of Greece under communist leadership lost. The KKE remained an outlawed party for many years until it was legalized by Konstantinos Karamanlis in 1974. To this day it has stayed firm on its positions, most notably advocating for Greek withdrawal from the European Union and NATO.

Aleka Papariga (Athens, 1945) is the most frequently elected female MP in the history of the Hellenic Parliament (1981 to 2019). She served as leader of the Communist Party of Greece (KKE).
Photo credit: Wikimedia Commons, 2015 - License: CC BY-SA 2.0. Original image available at this link.
Show the code
party_plot(
dataset = clean_dataset,
party = "KKE",
times_elected_min = 5,
title_text = "KKE MPs with more than 5 terms",
subtitle_text = "Number of elections per MP",
party_color = "#FF6666"
)ND
New Democracy was founded in October 1974 by Konstantinos Karamanlis, immediately after the fall of the dictatorship. It is considered the political successor of the National Radical Union (ERE) and is positioned in the centre-right. In the first post-junta elections it won a sweeping majority that allowed the drafting of a new Constitution and a referendum on the form of government. After the Karamanlis government, the party spent a long period in opposition (1981 to 1990), until it returned to power under Konstantinos Mitsotakis. It then alternated in office with PASOK, forming one stable pole of the Greek two-party system. During the crisis years, under Antonis Samaras, it formed a coalition government, and since 2019 it has governed under Kyriakos Mitsotakis.

Konstantinos Mitsotakis (Halepa, Chania, 1918 to 2017) was a Greek politician who served as Prime Minister from 1990 until October 1993. His son, Kyriakos Mitsotakis, became party leader in 2016 and was elected Prime Minister in 2019.
Photo credit: Greek Literary and Historical Archive, National Bank of Greece Cultural Foundation, 1950 - License: CC BY. Image has been cropped and background removed. Original found on Europeana.
Show the code
party_plot(
dataset = clean_dataset,
party = "ND",
times_elected_min = 10,
title_text = "ND MPs with more than 10 terms",
subtitle_text = "Number of elections per MP",
party_color = "#0492c2"
)PASOK
The Panhellenic Socialist Movement (PASOK) was founded on 3 September 1974 by Andreas Papandreou. It was positioned in the centre-left with a radical rhetoric in its early years that gradually moderated. In 1981 it won the elections with a sweeping majority, opening a long period of dominance. During the 1980s it carried out significant social reforms but faced criticism for expanding the public sector and accumulating debt. After the death of Andreas Papandreou in 1996, Kostas Simitis took the helm and led the country into the Eurozone. The 2010 economic crisis deeply scarred the party, as the government of G. Papandreou signed the first Memorandum of Understanding. The electoral collapse that followed was unprecedented: from 43.9% in 2009 to 4.7% in January 2015. In recent years, under Nikos Androulakis, the party has been trying to recover as a third force.

Andreas G. Papandreou (Chios, 1919 to 1996) was a Greek politician and founder of PASOK. He served as Prime Minister from 1981 to 1989 and again from October 1993 to January 1996. Among his government’s major social reforms were the abolition of the dowry system, the introduction of civil marriage, and the lowering of the voting age from 21 to 18. He also founded the National Health System (ESY). He has been criticized for a massive expansion of public spending, rising national debt, and a non-transparent increase in public sector employment. His son, Georgios A. Papandreou, served as Prime Minister from 2009 to 2011.
Photo credit: Wikimedia, 1981 - License: Public Domain. Original found on Europeana.
Show the code
party_plot(
dataset = clean_dataset,
party = "PASOK",
times_elected_min = 10,
title_text = "PASOK MPs with more than 10 terms",
subtitle_text = "Number of elections per MP",
party_color = "#95bb72"
)SYRIZA
The Coalition of the Left and Progress was founded in 1989 as an electoral alliance of the KKE and EAR (a successor to the interior KKE), together with other smaller centre-left parties. In 1991 it became a unified party, absorbing the alliance’s members. Until 2012 it remained a small parliamentary force with vote shares rarely exceeding 5%. Its explosive rise coincided with the economic crisis: from 4.6% in 2009 to 26.9% in June 2012 and finally 36.3% in January 2015, winning the election. Under Alexis Tsipras, it governed in coalition with Independent Greeks (ANEL) and, despite its anti-austerity rhetoric, ultimately signed a third Memorandum. It was defeated in 2019 and suffered further significant losses in 2023. What makes SYRIZA analytically unique is how it shot from minor-party status to official opposition and then government within just a few years.
Show the code
party_plot(
dataset = clean_dataset,
party = "SYRIZA",
times_elected_min = 5,
title_text = "SYRIZA MPs with more than 5 terms",
subtitle_text = "Number of elections per MP",
party_color = "#e27bb1"
)Two-party Dominance in Greece
The persistent loyalty to both parties and to the same individuals is clear. An interesting metric is the degree of two-party dominance, that is the combined seat share of the two largest parties. As we know, this tendency was quite strong especially in the early post-junta years. In this section I will not analyse electoral vote shares directly, but rather the seats held by elected MPs, and I will examine what percentage of those seats belong to the top two parties. It should be noted that there can be a substantial gap between vote shares and seat shares, mainly because of the seat bonus awarded to the winning party and the exclusion of sub-threshold parties. It is interesting to track this polarization over time: a declining share might signal some degree of voter pushback against the established system. The chart shows extraordinarily high two-party seat shares. During the crisis years the combined share fell significantly, from around 80% to roughly 60%. We know from earlier sections that the Hellenic Parliament saw a sharp increase in parliamentary groups during the crisis. Putting these findings together, it appears that there was a popular reaction that began with the onset of the economic crisis, which, while it did not fundamentally transform the party system, did break the duopoly and spread voter discontent across a range of smaller parties.
Show the code
f <- clean_dataset %>%
group_by(period_num, period_name, dates, abbrNamesEn) %>%
count() %>%
ungroup(abbrNamesEn) %>%
top_n(n = 2, wt = n) %>%
pivot_wider(names_from = abbrNamesEn, values_from = n) %>%
mutate(
seatsTopTwoParties = rowSums(
across(any_of(c("ND", "PASOK", "SYRIZA"))),
na.rm = TRUE
)
) %>%
mutate(
pctSeatsTopTwoParties = round((seatsTopTwoParties / 300) * 100, digits = 1)
) %>%
arrange(period_num)
series_data_f <- lapply(1:nrow(f), function(i) {
list(name = f$period_name[i], y = f$pctSeatsTopTwoParties[i], dates = f$dates[i])
})
highchart() %>%
hc_chart(type = "spline") %>%
hc_title(
text = "Two-party seat dominance over time",
style = list(fontWeight = "bold")
) %>%
hc_subtitle(
text = "Percentage (%) of seats held by the top two parties per term"
) %>%
hc_xAxis(
type = "category",
title = list(text = "Parliamentary Term"),
labels = list(rotation = -45, style = list(fontSize = "11px"))
) %>%
hc_yAxis(
title = list(text = "Seat share of top two parties (%)"),
gridLineColor = "#E6E6E6",
gridLineWidth = 1,
max = 100,
min = 0
) %>%
hc_add_series(
name = "Share",
data = series_data_f,
color = "#6366F1",
lineWidth = 3,
marker = list(enabled = TRUE, radius = 5, symbol = "circle")
) %>%
hc_tooltip(
useHTML = TRUE,
headerFormat = "",
pointFormat = "
<b>Term:</b> {point.name}<br/>
<b>Duration:</b> {point.dates}<br/>
<b>Seat share:</b> <b>{point.y}%</b>
",
backgroundColor = "#ffffff",
borderColor = "#e5e7eb",
style = list(color = "#111827", fontSize = "13px")
) %>%
hc_plotOptions(
spline = list(states = list(hover = list(lineWidthPlus = 0)))
) %>%
hc_legend(enabled = FALSE) %>%
hc_credits(enabled = FALSE)Female Representation
An important indicator of a parliament’s health, and by extension of society’s, is how representative it is. Can all voices and all social concerns be heard? One of the most obvious indicators is the degree to which society evolves and accepts women as equally capable representatives in the legislative branch. Historically, Greece has performed poorly in this area, with women consistently underrepresented in the labour market. The same social stereotypes appear to persist, producing persistently low rates of female MP election. Through the first ten terms of the Hellenic Parliament, women represented less than 10% of total MPs. In recent years the situation has improved and female parliamentary presence has become somewhat normalized, though equal representation has not been achieved. It is worth noting that women in Greece obtained the right to vote in 1952. We have now completed 70 years since women could both vote and stand for election, and female representation still stands at around one quarter of parliamentary seats. As a country we have institutionalized gender equality, but we have not yet developed the social maturity needed to overcome the biases about capability and the extent to which gender is used as a criterion for evaluating a person.

Eleni Skoura (Volos, 1896 to 1991) was the first Greek female member of parliament, elected in 1953, one year after the right to vote and stand for election was extended to women.
Photo credit: Greek Literary and Historical Archive, National Bank of Greece Cultural Foundation, 1940 - License: CC BY. Image has been cropped and converted to sketch. Original found on Europeana.
Show the code
test <- clean_dataset |> select(period_num, period_name, dates, gender)
test1 <- test |>
group_by(period_num, period_name, dates, gender) |>
count() |>
pivot_wider(names_from = gender, values_from = n, values_fill = 0)
make_gender_series <- function(values, df) {
lapply(1:nrow(df), function(i) {
list(name = df$period_name[i], y = values[i], dates = df$dates[i])
})
}
colors <- c("#90C3FF", "#FF9090")
highchart() %>%
hc_chart(type = "areaspline") %>%
hc_title(
text = "Parliamentary representatives by gender per term",
style = list(fontSize = "20px", fontWeight = "bold")
) %>%
hc_subtitle(
text = "In the last five terms, female representation has remained below one quarter",
style = list(fontSize = "12px", color = "#555555")
) %>%
hc_xAxis(
type = "category",
title = list(text = "Parliamentary Term"),
labels = list(rotation = 0, style = list(fontSize = "11px"))
) %>%
hc_yAxis(
title = list(text = "Percentage (%)"),
labels = list(format = "{value}%"),
max = 100,
gridLineColor = "#E6E6E6",
gridLineWidth = 1
) %>%
hc_colors(colors) %>%
hc_plotOptions(
areaspline = list(
stacking = "percent",
lineWidth = 2,
fillOpacity = 0.6,
marker = list(enabled = FALSE)
)
) %>%
hc_add_series(
name = "Male MPs",
data = make_gender_series(test1$`άνδρας`, test1)
) %>%
hc_add_series(
name = "Female MPs",
data = make_gender_series(test1$`γυναίκα`, test1)
) %>%
hc_tooltip(
shared = TRUE,
useHTML = TRUE,
formatter = JS("
function() {
var total = 0;
for (var i = 0; i < this.points.length; i++) {
total += this.points[i].y;
}
var periodName = this.points[0].point.name;
var dates = this.points[0].point.dates;
var s = '<b>Term: ' + periodName + '</b><br/>';
s += '<span style=\"color:#666\">Duration: ' + dates + '</span><br/><br/>';
for (var i = 0; i < this.points.length; i++) {
var pct = Math.round((this.points[i].y / total) * 100);
s += '<span style=\"color:' + this.points[i].color + '\">●</span> ' +
'<b>' + this.points[i].series.name + ':</b> ' +
this.points[i].y + ' (' + pct + '%)<br/>';
}
return s;
}
"),
backgroundColor = "#ffffff",
borderColor = "#e5e7eb",
style = list(color = "#111827", fontSize = "13px")
) %>%
hc_legend(
layout = "horizontal",
align = "center",
verticalAlign = "bottom"
) %>%
hc_credits(enabled = FALSE)Warning: Unknown or uninitialised column: `γυναίκα`.
Warning: Unknown or uninitialised column: `άνδρας`.
Of course, placing all the blame on society is somewhat unfair, given that the parties themselves select their candidates and promote certain individuals more heavily. Could it be that parties also fail to put forward women candidates on equal terms? To investigate this, the analysis was extended to the party level, examining the male-to-female ratio among all elected MPs per party. The data show that New Democracy, as the more conservative party, has consistently had very low female representation. On the other side of the spectrum, left-wing parties show a markedly different picture, with a stable and significantly higher share of women. Among parties with a continuous parliamentary presence, KKE achieved the highest female share in the 11th term, followed by SYRIZA in the 15th term at 38%, a figure that was not only percentagewise significant but also notable in absolute numbers given SYRIZA’s high seat count at the time.

Vasiliki Thanou (Chalcis, 1950) is the only woman to have served as Prime Minister of Greece. She served in a caretaker capacity when the SYRIZA-ANEL government resigned and snap elections were called. She remains to this day the sole woman to have held that office.
Photo credit: Wikimedia Commons, 2015 - License: CC BY-SA 2.0. Image has been lightly edited.
Show the code
test = clean_dataset |> select(period_num, period_name, dates, gender, abbrNamesEn)
test1 = test |>
group_by(period_num, period_name, dates, gender, abbrNamesEn) |>
count() |>
pivot_wider(names_from = gender, values_from = n) %>%
mutate(across(c(male, female), ~ replace_na(., 0))) %>%
mutate(
sum = male + female,
pct = round(100 * (female / sum), 1)
) %>%
ungroup() %>%
select(period_num, period_name, dates, abbrNamesEn, pct) %>%
dplyr::filter(abbrNamesEn %in% c("SYRIZA", "ND", "PASOK", "KKE")) %>%
pivot_wider(names_from = abbrNamesEn, values_from = pct) %>%
dplyr::filter(period_num > 9) %>%
arrange(period_num)
make_party_series <- function(values, df) {
lapply(1:nrow(df), function(i) {
list(
name = df$period_name[i],
y = values[i],
dates = df$dates[i],
period_name = df$period_name[i]
)
})
}
highchart() %>%
hc_chart(type = "spline") %>%
hc_title(text = "Female representation by party") %>%
hc_subtitle(
text = "New Democracy has never exceeded 17% female MPs in its history, in contrast to other historic parties."
) %>%
hc_xAxis(
type = "category",
categories = test1$period_name,
title = list(text = "Parliamentary Term")
) %>%
hc_yAxis(
title = list(text = "Share (%) of female MPs"),
min = 0,
max = 50,
gridLineColor = "#E6E6E6",
gridLineWidth = 1,
plotLines = list(list(
value = 25,
color = "#cccccc",
dashStyle = "Dash",
width = 1,
label = list(text = "25%", style = list(color = "#999999"))
))
) %>%
hc_add_series(
name = "KKE",
data = make_party_series(test1$KKE, test1),
color = "#FF6666",
lineWidth = 3,
marker = list(radius = 5, symbol = "circle")
) %>%
hc_add_series(
name = "ND",
data = make_party_series(test1$ND, test1),
color = "#0492c2",
lineWidth = 3,
marker = list(radius = 5, symbol = "circle")
) %>%
hc_add_series(
name = "PASOK",
data = make_party_series(test1$PASOK, test1),
color = "#95bb72",
lineWidth = 3,
marker = list(radius = 5, symbol = "circle")
) %>%
hc_add_series(
name = "SYRIZA",
data = make_party_series(test1$SYRIZA, test1),
color = "#e27bb1",
lineWidth = 3,
marker = list(radius = 5, symbol = "circle")
) %>%
hc_tooltip(
shared = TRUE,
useHTML = TRUE,
formatter = JS("
function() {
var periodName = this.points[0].point.name;
var dates = this.points[0].point.dates;
var s = '<b>Term: ' + periodName + '</b><br/>';
s += '<span style=\"color:#666\">Duration: ' + dates + '</span><br/><br/>';
for (var i = 0; i < this.points.length; i++) {
var val = this.points[i].y !== null ? this.points[i].y + '%' : 'N/A';
s += '<span style=\"color:' + this.points[i].color + '\">●</span> ' +
'<b>' + this.points[i].series.name + ':</b> ' + val + '<br/>';
}
return s;
}
"),
backgroundColor = "#ffffff",
borderColor = "#e5e7eb",
style = list(color = "#111827", fontSize = "13px")
) %>%
hc_plotOptions(
spline = list(states = list(hover = list(lineWidthPlus = 0)))
) %>%
hc_legend(
layout = "horizontal",
align = "center",
verticalAlign = "bottom"
) %>%
hc_credits(enabled = FALSE)Constituency-level Electability
At this point I have computed:
- The composition of parliament per term
- The most frequently elected MPs at the national level
- The most frequently elected MPs at the party level
Now I will identify the most popular MPs at the constituency level. The same logic as in the previous section applies here, with minor modifications. Using functions is almost mandatory in this case, since there are 50 constituencies. I will use the count function to compute frequencies.
Show the code
constituency_freqs <- function(input_constituency, min_times_elected) {
cont_df = clean_dataset %>%
dplyr::filter(region == input_constituency) %>%
count(surname1, name1, fullNamesEn, abbrNamesEn, Color) %>%
arrange(-n) |>
dplyr::filter(n >= min_times_elected) %>%
mutate(FullNameInitial = paste0(surname1, " ", str_sub(name1, 1, 1), "."))
highchart() %>%
hc_chart(type = "bar") %>%
hc_title(text = "Most frequently elected MPs") %>%
hc_subtitle(text = "Number of times they represented their party in the Hellenic Parliament") %>%
hc_xAxis(categories = cont_df$FullNameInitial) %>%
hc_yAxis(title = list(text = "Times elected")) %>%
hc_series(
list(
name = "# Times elected",
data = lapply(1:nrow(cont_df), function(i) {
list(y = cont_df$n[i], affiliate = cont_df$abbrNamesEn[i], color = cont_df$Color[i])
}),
dataLabels = list(
enabled = TRUE,
format = "{y}",
style = list(fontSize = "12px", textOutline = "none", color = "#FFFFFF")
)
)
) %>%
hc_plotOptions(
bar = list(borderRadius = 3, pointPadding = 0.2, groupPadding = 0.1)
) %>%
hc_tooltip(
headerFormat = "",
pointFormat = "<b>{point.category}</b><br/>
Party: <b>{point.affiliate}</b><br/>
Elected: <b>{point.y}</b> times"
) %>%
hc_legend(enabled = FALSE) %>%
hc_caption(
text = "Colors represent different party affiliations",
style = list(fontSize = "12px", color = "#666666")
)
}Nationwide
Show the code
constituency_freqs("ΕΠΙΚΡΑΤΕΙΑΣ", 3)Attica
Show the code
constituency_freqs("Athens A", 5)Show the code
constituency_freqs("Athens B", 7)Show the code
constituency_freqs("Piraeus A", 5)Show the code
constituency_freqs("Piraeus B", 5)Central Greece
Show the code
constituency_freqs("Viotia", 5)Show the code
constituency_freqs("Evrytania", 2)Show the code
constituency_freqs("Fokida", 2)Show the code
constituency_freqs("Fthiotida", 3)Central Macedonia
Show the code
constituency_freqs("Thessaloniki A", 6)Show the code
constituency_freqs("Thessaloniki B", 6)Show the code
constituency_freqs("Kilkis", 3)Show the code
constituency_freqs("Pella", 3)Show the code
constituency_freqs("Pieria", 3)Show the code
constituency_freqs("Serres", 3)Parliamentary Renewal
We observe that a small number of parties dominate the Greek political landscape and have proven remarkably durable over time. Despite the political turmoil and parliamentary reshuffling that accompanied the economic crisis, the new parties that emerged were mostly short-lived, and what we saw was essentially a reshuffling of voters among the historic parties rather than a genuine realignment. The absence of a meaningful political breakthrough by new forces means that choices largely remain confined to individuals within the existing parties. This raises an entirely logical question: granted that the vast majority of votes go to four parties, do voters at least push for fresh faces as their representatives? In other words, to what extent does each new parliamentary term consist of MPs who have never been elected before?
To implement this, I will extract two subsets of the tidy dataset corresponding to term n and all previous terms. I will then compare the name columns to see how many matches exist, that is, how many MPs were already in Parliament before. I also compare against all earlier terms, not just the immediately preceding one, so as to capture MPs who may have returned after skipping a term.
In this case I am studying the period 1981 to 2019 (3rd to 17th term), so the comparison meaningfully starts from the 2nd term (1977) to allow for a preceding reference point. The chart reveals strong tendencies toward the retention of familiar faces, with only two elections having produced a significant renewal that replaced roughly half the members with first-timers.
Show the code
get_new_members <- function(term) {
previous_parls <- clean_dataset |>
dplyr::filter(period_num < term) |>
dplyr::select(name)
current_parl <- clean_dataset |>
dplyr::filter(period_num == term) |>
dplyr::select(name)
how_many_current_term <- nrow(current_parl)
established_members <- sum(current_parl$name %in% previous_parls$name)
new_members <- how_many_current_term - established_members
return(list(established_members, new_members))
}
period_info <- clean_dataset %>%
distinct(period_num, period_name, dates) %>%
filter(period_num >= 2, period_num <= 17) %>%
arrange(period_num)
results <- lapply(2:17, get_new_members)
df <- data.frame(
num = 2:17,
established = sapply(results, `[[`, 1),
new = sapply(results, `[[`, 2)
) %>%
left_join(period_info, by = c("num" = "period_num"))
make_series <- function(values, df) {
lapply(1:nrow(df), function(i) {
list(name = df$period_name[i], y = values[i], dates = df$dates[i])
})
}
highchart() %>%
hc_chart(type = "areaspline") %>%
hc_title(
text = "Parliamentary renewal per term",
style = list(fontWeight = "bold")
) %>%
hc_subtitle(
text = "Share of MPs serving their first term in each parliamentary session"
) %>%
hc_xAxis(
type = "category",
title = list(text = "Parliamentary Term"),
labels = list(rotation = -45, style = list(fontSize = "11px"))
) %>%
hc_yAxis(
title = list(text = "Percentage (%)"),
labels = list(format = "{value}%"),
max = 100,
gridLineColor = "#E6E6E6",
gridLineWidth = 1
) %>%
hc_colors(c("#1f77b4", "#ff7f0e")) %>%
hc_plotOptions(
areaspline = list(
stacking = "percent",
marker = list(enabled = FALSE),
lineWidth = 2,
fillOpacity = 0.6
)
) %>%
hc_add_series(
name = "Returning MPs",
data = make_series(df$established, df)
) %>%
hc_add_series(
name = "First-term MPs",
data = make_series(df$new, df)
) %>%
hc_tooltip(
shared = TRUE,
useHTML = TRUE,
formatter = JS("
function() {
var total = 0;
for (var i = 0; i < this.points.length; i++) {
total += this.points[i].y;
}
var periodName = this.points[0].point.name;
var dates = this.points[0].point.dates;
var s = '<b>Term: ' + periodName + '</b><br/>';
s += '<span style=\"color:#666\">Duration: ' + dates + '</span><br/><br/>';
for (var i = 0; i < this.points.length; i++) {
var pct = Math.round((this.points[i].y / total) * 100);
s += '<span style=\"color:' + this.points[i].color + '\">●</span> ' +
'<b>' + this.points[i].series.name + ':</b> ' +
this.points[i].y + ' MPs (' + pct + '%)<br/>';
}
return s;
}
"),
backgroundColor = "#ffffff",
borderColor = "#e5e7eb",
style = list(color = "#111827", fontSize = "13px")
) %>%
hc_legend(
layout = "horizontal",
align = "center",
verticalAlign = "bottom"
) %>%
hc_credits(enabled = FALSE)Cumulative MP Count
Throughout this article I have studied how frequently parties or their representatives have been elected across a range of criteria. I thought it useful to close with a cumulative overview of the electoral results. The criticism of an absence of genuine political change is also expressed through the persistent dominance of representatives from specific parties. I therefore calculate the total number and share of MPs by the party they represented at the end of each term. PASOK and New Democracy are the parties whose combined representation exceeded three quarters of all MPs in the history of Parliament. Adding KKE and SYRIZA, the combined share of all four approaches 90%. All others are independents or members of smaller parties, which underscores just how far we are from a logic of political change.
Show the code
library(dplyr)
library(highcharter)
gh <- clean_dataset |>
count(abbrNamesEn) |>
arrange(-n) |>
mutate(abbrNamesEn = ifelse(n > 70, abbrNamesEn, "Other")) |>
group_by(abbrNamesEn) |>
mutate(n = sum(n)) |>
distinct() |>
ungroup() |>
mutate(pct = round((n / sum(n)) * 100, 1)) |>
left_join(
clean_dataset |>
group_by(abbrNamesEn) |>
summarise(Color = first(Color), .groups = "drop"),
by = "abbrNamesEn"
)
pie_data <- lapply(1:nrow(gh), function(i) {
list(name = gh$abbrNamesEn[i], y = gh$pct[i], color = gh$Color[i])
})
highchart() %>%
hc_chart(type = "pie", backgroundColor = NULL) %>%
hc_title(
text = "Cumulative MP representation by party (1981-2019)",
align = "center"
) %>%
hc_subtitle(
text = "PASOK and New Democracy account for 76% of all MPs in the history of the parliament"
) %>%
hc_plotOptions(pie = list(
startAngle = -90,
endAngle = 90,
center = c("50%", "75%"),
size = "110%",
innerSize = "60%",
showInLegend = TRUE,
dataLabels = list(
enabled = TRUE,
distance = -30,
style = list(fontSize = "12px"),
formatter = JS("function() { return '<b>'+ this.point.name +'</b>: '+ this.percentage.toFixed(1) +'%'; }")
)
)) %>%
hc_add_series(name = "Share", data = pie_data) %>%
hc_tooltip(pointFormat = '{series.name}: <b>{point.percentage:.1f}%</b>') %>%
hc_legend(layout = "horizontal", align = "center", verticalAlign = "bottom")Finally, it is equally interesting to look at the cumulative share of women in the Hellenic Parliament. The results are not encouraging: as we found in an earlier section, female representation has been historically low, with the highest recent share hovering around 25%. The picture does not improve when we aggregate across four decades: female MPs account for just 12.8% of all elected members. In absolute terms, this corresponds to 576 women compared to 3,927 male colleagues.
Show the code
gh = clean_dataset |>
count(gender) |>
arrange(-n) |>
mutate(pct = round(100 * (n / sum(n)), digits = 1)) |>
drop_na(gender)
colors <- c("#90C3FF", "#FF9090")
highchart() %>%
hc_chart(type = "pie") %>%
hc_title(
text = "Cumulative MP representation by gender (1981-2019)",
align = "center"
) %>%
hc_subtitle(
text = "Women have been historically underrepresented. Across the recent history of the Hellenic Parliament, women account for just 13% of all elected MPs."
) %>%
hc_plotOptions(pie = list(
startAngle = -90,
endAngle = 90,
center = c("50%", "75%"),
size = "110%",
innerSize = "60%",
showInLegend = TRUE,
dataLabels = list(
enabled = TRUE,
distance = -30,
style = list(fontSize = "12px"),
formatter = JS("function() { return '<b>'+ this.point.name +'</b>: '+ this.percentage.toFixed(1) +'%'; }")
)
)) %>%
hc_add_series(name = "Share", data = list_parse2(gh)) %>%
hc_colors(colors) %>%
hc_tooltip(pointFormat = '{series.name}: <b>{point.percentage:.1f}%</b>') %>%
hc_legend(layout = "horizontal", align = "center", verticalAlign = "bottom")Acknowledgements and Notes
Image by Leonhard Niederwimmer from Pixabay.
The scraped dataset used in this article is freely available from my repository on GitHub. The dataset and the original source of the information is the Hellenic Parliament website.
References
Citation
@online{2022,
author = {, stesiam},
title = {EDA on {Greek} {Parliament}},
date = {2022-10-10},
url = {https://stesiam.com/posts/eda-greek-parliament/},
langid = {en}
}
