mapping_movements/Mapping Movements.ipynb

961 lines
854 KiB
Text
Raw Normal View History

{
"cells": [
{
"cell_type": "markdown",
"id": "039c499c",
"metadata": {},
"source": [
"# Mapping Movements: Proximity\n",
"\n",
"This notebook is part of the pressure cooker for _Mapping movements: exploring the structure, vision and transformative potential of collections of movements for justice and sustainability_ of the Utrecht University Copernicus Institute, and Creative Coding Utrecht.\n",
"\n",
"This notebook documents an exploration to rethink \"distance\" for maps of social movements, or initiatives. In the maps researched by the project, distance is often presented as geographical distance, and rendered by the placement of entries on a skewed world map (often using Mercator projection, which preserves angle, not distance). The experiment here however is interested in finding new links between entries by deploying an of-the-shelf text embedding model known as _doc2vec_. Possibly revealing new categorisations and clusters.\n",
"\n",
"Many thanks to the exploration of Doc2Vec done by [Marton Trencseni](https://bytepawn.com/similar-posts-recommendation-with-doc2vec.html), on which many of these aproaches are based."
]
},
2023-12-30 15:00:03 +00:00
{
"cell_type": "markdown",
"id": "af8da066",
"metadata": {},
"source": [
"Contents: \n",
"\n",
"- [Embedding the text](#embedding)\n",
"- [Similar initiatives](#similar)\n",
"- [Find Clusters](#clusters)\n",
"- [Alternative Maps: Rendering Embedding Space](#rendering)\n",
"- [A situated map](#map)\n"
]
},
{
"cell_type": "markdown",
"id": "aaac4f97",
"metadata": {},
"source": [
2023-12-30 15:03:07 +00:00
"## 1. Embedding the text <a id=\"embedding\"></a>\n",
"\n",
"In this first step, the descriptions of the initiatives are embedded using Doc2Vec. That is to say, in a series of steps the text of the descriptions is transformed into a vector, a point in a (latent) multidimensional space: an embedding."
]
},
{
"cell_type": "code",
"execution_count": 70,
"id": "45d0504f-8bd2-46e0-83d1-2a3b0753ed98",
"metadata": {},
"outputs": [],
"source": [
"# some requirements to load for this project\n",
"\n",
"import csv\n",
"from gensim.models.doc2vec import Doc2Vec, TaggedDocument\n",
"import nltk\n",
"from nltk.tokenize import word_tokenize\n",
"import numpy as np\n",
"\n",
"import pandas as pd\n",
"import networkx as nx\n",
"import matplotlib.pyplot as plt\n",
"\n",
"from scipy.cluster.vq import kmeans,vq\n",
"from collections import defaultdict\n",
"\n",
"from sklearn.decomposition import PCA\n",
"from sklearn.manifold import TSNE"
]
},
{
"cell_type": "markdown",
"id": "50b9a342-d32b-4595-97df-b63b427397d1",
"metadata": {},
"source": [
"Then read the entries from CSV, this is an export of the spreadsheet prepred by other participants to the pressure cooker."
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "bf608f39-7984-4154-b2c0-bd2dc614cbab",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Fields: ['Title', 'Organisation', 'Location', 'Location - geographic', '', 'Category', 'Year', 'Website', 'Text', 'Population size']\n",
"41 initiatives\n"
]
}
],
"source": [
"with open('initiatives.csv') as fp:\n",
" initiatives = csv.DictReader(fp)\n",
" print(\"Fields:\", initiatives.fieldnames)\n",
" initiatives = [i for i in initiatives]\n",
"print(f\"{len(initiatives)} initiatives\")"
]
},
{
"cell_type": "markdown",
"id": "3509fe59-bda2-4d3b-96dc-2b9a98b108f7",
"metadata": {},
"source": [
"Then nltk's (a toolkit for natural language processing) \"punkt\" is used to parse inititatives into tokenized dict. Tokenization basically cuts the text into separate words and characters, a preparatory step before embedding."
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "31e2fe51-b6f2-4d93-81af-413f7ba8cc7c",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"[nltk_data] Downloading package punkt to /home/ruben/nltk_data...\n",
"[nltk_data] Package punkt is already up-to-date!\n"
]
},
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Punkt is required:\n",
"nltk.download('punkt')"
]
},
{
"cell_type": "markdown",
"id": "0628801e",
"metadata": {},
"source": [
"Make `tagged_initiatives` a dict indexed by the document's ID (row in the csv), which contains a \"TaggedDocument\" of the initiatives' descriptions"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "9a6dd962-c17d-4cbb-9b11-d3e8ff2e8103",
"metadata": {},
"outputs": [],
"source": [
"tagged_initiatives = {idx : TaggedDocument(word_tokenize(f\"{initiative['Title']} {initiative['Text']}\"), [idx]) for idx, initiative in enumerate(initiatives)}"
]
},
{
"cell_type": "markdown",
"id": "20573321-cea2-4004-b5c2-8337f5b04532",
"metadata": {},
"source": [
"This is then used to create the _doc2vec_ model, using a vector_size of 20 dimensions (we only have a small set of text, thus a small dimensionality should still give plenty of variety)"
]
},
{
"cell_type": "code",
"execution_count": 17,
"id": "8e86ebe5-3290-447c-836f-565f8ed53654",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Created a Doc2Vec model with 41 entries, and a total of 17278 words.\n"
]
}
],
"source": [
"model = Doc2Vec(tagged_initiatives.values(), vector_size=20, alpha=0.025, min_count=1, workers=16, epochs=100)\n",
"\n",
"print(f\"Created a Doc2Vec model with {model.corpus_count} entries, and a total of {model.corpus_total_words} words.\")"
]
},
{
"cell_type": "markdown",
"id": "2e6b9b9d",
"metadata": {},
"source": [
2023-12-30 15:03:07 +00:00
"## 2. Similar initiatives <a id=\"similar\"></a>\n",
"\n",
"Now that we have a Doc2Vec model, we can use it to calculate some sort of similarity score between the initiative in our little dataset which is based on a mathematical similarity of words ocuring in their descriptions. "
]
},
{
"cell_type": "code",
"execution_count": 22,
"id": "6e5531dd-b238-4f99-857d-75117556b59c",
"metadata": {},
"outputs": [],
"source": [
"def similar_initiatives(which: int, n: int = 3) -> [tuple[int, str, float]]:\n",
" \"\"\"Based on the given index, return the `n` most similar inititives.\n",
" Returns a list of tuples: (idx, title, similarity)\n",
" \"\"\"\n",
" if n == 'all':\n",
" return model.dv.most_similar(positive=[model.infer_vector(tagged_initiatives[which][0])], topn=None)\n",
" results = model.dv.most_similar(positive=[model.infer_vector(tagged_initiatives[which][0])], topn=n+1)\n",
" results = [(idx, initiatives[idx]['Title'], score) for idx, score in results if idx != tagged_initiatives[which][1][0]]\n",
" return results[:n]"
]
},
{
"cell_type": "markdown",
"id": "48c7cd7d",
"metadata": {},
"source": [
"For example, we can now find similar initiatives to the first entry of our spreadsheet:"
]
},
{
"cell_type": "code",
"execution_count": 26,
"id": "eef6cd37-d421-4c98-a638-f409d6c3403c",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Initiatives similar to 'Keep water in public hands!'.\n",
"- 'Observatorio del Agua de Terrassa ensures a democratic governance of water' (#24), has a similarity score of 0.62932288646698\n",
"- 'Our Water Our Right campaign mobilization against water privatisation' (#16), has a similarity score of 0.5763330459594727\n",
"- 'Citizen participation and solidarity tariffs in remunicipalized water utility' (#35), has a similarity score of 0.5491517186164856\n",
"- 'Million Wells Bengaluru' (#11), has a similarity score of 0.5210488438606262\n",
"- 'Agua Para Todos tackles water privatization and the impact of climate change' (#12), has a similarity score of 0.48210036754608154\n"
]
}
],
"source": [
"idx = 0\n",
"print(f\"Initiatives similar to '{initiatives[idx]['Title']}'.\")\n",
"for idx, title, score in similar_initiatives(idx, 5):\n",
" print(f\"- '{title}' (#{idx}), has a similarity score of {score}\")"
]
},
{
"cell_type": "markdown",
"id": "7c42f659",
"metadata": {},
"source": [
"These seem to make sense, as they're all about water. But it will be hard to digest for all 41 initiatives. "
]
},
{
"cell_type": "markdown",
"id": "2f7d6725-a245-45fe-8f14-2d8ff7ef3cda",
"metadata": {},
"source": [
"### Similarity matrix\n",
"\n",
"A similarity matrix visualises all similarities in a 2D matrix. I.e. a dark red means a score of 1, that is, completely similar. A white square means total dissimilarity.\n",
"\n",
"As the matrix plots entries against itself, the diagonal is 1."
]
},
{
"cell_type": "code",
"execution_count": 27,
"id": "989e5e0e-8230-4881-bf4a-25fc7f6e3de4",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 640x480 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import matplotlib.pyplot as plt\n",
"\n",
"def plot_matrix(m):\n",
" plt.imshow(m, cmap='YlOrRd', interpolation='nearest')\n",
" plt.colorbar()\n",
" plt.show()\n",
" \n",
"similarity_matrix = [similar_initiatives(idx, n='all') for idx in tagged_initiatives]\n",
"plot_matrix(similarity_matrix)"
]
},
{
"cell_type": "markdown",
"id": "b6f1d9b7",
"metadata": {},
"source": [
"While this plot renders all data, it is a bit hard to process. So, how can we understand these similarities, and how can we use it to find new aliances?"
]
},
{
"cell_type": "markdown",
"id": "562d4340-e4b0-4366-a917-ba91056c8ced",
"metadata": {},
"source": [
2023-12-30 15:03:07 +00:00
"## 3. Find clusters <a id=\"clusters\"></a>"
]
},
{
"cell_type": "markdown",
"id": "6f68a1c0",
"metadata": {},
"source": [
"### k-means\n",
"\n",
"A common aproach to clustering entries is the kmeans algorithm. This algorithm starts by picking `k` random points, and iteratively moving these as to find `k` number of distinct clusters."
]
},
{
"cell_type": "code",
"execution_count": 34,
"id": "65e0b155-08c6-4f73-a031-d300a0e9ce6f",
"metadata": {},
"outputs": [],
"source": [
"number_of_clusters = 7"
]
},
{
"cell_type": "code",
"execution_count": 35,
"id": "9f109275-7aae-40b2-8c91-c469e26b07dd",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Cluster: 0\n",
"- Keep water in public hands!\n",
"- Million Wells Bengaluru\n",
"- Agua Para Todos tackles water privatization and the impact of climate change\n",
"- Our Water Our Right campaign mobilization against water privatisation\n",
"- Community-led response to water pollution crisis\n",
"- Observatorio del Agua de Terrassa ensures a democratic governance of water\n",
"- Eau de Paris delivers cheaper, cleaner water\n",
"- Barcelona en Comú\n",
"- Citizen's Initiative Referendum against forced demolitions of social housing\n",
"- Citizen participation and solidarity tariffs in remunicipalized water utility\n",
"- Refusing to Give Up: Civil Societys Movement against Water Privatization in Jakarta\n",
"\n",
"Cluster: 1\n",
"- Entrepatios Madrid\n",
"- Social, cultural, and economic empowerment in Bukit Duri Urban Kampung reconstruction\n",
"- Relocation of road construction project affected slum dwellers\n",
"- Integrated social reconstruction homes in Isthmus of Tehuantepec\n",
"\n",
"Cluster: 2\n",
"- Women Workers Association builds tens of thousands of homes\n",
"- Dispossessed community finances and builds affordable homes\n",
"\n",
"Cluster: 3\n",
"- 100% renewable energy for Gaza\n",
"- PENGON empowers Palestinian women as sustainable energy leaders\n",
"\n",
"Cluster: 4\n",
"- Valencia walks towards the future: the cycling revolution in Valencia\n",
"- Rainwater harvesting in Mexico Citys marginalized neighborhoods\n",
"- No Bicycle, No Planet\n",
"- Women for Food Sovereignty in Cochabamba\n",
"- The municipality of Burgas pioneers energy efficient housing in Bulgaria\n",
"- Barcelona Energia\n",
"- Energy transition built on democracy, renewables and jobs\n",
"- Cargonomia Community Cargobike and Local Food Distribution Center\n",
"\n",
"Cluster: 5\n",
"- Building the movement for agroecological urban gardening to ensure food sovereignty\n",
"- Linking urban consumers to rural producers\n",
"- CaSanAT is a micro-utopia serving as a space for exchange, learning and resistance\n",
"- Waste management innovation for food security and climate change mitigation\n",
"- Maison dÉducation à lAlimentation Durable supplies the community with organic food and educates future generations\n",
"- Bronx Cooperative Development Initiative\n",
"- Transforming a century-old, oil company town\n",
"- Power Shift supports farmers with clean energy\n",
"\n",
"Cluster: 6\n",
"- Penca de Sábila Corporation improves the lives of rural farmers and connects them with urban communities\n",
"- EnergÉtica Cooperative challenges energy poverty by supplying clean energy\n",
"- The Cloughjordan Ecovillage models the transition to a low-carbon society\n",
"- The Jackson Just Transition Plan is transforming Jackson into a city of equity, solidarity and mutual aid\n",
"- Earthworker Cooperative\n",
"- People power drives social and ecological transition\n"
]
}
],
"source": [
"vectors = [model.dv[i] for i in range(41)]\n",
"centroids, _ = kmeans(vectors, number_of_clusters)\n",
"\n",
"# computes cluster Id for document vectors\n",
"doc_ids,_ = vq(vectors,centroids)\n",
"\n",
"clusters = defaultdict(list)\n",
"for initiative, cluster_id in zip(initiatives, doc_ids):\n",
" clusters[cluster_id].append(initiative)\n",
"\n",
"cluster_ids = sorted(list(clusters.keys()))\n",
"\n",
"for cluster_id in cluster_ids:\n",
" print('\\nCluster:', cluster_id)\n",
" for i in clusters[cluster_id]:\n",
" print(f\"- {i['Title']}\")"
]
},
{
"cell_type": "markdown",
"id": "f2014a13",
"metadata": {},
"source": [
"While this is certainly a good first stab at clustering (i.e. the first cluster contains some water projects but also other entries and cluster 3 has projects on Palestinia & Gaza), it's major disadvantage is that one needs to specify a specific `k` number of clusters. Thus, it doesn't start from the data."
]
},
{
"cell_type": "markdown",
"id": "6558ed13-6d43-4229-845e-ac515fafb1d8",
"metadata": {},
"source": [
"### Truncated similiarity "
]
},
{
"cell_type": "markdown",
"id": "c48d8d18",
"metadata": {},
"source": [
"Another way to find aliances would be not to directly use the embeddings to calculate clusters, but to start from the calculated similarities.\n",
"\n",
"A first step in that could be to treshhold the similarity matrix and link up those that are above the given threshold. This limits the number of matches between entries. A disadvantage of this approach becomes apparent in the network graph: the clusters that emerge are very uneven. In our case most items are in a single cluster, while some entries have _no_ matches. Increasing the threshold creates even more singular items, decreasing it merges everything into one web, which pretty much beats the purpose."
]
},
{
"cell_type": "code",
"execution_count": 48,
"id": "19348a01",
"metadata": {},
"outputs": [],
"source": [
"threshold = .55"
]
},
{
"cell_type": "code",
"execution_count": 49,
"id": "443ae02f-60d6-4716-b8d6-5f9253660b1e",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 640x480 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"similarity_matrix_truncated = [[y if y > threshold else 0 for y in x] for x in similarity_matrix]\n",
"for i in range(len(similarity_matrix_truncated)):\n",
" similarity_matrix_truncated[i][i] = 0\n",
"plot_matrix(similarity_matrix_truncated)"
]
},
{
"cell_type": "code",
"execution_count": 50,
"id": "6a175908-e8c1-4b3b-b10d-cc1889a1e69d",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1500x1500 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"def plot_graph(m):\n",
" labels = list(range(len(m)))\n",
" df = pd.DataFrame(m, index=labels, columns=labels)\n",
" G = nx.from_pandas_adjacency(df)\n",
" plt.figure(figsize=(15, 15))\n",
" nx.draw_networkx(G, nx.spring_layout(G), node_size=0, arrows=False, edge_color='lightgray', font_size=8)\n",
" plt.show()\n",
"\n",
"plot_graph(similarity_matrix_truncated)"
]
},
{
"cell_type": "markdown",
"id": "8d7a0663",
"metadata": {},
"source": [
"### Similarity top-n\n",
"\n",
"Another approach, suggested by Trensceni in his blog-post, is to no simply truncate the similarity matrix, but to build a web by finding the `n` most similar entries for each initiative and using these as links. Then the linked-up entries act as clusters.\n"
]
},
{
"cell_type": "code",
"execution_count": 51,
"id": "3fbeb2e7",
"metadata": {},
"outputs": [],
"source": [
"# another approach, to avoid singletons:\n",
"# for each initiative, get the top n=3 most similar\n",
"def similarity_matrix_top_n(n=3):\n",
" m = np.zeros((len(initiatives), len(initiatives)))\n",
" for idx, initiative in enumerate(initiatives):\n",
" sp = similar_initiatives(idx, n)\n",
" idxs = [p[0] for p in sp]\n",
" # idxs = [tagged_initiatives[p[0]][1][0] for p in sp]\n",
" for k, j in enumerate(idxs):\n",
" m[idx][j] = 1 #sp[k][2]\n",
" return m"
]
},
{
"cell_type": "markdown",
"id": "59e23d03",
"metadata": {},
"source": [
"\n",
"The question then is, which `n` should be used. In our case, when starting with $n=3$ all initiatives still merge into one giant cluster, the same happens with $n=2$. With $n=1$ however, clusters emerge. Some only of 2 items (each having the other as most similar entry). Yet some linking more items together."
]
},
{
"cell_type": "code",
"execution_count": 52,
"id": "ad7deef9-0b81-4b44-ab10-044756782982",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 640x480 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1500x1500 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 640x480 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1500x1500 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 640x480 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1500x1500 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"similarity_matrix_truncated = similarity_matrix_top_n(n=3)\n",
"plot_matrix(similarity_matrix_truncated)\n",
"plot_graph(similarity_matrix_truncated)\n",
"\n",
"\n",
"similarity_matrix_truncated = similarity_matrix_top_n(n=2)\n",
"plot_matrix(similarity_matrix_truncated)\n",
"plot_graph(similarity_matrix_truncated)\n",
"\n",
"\n",
"similarity_matrix_truncated = similarity_matrix_top_n(n=1)\n",
"plot_matrix(similarity_matrix_truncated)\n",
"plot_graph(similarity_matrix_truncated)"
]
},
{
"cell_type": "markdown",
"id": "8152479b",
"metadata": {},
"source": [
"Instead of a linked plot, this can be rendered as a list of clusters:"
]
},
{
"cell_type": "code",
"execution_count": 63,
"id": "235496c5",
"metadata": {},
"outputs": [],
"source": [
"def matrix2clusters(m):\n",
" connected_subgraphs = set([frozenset([i]) for i in list(range(len(m)))])\n",
" def update_subgraphs(i, j):\n",
" join_targets = [g for g in connected_subgraphs if i in g or j in g]\n",
" new_subgraph = frozenset({i for g in join_targets for i in g})\n",
" for g in join_targets:\n",
" connected_subgraphs.remove(g)\n",
" connected_subgraphs.add(new_subgraph)\n",
" for i in range(len(m)):\n",
" for j in range(len(m)):\n",
" if m[i][j] > 0:\n",
" update_subgraphs(i, j)\n",
" return connected_subgraphs\n",
"\n",
"def print_clusters(connected_subgraphs):\n",
" for g in connected_subgraphs:\n",
" if len(g) == 1:\n",
" for i in g:\n",
" print(f'Singleton: {idx_lookup[i]}')\n",
" for idx, g in enumerate(connected_subgraphs):\n",
" if len(g) > 1:\n",
" print(f'\\nCluster {idx}:')\n",
" for i in g:\n",
" print(f\"- {initiatives[i]['Title']} (#{i})\")"
]
},
{
"cell_type": "code",
"execution_count": 64,
"id": "cd12ab56-df85-41e4-b7d0-4ccfb0916b4b",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Cluster 0:\n",
"- PENGON empowers Palestinian women as sustainable energy leaders (#29)\n",
"- 100% renewable energy for Gaza (#6)\n",
"\n",
"Cluster 1:\n",
"- Linking urban consumers to rural producers (#9)\n",
"- Building the movement for agroecological urban gardening to ensure food sovereignty (#2)\n",
"- Waste management innovation for food security and climate change mitigation (#19)\n",
"\n",
"Cluster 2:\n",
"- Our Water Our Right campaign mobilization against water privatisation (#16)\n",
"- Citizen's Initiative Referendum against forced demolitions of social housing (#34)\n",
"- Million Wells Bengaluru (#11)\n",
"\n",
"Cluster 3:\n",
"- The municipality of Burgas pioneers energy efficient housing in Bulgaria (#13)\n",
"- Energy transition built on democracy, renewables and jobs (#21)\n",
"\n",
"Cluster 4:\n",
"- Women for Food Sovereignty in Cochabamba (#8)\n",
"- Valencia walks towards the future: the cycling revolution in Valencia (#1)\n",
"- Cargonomia Community Cargobike and Local Food Distribution Center (#31)\n",
"\n",
"Cluster 5:\n",
"- Maison dÉducation à lAlimentation Durable supplies the community with organic food and educates future generations (#23)\n",
"- Penca de Sábila Corporation improves the lives of rural farmers and connects them with urban communities (#15)\n",
"\n",
"Cluster 6:\n",
"- The Jackson Just Transition Plan is transforming Jackson into a city of equity, solidarity and mutual aid (#27)\n",
"- People power drives social and ecological transition (#39)\n",
"\n",
"Cluster 7:\n",
"- Rainwater harvesting in Mexico Citys marginalized neighborhoods (#3)\n",
"- No Bicycle, No Planet (#7)\n",
"\n",
"Cluster 8:\n",
"- Barcelona en Comú (#32)\n",
"- Barcelona Energia (#17)\n",
"\n",
"Cluster 9:\n",
"- Power Shift supports farmers with clean energy (#40)\n",
"- Bronx Cooperative Development Initiative (#30)\n",
"\n",
"Cluster 10:\n",
"- Keep water in public hands! (#0)\n",
"- Citizen participation and solidarity tariffs in remunicipalized water utility (#35)\n",
"- Refusing to Give Up: Civil Societys Movement against Water Privatization in Jakarta (#37)\n",
"- Transforming a century-old, oil company town (#38)\n",
"- Agua Para Todos tackles water privatization and the impact of climate change (#12)\n",
"- Community-led response to water pollution crisis (#20)\n",
"- Observatorio del Agua de Terrassa ensures a democratic governance of water (#24)\n",
"- Eau de Paris delivers cheaper, cleaner water (#28)\n",
"\n",
"Cluster 11:\n",
"- EnergÉtica Cooperative challenges energy poverty by supplying clean energy (#25)\n",
"- The Cloughjordan Ecovillage models the transition to a low-carbon society (#26)\n",
"- Earthworker Cooperative (#33)\n",
"\n",
"Cluster 12:\n",
"- Integrated social reconstruction homes in Isthmus of Tehuantepec (#18)\n",
"- Entrepatios Madrid (#4)\n",
"- Social, cultural, and economic empowerment in Bukit Duri Urban Kampung reconstruction (#5)\n",
"- Dispossessed community finances and builds affordable homes (#36)\n",
"- Women Workers Association builds tens of thousands of homes (#22)\n",
"- Relocation of road construction project affected slum dwellers (#10)\n",
"- CaSanAT is a micro-utopia serving as a space for exchange, learning and resistance (#14)\n"
]
}
],
"source": [
"similarity_clusters = matrix2clusters(similarity_matrix_truncated)\n",
"print_clusters(similarity_clusters)"
]
},
{
"cell_type": "markdown",
"id": "9940e93e",
"metadata": {},
"source": [
"What emerges is a variety of clusters -- which capture a heterogenity of characteristics. For example, cluster 8 contains two Barcelona related initiatives, whereas the last cluster, number 12, seems to capture housing/urban related project."
]
},
{
"cell_type": "code",
"execution_count": 66,
"id": "05e6d518-9de5-463b-a9a2-244aa7168228",
"metadata": {},
"outputs": [],
"source": [
"\"\"\"Prepare a list of colors for each initiative based on their cluster. This can be used in the next step.\"\"\"\n",
"colors = np.zeros(len(initiatives))\n",
"for cluster, entries in enumerate(similarity_clusters):\n",
" for entry in entries:\n",
" colors[entry-1] = cluster"
]
},
{
"cell_type": "markdown",
"id": "fa10d87a-4435-4e8c-bde1-96861d4401ad",
"metadata": {},
"source": [
2023-12-30 15:03:07 +00:00
"## 4. Rendering embedding space: alternative maps of movement <a id=\"rendering\"></a>"
]
},
{
"cell_type": "markdown",
"id": "065ed897-aa53-409f-b3ac-f2fc357c9a45",
"metadata": {},
"source": [
"It can be hard to make sense of the mathematical projections of the initiatives. The matrix rendering above is basically illegible, or at least hard to navigate. The network renderings are much more intuitive, but really only start from the calculated similarities. They are 'force' graphs, that discard any sense of the configuration of the embedding space. This becomes even more apparent when rendering it into a 2D. \n",
"\n",
"One way to do this is to reduce the 20 dimensions into only 2 using PCA. If we run a PCA on the 41 embedded initiatives and plot the first 2 dimensions, it is clear that the clusters that emerged in the previous step (as indicated with the color of the point) is really different from their placement in this kind of visualisation."
]
},
{
"cell_type": "code",
"execution_count": 79,
"id": "ecd004a4-3c05-4b5d-b4f8-5bf426d4d561",
"metadata": {},
"outputs": [],
"source": [
"pca = PCA(n_components=2)"
]
},
{
"cell_type": "code",
"execution_count": 80,
"id": "bf77c5ce-8cc3-4ba5-adb0-847a5d3052ee",
"metadata": {},
"outputs": [],
"source": [
"projected = pca.fit_transform(vectors)"
]
},
{
"cell_type": "code",
"execution_count": 123,
"id": "1a0fdb3f-24ba-4408-884b-d2ae5e41e41a",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1400x1400 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"f = plt.figure(figsize=(14, 14))\n",
"ax = plt.subplot(aspect='equal')\n",
"ax.scatter(projected[:,0],projected[:,1], c=colors)\n",
"\n",
"\n",
"for idx, ini in enumerate(initiatives):\n",
" x, y = projected[idx]\n",
" # add label to a point\n",
" ax.text(x, y, ini['Title'][:18]+'...', fontsize=8, alpha=.5)"
]
},
{
"cell_type": "markdown",
"id": "3efa87f4",
"metadata": {},
"source": [
"Another algorithm that can be used to transform the space is t-SNE, which unlike PCA is not deterministic. I.e. it tends to produce different output on each run. This algorithm is optimised to find render similar items close together and increase the distance between less similar items; thus providing _some_ similar clusters. Loooking at the output here however, it seems not very successful at that with the small dataset used here. Nevertheless, when looking at the image below, some clusters we saw earlier reappear. For example, the top of the image contains water related projects, and some Citizen participatory initiatives appear together in the center of the mapping."
]
},
{
"cell_type": "code",
"execution_count": 103,
"id": "f2b139e7-2781-4a03-acba-01e51f151276",
"metadata": {},
"outputs": [],
"source": [
"# Random state.\n",
"RS = 20150101\n",
"tsne_projected = TSNE(random_state=RS, perplexity=30).fit_transform(np.vstack(vectors))"
]
},
{
"cell_type": "code",
"execution_count": 120,
"id": "fcedc397",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAABJcAAARKCAYAAADyqZEZAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8g+/7EAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOz9eXiVdZ7ve7/XWhlIQsIUIIQEkoCCzIgDFiCCIg6IWpRDF0UVOCBdQ5+q0/vZx+c5+zrbs0/v3r13n96b6io0WlrSVWI5gyAyCIKKgBhlEgSFJCJDgEwkhIxrrecPmlVG5iWCyPt1XfaVdd+/+3d/10oXJB9+v+8diEajUSRJkiRJkqQ4BC90AZIkSZIkSbp4GS5JkiRJkiQpboZLkiRJkiRJipvhkiRJkiRJkuJmuCRJkiRJkqS4GS5JkiRJkiQpboZLkiRJkiRJipvhkiRJkiRJkuJmuCRJkiRJkqS4GS5JkiRJkiQpboZLkiRJkiRJipvhkiRJkiRJkuJmuCRJkiRJkqS4GS5JkiRJkiQpboZLkiRJkiRJipvhkiRJkiRJkuJmuCRJkiRJkqS4GS5JkiRJkiQpboZLkiRJkiRJipvhkiRJkiRJkuJmuCRJkiRJkqS4GS5JkiRJkiQpboZLkiRJkiRJipvhkiRJkiRJkuJmuCRJkiRJkqS4GS5JkiRJkiQpboZLkiRJkiRJipvhkiRJkiRJkuJmuCRJkiRJkqS4GS5JkiRJkiQpboZLkiRJkiRJipvhkiRJkiRJkuJmuCRJkiRJkqS4GS5JkiRJkiQpboZLkiRJkiRJipvhkiRJkiRJkuJmuCRJkiRJkqS4GS5JkiRJkiQpboZLkiRJkiRJipvhkiRJkiRJkuJmuCRJkiRJkqS4GS5JkiRJkiQpboZLkiRJkiRJipvhkiRJkiRJkuJmuCRJkiRJkqS4GS5JkiRJkiQpboZLkiRJkiRJipvhkiRJkiRJkuJmuCRJkiRJkqS4GS5JkiRJkiQpboZLkqTvjZkzZ1JWVgZAS0sLf/nLX3jppZcIh8MXuLLTW7lyJS0tLedkrhUrVrBp06ZzMpckSZJ0OoZLkqTvncbGRp577jnatm3LPffcQygUutAlnVa84VIkEjnu2JgxYxg0aNC5KEuSJEk6rYQLXYAkSefSkSNHmD9/PgUFBdx0002x4xs3bmTdunVEIhGSkpK49dZbycrKAmD16tVs2bKFSCRCWloaEyZMoH379qxcuZL9+/fT0NBAbW0tHTt25K677iI1NbXVPT/66CP27t3LHXfcwcGDB5k1axZTpkyhV69evPPOOwCMHj2apUuXUlpaSiQSITk5mTvuuIPMzEzeeOMNAP74xz8SDAaZMmUKCQkJLFmyhP3799PS0kJOTg633XYboVCI2bNn07VrV/bs2UNiYiI/+9nPWtUzb948srKyGD58OCtXruTgwYM0NzdTVVVF27Ztuffee0lJSTnus5s5cyb9+vWjpKSExsZGhg0bxogRI87p90eSJEnfP4ZLkqSL1p7yQ7z87kbe3VRMSyRCw45P2VVWwW03jW4VLO3atYtPPvmEadOmkZCQwBdffMGrr77KL37xCzZv3kx5eTkPPvggwWCQjRs3snDhQiZPnhy79m//9m9p27YtCxcuZPny5dxxxx2t6igoKGDVqlUA7Ny5k9zcXIqLi+nVqxc7d+5k3LhxAIwYMYKbb74ZgE8++YTFixfzk5/8hAkTJlBUVMQDDzxAmzZtAFiwYAE9e/Zk4sSJRKNRFixYwNq1a2NhT0VFBdOmTTujVVl79uxh+vTppKam8sorr1BUVMSoUaNOOLauro7p06dTX1/Pk08+SY8ePcjNzT2bb4skSZIuMYZLkqSL0uqtpfzmiflEIhHCkSgA5bsOsKOyif01i7n66qtp164dANu3b6esrIynn346dn19fT3Nzc1s27aNPXv28NRTTwHHbzO77LLLaNu2LQDDhg3jxRdfPK6WDh06AFBVVUVxcTE33ngjS5cupampiYMHD9K9e3cAiouL+eCDD2hqaiIajVJfX3/S97dt2za+/PJL1qxZA0BzczOBQCB2ftCgQWe83a93796x1VY5OTkcOHDgpGOHDh1KIBAgNTWVK664guLiYsMlSZIknZLhkiTpolNZc4T/ULiAlnCYaPSvxyPRKGld8yjaV8n//d//F//5//gN7dq1IxqNMmTIEG688cbj5opGo4waNYphw4Z9o5oKCgr4/PPPqaysJC8vj2g0ytatW8nNzSUYDHLo0CHefPNNHn74YTp27Mj+/ft59tlnTzpfNBrlvvvuo1OnTic8n5SUdMa1JST89a/7YDB4wj5N+m6ZOXMmoVCIxMTE2LG7776brl27fiv3W7duHXv37uWuu+46q+u+Wmc4HObqq6/mmmuuOas59u7dy/vvv88999xzVtd91VNPPcXNN99MXl5e3HNIkqT42dBbknTRmbf6ExpbWgdLX5WRnc/uphRmz55NdXU1ffr0YdOmTRw6dAg4Gtzs3bsXgL59+1JUVBRbRRQOh9m3b19srs8//5zDhw8D8PHHH1NQUHDCexYUFLB69erYKqX8/HxWrlwZG9/Q0EAwGCQ9PZ1oNMq6detaXZ+cnExDQ0Psdd++fVm1alUsCKqvr6eysvKsPqd4bNiwIXa/Tz/99KTvV9++e+65hxkzZsT++7aCpW/qWJ2TJ09m+fLl7N+//4yvjUQiZGdnf6NgSZIkXXiuXJIkXXQ++nw30ZMlS0A4EmVPcyrDh1/D7Nmz+dnPfsa4ceN44YUXjm6jC4e5/PLLyc7OZtCgQdTX1zN79mzg6C+7Q4cOpVu3bgD07NmTV199tVVD7xPJz8/n0KFDsTCmV69erF69mvz8fAC6du3KgAEDmDVrFqmpqfTt27fV9ddddx1//vOfSUxMZMqUKdxyyy0sW7aMwsJCAoEAwWCQcePG0bFjx2/46Z1aWloaTz75JI2NjVxzzTWxLXErVqwgPT2dq666CoDCwkImT55Meno627dvZ/v27UycOPFbrU1Hvfrqq1RUVBAOh8nIyODOO++kbdu2VFdXU1hYyKOPPgpAU1MT//iP/8hjjz123ByNjY3Mnz+fsrIy0tLS6Ny5c6vzJ2tyfyrt27cnMzOTiooKiouL2bx5M5FIhGAwyK233hr7/6WZM2fSv39/SktL6dixI8OGDWPx4sXMmDGDuro6XnvtNWprawkEAnTr1u2E/5v78ssvWbhwYSyc+upqvMOHD7No0SKqq6tpbm6mb9++jB079uw+ZEmSdFYMlyRJ3xtdBo1u9fraa6/l2muvBY72RRowYMAJr/vquK/LyMjg3nvvPe29U1NT+c//+T/HXvfq1eu4X+pvvfVWbr311tjr66+/Pvb1DTfcwA033NBq/G233XbCe02dOvWUtXz1l/Gvz3m6LUsDBw6MNSD/qjFjxrR6PWPGjNjXffr0oU+fPqecVycXDod569/e4fVZi/li65cktUki2ucI1QdqyOrRJTbuwQcfJDExkVtuuYW0tDQAVq1axcqVK5kwYcJZ3fOdd94hISGBX/7ylzQ2NvL000+Tk5MDcNom9yezf/9+ysvL6dq1Kz179uS6664DYPfu3cybN49f/vKXsbH19fU89NBDBAIBSktLY8c3bdpE+/btmTJlSmzciT6vl19+mbvuuouCggJ27twZW3EHMHfuXEaNGkVeXh6RSITnn3+eLVu20L9//7P6jCRJ0pkzXJIkXXSGXZbD2k93nXT1UigY4KrLbUJ9sWpsbORf/uVf6N+/P3feeed5vfe8efPYuXMnaWlptLS00LNnT2677bYzbp5+NlasWMGnWz9l4VPL2L7pM0KBBILRIDRAy4fN1K5v5n8s+L+56ubBra7bvHkzmzZtoqWlhSVLlpywl9jplJSUMH78eAKBAG3atGHgwIFUVVUBnLbJ/de9/PLLJCYmkpiYyJ133kmnTp3YuXMn7777LvX19QSDQcrLy2lubo71kBoyZEirBvXH5OTksHbtWpYsWULPnj3p3bv3cWPKy8sJBoOtVgkea6rf1NRESUkJdXV
"text/plain": [
"<Figure size 1400x1400 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"f = plt.figure(figsize=(14,14))\n",
"ax = plt.subplot(aspect='equal')\n",
"ax.scatter(tsne_projected[:,0], tsne_projected[:,1], c=colors)\n",
"ax.axis('off')\n",
"ax.axis('tight')\n",
"\n",
"for idx, ini in enumerate(initiatives):\n",
" x, y = tsne_projected[idx]\n",
" # add label to a point\n",
" ax.text(x, y, ini['Title'][:15]+'...', fontsize=8, alpha=.5)"
]
},
{
"cell_type": "markdown",
"id": "70b3afe8",
"metadata": {},
"source": [
2023-12-30 15:03:07 +00:00
"## 5. A situated map <a id=\"map\"></a>"
]
},
{
"cell_type": "markdown",
"id": "c56057b4",
"metadata": {},
"source": [
"What if we rethink a single rendition of similarity, and instead try to consider similarity for each project, and draw a 'map' of similar projects based on that. Such a map is open for possible coalitions for each initiative."
]
2023-12-30 15:20:15 +00:00
},
{
"cell_type": "code",
"execution_count": 135,
"id": "fbe09619",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'{\"initiatives\": [{\"Title\": \"Keep water in public hands!\", \"Organisation\": \"African Center for Advocacy (ACA)\", \"Location\": \"YAOUNDE, CAMEROON\", \"Location - geographic\": \"\", \"\": \"\", \"Category\": \"WATER \", \"Year\": \"2021\\\\u20132022\", \"Website\": \"http://www.we-advocate.org/\", \"Text\": \"WHAT\\\\u2019S UNIQUE ABOUT THE INITIATIVE?\\\\nTen years of water privatization have affected about 43% of the Cameroonian population, with women and children bearing the brunt. In 2019, African Center for Advocacy (ACA) launched the \\\\u00abKeep Water in Public Hands\\\\u00bb campaign with a coalition of civil society, media, unions and grassroots organisations to stop the corporate agenda of forcing the government to privatize water. This movement has contributed to stopping water privatization and to advancing the human right to water in Cameroon.\\\\nMOST OUTSTANDING RESULTS\\\\nThe conditions that prompted Cameroon to privatise the public water service in 2008 are once again multiplying on the ground. Between untimely water cuts, deterioration of installations and bad management practices, the public company (Camwater) which produces and distributes drinking water, is struggling to provide it in quantity and quality to an ever-growing population.\\\\n\\\\nBack then, privatization was supposed to deliver improved infrastructure and lower prices \\\\u2014 but neither materialized. Though the water was renationalized in 2018, numerous shortcomings continue to hamper the provision of clean water to the population.\\\\n\\\\nIn 2022, Camwater confessed its role in the drinking water crisis. According to the company, the episodic shortages observed in the capital are mainly linked to the numerous malfunctions of the Akomnyada water collection and treatment station, located 35 km east of the city. According to official figures, the demand for drinking water in Yaound\\\\u00e9 and Mbalmayo, two towns supplied by the Akomnyada catchment station, is currently around 300,000 m3 per day.\\\\n\\\\nFaced with the state\\\\u2019s \\\\u201cinability\\\\u201d to effectively provide public water service, the African Center for Advocacy (ACA) has increased lobbying, media advocacy as well as labour engagements to push for reduced taxes for any household that consumes less than 20 cubic meters of water per month. ACA has enjoined the national water distribution company to establish water pricing by categorizing the price per cubic meter of water by the type of customer. This greatly increased the number of low-income households connected to the water system. They are also monitoring privatization threats and pressing the government to invest on rehabilitation projects and taking responsibility.\\\\n\\\\nThe ACA will not give up its fight as long as the cloud of privatisation hangs over the water sector in Cameroon. Their goal is the recognition of the right to water in the Cameroonian constitution.\", \"Population size\": \"\"}, {\"Title\": \"Valencia walks towards the future: the cycling revolution in Valencia\", \"Organisation\": \"Sustainable Urban Mobility Plan (PMUS)\", \"Location\": \"VALENCIA, SPAIN\", \"Location - geographic\": \"\", \"\": \"\", \"Category\": \"ENERGY\", \"Year\": \"2021\\\\u20132022\", \"Website\": \"https://www.valencia.es/val/inici\", \"Text\": \"WHAT\\\\u2019S UNIQUE ABOUT THE INITIATIVE?\\\\nFor decades, Valencia was a city that revered motor vehicles and boasted about the quantity and fluidity of its traffic. However, in the summer of 2015, the municipal authorities took a step towards reversing this situation. The climate emergency scenario demanded it, but also the desire to improve the quality of life of its inhabitants, who, with the promotion of cycling and the new pedestrianisation, save energy and improve their economy.\\\\nMOST OUTSTANDING RESULTS\\\\nValencia is a city where public space once again belongs to citizens, rather than cars, and people are no longer pedestrians. The sustainable mobility promoted by Valencia City Council has brought about ambitious and fundame
]
},
"execution_count": 135,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"sim = np.clip(similarity_matrix, 0, 1)\n",
"\n",
"import json\n",
"\n",
"data = {\n",
" \"initiatives\": initiatives,\n",
" 'distances': sim.tolist()\n",
"}\n",
"\n",
"json.dumps(data)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"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.10.13"
}
},
"nbformat": 4,
"nbformat_minor": 5
}