{
"cells": [
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"import json\n",
"\n",
"from branca.colormap import linear\n",
"import folium\n",
"from folium import Map, Marker, GeoJson, LayerControl\n",
"import pandas as pd\n",
"import geopandas as gpd\n",
"\n",
"%matplotlib inline"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Load and explore geojson"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"gj_path = \"geojson/anc.geojson\""
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"anc_df = gpd.read_file(gj_path)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" OBJECTID | \n",
" ANC_ID | \n",
" WEB_URL | \n",
" NAME | \n",
" Shape_Leng | \n",
" Shape_Area | \n",
" geometry | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 1 | \n",
" 1C | \n",
" http://anc.dc.gov/page/advisory-neighborhood-c... | \n",
" ANC 1C | \n",
" 5218.954361 | \n",
" 1.285112e+06 | \n",
" POLYGON ((-77.0464219248981 38.92597950466725,... | \n",
"
\n",
" \n",
" | 1 | \n",
" 2 | \n",
" 1D | \n",
" http://anc.dc.gov/page/advisory-neighborhood-c... | \n",
" ANC 1D | \n",
" 4224.010068 | \n",
" 9.475922e+05 | \n",
" POLYGON ((-77.03645123520528 38.93638367371454... | \n",
"
\n",
" \n",
" | 2 | \n",
" 3 | \n",
" 2A | \n",
" http://anc.dc.gov/page/advisory-neighborhood-c... | \n",
" ANC 2A | \n",
" 12477.943204 | \n",
" 7.065358e+06 | \n",
" POLYGON ((-77.05445304334567 38.90725341205063... | \n",
"
\n",
" \n",
" | 3 | \n",
" 4 | \n",
" 2B | \n",
" http://anc.dc.gov/page/advisory-neighborhood-c... | \n",
" ANC 2B | \n",
" 7712.504785 | \n",
" 2.160620e+06 | \n",
" POLYGON ((-77.0412259402753 38.91701561959232,... | \n",
"
\n",
" \n",
" | 4 | \n",
" 5 | \n",
" 2C | \n",
" http://anc.dc.gov/page/advisory-neighborhood-c... | \n",
" ANC 2C | \n",
" 7811.084627 | \n",
" 2.861750e+06 | \n",
" POLYGON ((-77.02404971019487 38.90293630338282... | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" OBJECTID ANC_ID WEB_URL NAME \\\n",
"0 1 1C http://anc.dc.gov/page/advisory-neighborhood-c... ANC 1C \n",
"1 2 1D http://anc.dc.gov/page/advisory-neighborhood-c... ANC 1D \n",
"2 3 2A http://anc.dc.gov/page/advisory-neighborhood-c... ANC 2A \n",
"3 4 2B http://anc.dc.gov/page/advisory-neighborhood-c... ANC 2B \n",
"4 5 2C http://anc.dc.gov/page/advisory-neighborhood-c... ANC 2C \n",
"\n",
" Shape_Leng Shape_Area \\\n",
"0 5218.954361 1.285112e+06 \n",
"1 4224.010068 9.475922e+05 \n",
"2 12477.943204 7.065358e+06 \n",
"3 7712.504785 2.160620e+06 \n",
"4 7811.084627 2.861750e+06 \n",
"\n",
" geometry \n",
"0 POLYGON ((-77.0464219248981 38.92597950466725,... \n",
"1 POLYGON ((-77.03645123520528 38.93638367371454... \n",
"2 POLYGON ((-77.05445304334567 38.90725341205063... \n",
"3 POLYGON ((-77.0412259402753 38.91701561959232,... \n",
"4 POLYGON ((-77.02404971019487 38.90293630338282... "
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"anc_df.head()"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"# Tried this to reduce the map complexity for Chrome, didn't work\n",
"# anc_df.geometry = anc_df.geometry.simplify(500, preserve_topology=False)"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [],
"source": [
"def embed_map(m):\n",
" from IPython.display import IFrame\n",
"\n",
" m.save('inline_map.html')\n",
" return IFrame('inline_map.html', width='100%', height='750px')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Preprocess data and join with election CSV using pandas"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" ward | \n",
" year | \n",
" anc | \n",
" num_candidates | \n",
" votes | \n",
" vote_norm | \n",
" engagement | \n",
" prop_uncontested | \n",
" prop_empty | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 1 | \n",
" 2012 | \n",
" A | \n",
" 1.583333 | \n",
" 481.500000 | \n",
" NaN | \n",
" NaN | \n",
" 0.500000 | \n",
" 0.0 | \n",
"
\n",
" \n",
" | 1 | \n",
" 1 | \n",
" 2012 | \n",
" B | \n",
" 1.250000 | \n",
" 544.333333 | \n",
" NaN | \n",
" NaN | \n",
" 0.916667 | \n",
" 0.0 | \n",
"
\n",
" \n",
" | 2 | \n",
" 1 | \n",
" 2012 | \n",
" C | \n",
" 1.500000 | \n",
" 641.875000 | \n",
" NaN | \n",
" NaN | \n",
" 0.625000 | \n",
" 0.0 | \n",
"
\n",
" \n",
" | 3 | \n",
" 1 | \n",
" 2012 | \n",
" D | \n",
" 1.400000 | \n",
" 559.800000 | \n",
" NaN | \n",
" NaN | \n",
" 0.600000 | \n",
" 0.0 | \n",
"
\n",
" \n",
" | 4 | \n",
" 1 | \n",
" 2014 | \n",
" A | \n",
" 1.333333 | \n",
" 296.250000 | \n",
" 0.529246 | \n",
" 0.63618 | \n",
" 0.666667 | \n",
" 0.0 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" ward year anc num_candidates votes vote_norm engagement \\\n",
"0 1 2012 A 1.583333 481.500000 NaN NaN \n",
"1 1 2012 B 1.250000 544.333333 NaN NaN \n",
"2 1 2012 C 1.500000 641.875000 NaN NaN \n",
"3 1 2012 D 1.400000 559.800000 NaN NaN \n",
"4 1 2014 A 1.333333 296.250000 0.529246 0.63618 \n",
"\n",
" prop_uncontested prop_empty \n",
"0 0.500000 0.0 \n",
"1 0.916667 0.0 \n",
"2 0.625000 0.0 \n",
"3 0.600000 0.0 \n",
"4 0.666667 0.0 "
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"election_df = pd.read_csv(\"election_data_for_anc_map.csv\")\n",
"election_df.head()"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"(160, 8)\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" year | \n",
" num_candidates | \n",
" votes | \n",
" vote_norm | \n",
" engagement | \n",
" prop_uncontested | \n",
" prop_empty | \n",
" ANC_ID | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 2012 | \n",
" 1.583333 | \n",
" 481.500000 | \n",
" NaN | \n",
" NaN | \n",
" 0.500000 | \n",
" 0.0 | \n",
" 1A | \n",
"
\n",
" \n",
" | 1 | \n",
" 2012 | \n",
" 1.250000 | \n",
" 544.333333 | \n",
" NaN | \n",
" NaN | \n",
" 0.916667 | \n",
" 0.0 | \n",
" 1B | \n",
"
\n",
" \n",
" | 2 | \n",
" 2012 | \n",
" 1.500000 | \n",
" 641.875000 | \n",
" NaN | \n",
" NaN | \n",
" 0.625000 | \n",
" 0.0 | \n",
" 1C | \n",
"
\n",
" \n",
" | 3 | \n",
" 2012 | \n",
" 1.400000 | \n",
" 559.800000 | \n",
" NaN | \n",
" NaN | \n",
" 0.600000 | \n",
" 0.0 | \n",
" 1D | \n",
"
\n",
" \n",
" | 4 | \n",
" 2014 | \n",
" 1.333333 | \n",
" 296.250000 | \n",
" 0.529246 | \n",
" 0.63618 | \n",
" 0.666667 | \n",
" 0.0 | \n",
" 1A | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" year num_candidates votes vote_norm engagement prop_uncontested \\\n",
"0 2012 1.583333 481.500000 NaN NaN 0.500000 \n",
"1 2012 1.250000 544.333333 NaN NaN 0.916667 \n",
"2 2012 1.500000 641.875000 NaN NaN 0.625000 \n",
"3 2012 1.400000 559.800000 NaN NaN 0.600000 \n",
"4 2014 1.333333 296.250000 0.529246 0.63618 0.666667 \n",
"\n",
" prop_empty ANC_ID \n",
"0 0.0 1A \n",
"1 0.0 1B \n",
"2 0.0 1C \n",
"3 0.0 1D \n",
"4 0.0 1A "
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"election_df[\"ANC_ID\"] = election_df[\"ward\"].map(str) + election_df[\"anc\"]\n",
"election_df.drop(columns = [\"ward\", \"anc\"], inplace=True)\n",
"print(election_df.shape)\n",
"election_df.head()"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"(40, 8)\n"
]
}
],
"source": [
"election_df_2018 = election_df[election_df.year == 2018]\n",
"print(election_df_2018.shape)"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" OBJECTID | \n",
" ANC_ID | \n",
" WEB_URL | \n",
" NAME | \n",
" Shape_Leng | \n",
" Shape_Area | \n",
" geometry | \n",
" year | \n",
" num_candidates | \n",
" votes | \n",
" vote_norm | \n",
" engagement | \n",
" prop_uncontested | \n",
" prop_empty | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 1 | \n",
" 1C | \n",
" http://anc.dc.gov/page/advisory-neighborhood-c... | \n",
" ANC 1C | \n",
" 5218.954361 | \n",
" 1.285112e+06 | \n",
" POLYGON EMPTY | \n",
" 2018 | \n",
" 1.375000 | \n",
" 690.500000 | \n",
" 0.695144 | \n",
" 0.818804 | \n",
" 0.625000 | \n",
" 0.0 | \n",
"
\n",
" \n",
" | 1 | \n",
" 2 | \n",
" 1D | \n",
" http://anc.dc.gov/page/advisory-neighborhood-c... | \n",
" ANC 1D | \n",
" 4224.010068 | \n",
" 9.475922e+05 | \n",
" POLYGON EMPTY | \n",
" 2018 | \n",
" 1.600000 | \n",
" 513.200000 | \n",
" 0.608100 | \n",
" 0.818987 | \n",
" 0.400000 | \n",
" 0.0 | \n",
"
\n",
" \n",
" | 2 | \n",
" 3 | \n",
" 2A | \n",
" http://anc.dc.gov/page/advisory-neighborhood-c... | \n",
" ANC 2A | \n",
" 12477.943204 | \n",
" 7.065358e+06 | \n",
" POLYGON EMPTY | \n",
" 2018 | \n",
" 1.125000 | \n",
" 254.375000 | \n",
" 0.688037 | \n",
" 0.770138 | \n",
" 0.875000 | \n",
" 0.0 | \n",
"
\n",
" \n",
" | 3 | \n",
" 4 | \n",
" 2B | \n",
" http://anc.dc.gov/page/advisory-neighborhood-c... | \n",
" ANC 2B | \n",
" 7712.504785 | \n",
" 2.160620e+06 | \n",
" POLYGON EMPTY | \n",
" 2018 | \n",
" 1.222222 | \n",
" 574.666667 | \n",
" 0.698349 | \n",
" 0.840883 | \n",
" 0.777778 | \n",
" 0.0 | \n",
"
\n",
" \n",
" | 4 | \n",
" 5 | \n",
" 2C | \n",
" http://anc.dc.gov/page/advisory-neighborhood-c... | \n",
" ANC 2C | \n",
" 7811.084627 | \n",
" 2.861750e+06 | \n",
" POLYGON EMPTY | \n",
" 2018 | \n",
" 1.333333 | \n",
" 417.000000 | \n",
" 0.686430 | \n",
" 0.806862 | \n",
" 0.666667 | \n",
" 0.0 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" OBJECTID ANC_ID WEB_URL NAME \\\n",
"0 1 1C http://anc.dc.gov/page/advisory-neighborhood-c... ANC 1C \n",
"1 2 1D http://anc.dc.gov/page/advisory-neighborhood-c... ANC 1D \n",
"2 3 2A http://anc.dc.gov/page/advisory-neighborhood-c... ANC 2A \n",
"3 4 2B http://anc.dc.gov/page/advisory-neighborhood-c... ANC 2B \n",
"4 5 2C http://anc.dc.gov/page/advisory-neighborhood-c... ANC 2C \n",
"\n",
" Shape_Leng Shape_Area geometry year num_candidates \\\n",
"0 5218.954361 1.285112e+06 POLYGON EMPTY 2018 1.375000 \n",
"1 4224.010068 9.475922e+05 POLYGON EMPTY 2018 1.600000 \n",
"2 12477.943204 7.065358e+06 POLYGON EMPTY 2018 1.125000 \n",
"3 7712.504785 2.160620e+06 POLYGON EMPTY 2018 1.222222 \n",
"4 7811.084627 2.861750e+06 POLYGON EMPTY 2018 1.333333 \n",
"\n",
" votes vote_norm engagement prop_uncontested prop_empty \n",
"0 690.500000 0.695144 0.818804 0.625000 0.0 \n",
"1 513.200000 0.608100 0.818987 0.400000 0.0 \n",
"2 254.375000 0.688037 0.770138 0.875000 0.0 \n",
"3 574.666667 0.698349 0.840883 0.777778 0.0 \n",
"4 417.000000 0.686430 0.806862 0.666667 0.0 "
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"joined_df = anc_df.merge(election_df_2018, how=\"left\", on=\"ANC_ID\")\n",
"joined_df.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Update geojson features from dataframe values"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"' No longer necessary\\nfor anc in gjdata[\\'features\\']:\\n anc_id = anc[\\'properties\\'][\\'ANC_ID\\']\\n features = election_df.columns.tolist()\\n features.remove(\"ANC_ID\")\\n for feature in features:\\n anc[\\'properties\\'][feature] = joined_df.loc[joined_df[\\'ANC_ID\\'] == anc_id, feature].item()\\n'"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"\"\"\" No longer necessary\n",
"for anc in gjdata['features']:\n",
" anc_id = anc['properties']['ANC_ID']\n",
" features = election_df.columns.tolist()\n",
" features.remove(\"ANC_ID\")\n",
" for feature in features:\n",
" anc['properties'][feature] = joined_df.loc[joined_df['ANC_ID'] == anc_id, feature].item()\n",
"\"\"\""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Construct map"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
"anc_map = Map(location = (38.8899, -77.0091),\n",
" zoom_start = 12,\n",
" tiles = 'Stamen Toner')"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
""
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"folium.Choropleth(\n",
" geo_data=gj_path,\n",
" data=joined_df,\n",
" columns=[\"ANC_ID\", \"votes\"],\n",
" key_on='feature.properties.ANC_ID',\n",
" fill_color='GnBu',\n",
" fill_opacity=0.5,\n",
" line_weight=1, \n",
" highlight=True,\n",
" overlay=True,\n",
" name=\"average votes\",\n",
" legend_name=\"average # votes for winning candidates\",\n",
").add_to(anc_map)"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
""
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"folium.Choropleth(\n",
" geo_data=gj_path,\n",
" data=joined_df,\n",
" columns=[\"ANC_ID\", \"engagement\"],\n",
" key_on='feature.properties.ANC_ID',\n",
" fill_color='PuRd',\n",
" fill_opacity=0.5,\n",
" line_weight=1, \n",
" highlight=True,\n",
" overlay=True,\n",
" name=\"engagement\",\n",
" legend_name=\"percentage of ballots where ANC candidate was marked\",\n",
").add_to(anc_map)"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
""
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"LayerControl().add_to(anc_map)"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
" \n",
" "
],
"text/plain": [
""
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"embed_map(anc_map)"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [],
"source": [
"anc_map.save(\"anc_map.html\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.3"
}
},
"nbformat": 4,
"nbformat_minor": 2
}