{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Analysing the Petition for a General Election\n", "\n", "2024 general election results where downloaded from [here](https://commonslibrary.parliament.uk/research-briefings/cbp-10009/) on 29 November 2024. Petition results were downloaded using the following command on 29 November 2024:\n", "\n", "```shell\n", "curl https://petition.parliament.uk/petitions/700143.json | jq > data/election-petition-results.json\n", "```" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import json\n", "from pathlib import Path\n", "\n", "import matplotlib.pyplot as plt\n", "import pandas as pd\n", "import seaborn as sns\n", "from dotenv import find_dotenv\n", "\n", "ROOT_DIR = Path(find_dotenv(\"pyproject.toml\")).parent\n", "DATA_DIR = ROOT_DIR / \"data\"\n", "ELECTION_RESULTS_PATH = DATA_DIR / \"election-petition\" / \"HoC-GE2024-results-by-candidate.csv\"\n", "PETITION_RESULTS_PATH = DATA_DIR / \"election-petition\" / \"election-petition-results.json\"\n", "\n", "TOP_PARTIES = [\n", " \"Conservative\",\n", " \"Labour\",\n", " \"Liberal Democrat\",\n", " \"Reform UK\",\n", " \"Green\",\n", " \"Scottish National Party\",\n", " \"Plaid Cymru\",\n", " \"Independent\",\n", "]\n", "\n", "PARTY_COLOURS = {\n", " \"Conservative\": \"#0087DC\",\n", " \"Labour\": \"#E4003B\",\n", " \"Liberal Democrat\": \"#FAA61A\",\n", " \"Reform UK\": \"#12B6CF\",\n", " \"Green\": \"#02A95B\",\n", " \"Scottish National Party\": \"#FDF38E\",\n", " \"Plaid Cymru\": \"#005B54\",\n", " \"Independent\": \"grey\",\n", "}\n", "\n", "sns.set_style(\"ticks\")\n", "sns.set_palette(PARTY_COLOURS.values())" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Total petition signatures: 2,886,188\n", "Total petition signatures from per-consituency counts: 2,831,513\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "/tmp/ipykernel_59936/2971000648.py:54: FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version. Call result.infer_objects(copy=False) instead. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`\n", " .fillna({\"winner\": False})\n" ] } ], "source": [ "with PETITION_RESULTS_PATH.open(\"r\", encoding=\"utf-8\") as f:\n", " petition_results_json = json.load(f)\n", "\n", "petition_results_df = (\n", " pd.DataFrame.from_records(\n", " petition_results_json[\"data\"][\"attributes\"][\"signatures_by_constituency\"],\n", " exclude=[\"name\", \"mp\"],\n", " )\n", " .rename(columns={\"ons_code\": \"ons_id\"})\n", ")\n", "\n", "df = (\n", " pd.read_csv(\n", " ELECTION_RESULTS_PATH,\n", " header=0,\n", " usecols=[\n", " \"ONS ID\",\n", " \"Constituency name\",\n", " \"Region name\",\n", " \"Party name\",\n", " \"Votes\",\n", " \"Share\",\n", " ]\n", " )\n", " .rename(columns={\n", " \"ONS ID\": \"ons_id\",\n", " \"Constituency name\": \"constituency\",\n", " \"Region name\": \"region\",\n", " \"Party name\": \"party\",\n", " \"Votes\": \"votes\",\n", " \"Share\": \"share\",\n", " })\n", " .replace({\"party\": {\"Labour and Co-operative\": \"Labour\"}}) # Labour in Wales\n", " .merge(petition_results_df, on=\"ons_id\", how=\"left\")\n", ")\n", "\n", "df = (\n", " df\n", " .join(df.groupby(\"ons_id\")[\"votes\"].sum().rename(\"total_votes\"), how=\"left\", on=\"ons_id\")\n", " .assign(signatures_per_vote=lambda x: x[\"signature_count\"] / x[\"total_votes\"])\n", ")\n", "\n", "df = (\n", " df.merge(\n", " df\n", " .sort_values(\"votes\", ascending=False)\n", " .groupby(\"ons_id\")\n", " .first()[[\"party\", \"votes\"]]\n", " .assign(winner=True)\n", " .reset_index(),\n", " on=[\"ons_id\", \"party\", \"votes\"],\n", " how=\"left\",\n", " )\n", " .fillna({\"winner\": False})\n", ")\n", "\n", "print(f'Total petition signatures: {petition_results_json[\"data\"][\"attributes\"][\"signature_count\"]:,d}')\n", "print(f'Total petition signatures from per-consituency counts: {df.groupby(\"ons_id\")[\"signature_count\"].max().sum():,d}')" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " | ons_id | \n", "constituency | \n", "region | \n", "party | \n", "votes | \n", "share | \n", "signature_count | \n", "total_votes | \n", "signatures_per_vote | \n", "winner | \n", "
---|---|---|---|---|---|---|---|---|---|---|
0 | \n", "W07000081 | \n", "Aberafan Maesteg | \n", "Wales | \n", "Heritage Party | \n", "183 | \n", "0.005118 | \n", "3444 | \n", "35755 | \n", "0.096322 | \n", "False | \n", "
1 | \n", "W07000081 | \n", "Aberafan Maesteg | \n", "Wales | \n", "Independent | \n", "618 | \n", "0.017284 | \n", "3444 | \n", "35755 | \n", "0.096322 | \n", "False | \n", "
2 | \n", "W07000081 | \n", "Aberafan Maesteg | \n", "Wales | \n", "Liberal Democrat | \n", "916 | \n", "0.025619 | \n", "3444 | \n", "35755 | \n", "0.096322 | \n", "False | \n", "
3 | \n", "W07000081 | \n", "Aberafan Maesteg | \n", "Wales | \n", "Green | \n", "1094 | \n", "0.030597 | \n", "3444 | \n", "35755 | \n", "0.096322 | \n", "False | \n", "
4 | \n", "W07000081 | \n", "Aberafan Maesteg | \n", "Wales | \n", "Conservative | \n", "2903 | \n", "0.081191 | \n", "3444 | \n", "35755 | \n", "0.096322 | \n", "False | \n", "
... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "
4510 | \n", "E14001605 | \n", "York Outer | \n", "Yorkshire and The Humber | \n", "Green | \n", "2212 | \n", "0.043283 | \n", "4135 | \n", "51106 | \n", "0.080910 | \n", "False | \n", "
4511 | \n", "E14001605 | \n", "York Outer | \n", "Yorkshire and The Humber | \n", "Liberal Democrat | \n", "5496 | \n", "0.107541 | \n", "4135 | \n", "51106 | \n", "0.080910 | \n", "False | \n", "
4512 | \n", "E14001605 | \n", "York Outer | \n", "Yorkshire and The Humber | \n", "Reform UK | \n", "5912 | \n", "0.115681 | \n", "4135 | \n", "51106 | \n", "0.080910 | \n", "False | \n", "
4513 | \n", "E14001605 | \n", "York Outer | \n", "Yorkshire and The Humber | \n", "Conservative | \n", "13770 | \n", "0.269440 | \n", "4135 | \n", "51106 | \n", "0.080910 | \n", "False | \n", "
4514 | \n", "E14001605 | \n", "York Outer | \n", "Yorkshire and The Humber | \n", "Labour | \n", "23161 | \n", "0.453195 | \n", "4135 | \n", "51106 | \n", "0.080910 | \n", "True | \n", "
4515 rows × 10 columns
\n", "