<jupyter_start><jupyter_text>Stolen Bronzes: Western Museums and Repatriation Introduction>"*Walk into any European museum today and you will see the curated spoils of Empire. They sit behind plate glass: dignified, tastefully lit. Accompanying pieces of card offer a name, date and place of origin. They do not mention that the objects are all stolen*.">> 'Radicals in Conversation': The Brutish MuseumsPublic history and digital humanities offers a locus point of contending with difficult pasts. Museums, often considered bastions of knowledge, learning, and public good have fallen under an increasingly critical gaze -- and rightfully so. Public museums have been tools of colonialism, racism, and superiority centred around the supremacy of the west and its history. Digital repositories of museum archives and websites can be used to subvert the exclusionary practices employed by museums and provide tools for marginalized peoples --. The purpose of this notebook is to act as a digital tool for real life change, and it is focused on <NAME>'s [Tweet](https://twitter.com/profdanhicks/status/1375421209265983488) and book, *The Brutish Museum*.<jupyter_code>%%html
<iframe src="https://drive.google.com/file/d/1txSH3UkjJgLTeQW47MGLfrht7AHCEkGC/preview" width="640" height="480"></iframe><jupyter_output><empty_output><jupyter_text>What I read in Dan Hicks' Tweet was a call to action. Not necessarily for the average citizen to take the bronzes back, but to start an important discussion about the nature of artifact aqcuisition and confronting how museums procure these items in the first place.The appendix' list is a small fraction of the stolen artifacts found in hundreds of museums all over the world but it is a powerful point of focus. I want to create something, however small, that can give others the tools to have a visual representation of stolen artifacts distribution and interrogate why (mostly) western museums are the institutions holding these artifacts, what effect this has, and what's being done with them. Can anyone own art? Who has the power to decide? How do we give that power back to those who were stolen from?To learn more about the Benin bronzes and their history, a good place to start is with the ['Radicals in Conversation'](https://www.plutobooks.com/blog/podcast-brutish-museums-benin-bronzes-decolonisation/) podcast.And now, what I have here is a helpful tool for all of us to answer, **"*How close are you right this second to a looted Benin Bronze*?"** DataI have compiled a dataframe of all the museums listed in Hicks' appendix'; you can see the original above in his Tweet. The data is in a .CSV file stored in my [GitHub repository](https://github.com/kuriousk516/HIST4916a-Stolen_Bronzes), and you can also find screenshots of the errors I encountered and advice I recieved through the HIST4916a Discord server, some of which I will reference here when discussing data limitations.  Mapping with FoliumFolium seemed the best choice for this project since it doesn't rely on Google Maps for the map itself or the data entry process. [This is the tutorial](https://craftingdh.netlify.app/tutorials/folium/) that I used for the majority of the data coding, and this is the [Point Map alternative](https://handsondataviz.org/mymaps.html) I considered but decided against.<jupyter_code>import lxml
import pandas as pd
pd.set_option("max_rows", 400)
pd.set_option("max_colwidth", 400)
import pandas, os
os.listdir()
['.config', 'benin_bronze_locations2.csv', 'sample_data']<jupyter_output><empty_output><jupyter_text>Here is where I ran into some trouble. I was having great difficulty in loading my .CSV file into the notebook, so I uploaded the file from my computer. Here is the alternative code to upload it using the RAW link from GitHub: url = 'copied_raw_GH_link'df1 = pd.read_csv(url)If you have another (simpler) way of getting the job done, I fully encourage you altering the code to make it happen.<jupyter_code>from google.colab import files
uploaded = files.upload()<jupyter_output><empty_output><jupyter_text>In the .CSV file, I only had the name of the museums, cities, and countries. Manually inputting the necessary data for plotting the locations would be time-consuming and tedious, but I have an example using geopy and Nomatim to pull individual location info for the cases when "NaN" pops up when expanding the entire dataframe.<jupyter_code>df1=pandas.read_csv('benin_bronze_locations2.csv', encoding = "ISO-8859-1", engine ='python')
df1
!pip install geopy
from geopy.geocoders import Nominatim
geolocator = Nominatim(user_agent="BENIN-BRONZES", timeout=2)
location = geolocator.geocode("Ulster Museum United Kingdom")
location<jupyter_output><empty_output><jupyter_text>Great! Now we have the means of finding the relevant map information for individual entires. But to process the large amount of data, I followed [this YouTube tutorial](https://www.youtube.com/watch?v=0IjdfgmWzMk) for some extra help.<jupyter_code>def find_location(row):
    
    place = row['place']
    
    location = geolocator.geocode(place)
    
    if location != None:
        return location.address, location.latitude, location.longitude, location.raw['importance']
    else:
        return "Not Found", "Not Found", "Not Found", "Not Found"<jupyter_output><empty_output><jupyter_text>To expand on my data, I needed to add a new column to my dataframe -- the addresses of the museums.<jupyter_code>df1["Address"]=df1["Place"]+", "+df1["City"]+", "+df1["Country"]
df1
#Then I added this string to the geocode to create a coordinates column.

df1["Coordinates"]=df1["Address"].apply(geolocator.geocode)
df1<jupyter_output><empty_output><jupyter_text>After compiling the addresses and coordinates, the dataframe needed the latitude and longitudes for Folium to plot the locations on the map.<jupyter_code>df1["Latitude"]=df1["Coordinates"].apply(lambda x: x.latitude if x !=None else None)
df1["Longitude"]=df1["Coordinates"].apply(lambda x: x.longitude if x !=None else None)
df1
!pip install folium
import folium
beninbronze_map = folium.Map(location=[6.3350, 5.6037], zoom_start=7)
beninbronze_map<jupyter_output><empty_output><jupyter_text>I want Benin City to be the centre of this map, a rough point of origin. The Kingdom of Benin existed in modern day Nigeria, and it's where the looted bronzes belong. Only *nine* locations in Nigeria have collections of the bronzes, as opposed to the 152 others all over Europe, America, Canada, Russia, and Japan. Nigeria needs to be the centre of the conversation of the looted bronzes and repatriation, and so it is the centre of the map being created.<jupyter_code>def create_map_markers(row, beninbronze_map):
    folium.Marker(location=[row['lat'], row['lon']], popup=row['place']).add_to(beninbronze_map)
folium.Marker(location=[6.3350, 5.6037], popup="Send the bronzes home").add_to(beninbronze_map)
beninbronze_map
def create_map_markers(row, beninbronze_map):
    folium.Marker(location=[row['Latitude'], row['Longitude']], popup=row['Place']).add_to(beninbronze_map)<jupyter_output><empty_output><jupyter_text>Many of the data entries came up as "NaN" when the code was trying to find their latitude and longitude. It's an invalid entry and needs to be dropped in order for the map markers to function. This is very important to note: out of the 156 data entries, only 86 were plotted on the map. The missing coordinates need to be added to the dataframe, but that's a bit beyond the scope of this project. I invite anyone with the time to complete the map markers using the code examples above.<jupyter_code>df1.dropna(subset = ["Latitude"], inplace=True)
df1.dropna(subset = ["Longitude"], inplace=True)
nan_value = float("NaN")
df1.replace("",nan_value, inplace=True)
df1.dropna(subset = ["Latitude"], inplace=True)
df1.dropna(subset = ["Longitude"], inplace=True)
df1
df1.apply(lambda row:folium.CircleMarker(location=[row["Latitude"], 
                                                  row["Longitude"]]).add_to(beninbronze_map),
         axis=1)
beninbronze_map
beninbronze_map.save("stolen-bronzes-map.html")<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.08184049079754602, 'fraction_numerical': 0.013374233128834356, 'mean_word_length': 5.453681710213777, 'pattern_counts': {'":': 0, '<': 40, '<?xml version=': 0, '>': 43, 'https://': 7, 'lorem ipsum': 0, 'www.': 2, 'xml': 1}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '9', 'dir': 'jupyter-structured-clean-dedup', 'id': '9411', 'license': 'CC-BY-4.0', 'n_tokens_mistral': 2451, 'n_tokens_neox': 2311, 'n_words': 982, 'path': 'Stolen_Bronzes.ipynb', 'repo_name': 'shawngraham/tdm-notebooks', 'size': '8152'}