7. Mysteries of the Deep

Fish. The most mysterious of the sea creatures (opinions vary). Let’s see if we can find clues to their behaviour in museum objects, looking at how they have been described throughout history, what their habitats have been, and what other creatures they tend to hang out with. For this we will use fish based collection data from the V&A and Chester Beatty.

Chester Beatty Collections

Chester Beatty provide IIIF manifests which helpfully gives some descriptions of the objects that are machine readable, and of course also links to the images. After a search for fish snuff bottles (the whole snuff bottle collection at the Chester Beatty is well worth exploring), we can see the identifiers we can use to request each manifest.

identifiers = [
    'C_0905', 'C_0415', 'C_0395' , 'C_0374','C_0702',
    'C_0661', 'C_0730', 'C_0759' , 'C_0826', 'C_0489',
    'C_0871', 'C_0632', 'C_0121' , 'C_0657', 'C_0488',
    'C_0211', 'C_0329', 'C_0480' , 'C_0159', 'C_0369',
    'C_0460', 'C_0682', 'C_0070' , 'C_0341', 'C_0930' 
]

base_url = 'https://viewer.cbl.ie/viewer/api/v1/records/'
import requests
import pandas as pd

bottle_types = []
for identifier in identifiers:
  # Request the IIIF Presentation API manifest  
  req = requests.get(f'{base_url}{identifier}/manifest')
  fish_json = req.json()
  thumbnail_url = ""
  if 'thumbnail' in fish_json:
    thumbnail_url = fish_json['thumbnail']['@id']
  metadata = {}
  if 'metadata' in fish_json:
    for elem in fish_json['metadata']:
      if elem['label'] == "Description":
        bottle_types.append(["Chester Beatty", elem['value'], thumbnail_url])

V&A Collections

For the V&A we issue a query to the API and use either the physical description or the summary description if available.

import requests
import pandas as pd

vam_bottles_df = pd.read_csv('https://api.vam.ac.uk/v2/objects/search/?kw_object_type=Snuff%20bottle&page_size=25&response_format=csv')

bottle_types = []

for index, obj in vam_bottles_df.iterrows():
    object_data = requests.get(f"https://api.vam.ac.uk/v2/object/{obj['systemNumber']}")
    obj_json = object_data.json()
    if len(obj_json['record']['physicalDescription']) > 0:
      if obj_json['meta']['images'] is not None:
        bottle_types.append(["V&A", obj_json['record']['physicalDescription'], obj_json['meta']['images']['_primary_thumbnail']])
    else:
      if obj_json['meta']['images'] is not None:
        bottle_types.append(["V&A", obj_json['record']['summaryDescription'], obj_json['meta']['images']['_primary_thumbnail']])
    

We now combine the two collections so we can analyse them together using scattertext

import pandas as pd

bottle_types_df = pd.DataFrame(bottle_types, columns=('Institution', 'Description', 'Thumbnail'))
import scattertext as st
import pandas as pd

bottle_types_df = pd.DataFrame(bottle_types, columns=('Institution', 'Description', 'Thumbnail'))

corpus = st.CorpusFromPandas(bottle_types_df, category_col='Institution', text_col='Description').build()

Note

Formatting is currently being lost on the page with scattertext HTML being displayed within the notebook

html = st.produce_scattertext_explorer(corpus, category='V&A', category_name='V&A', not_category_name='Chester Beatty', minimum_term_frequency=2, width_in_pixels=1000 )
%%HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.6.2/d3.min.js"></script>
from IPython.core.display import display, HTML
HTML(html)

Conclusion

Well, from a limited dataset, we can see that fish are, on average, associated with bamboo and dragons in both collections, so that’s been very useful in learning about their natural habitat.

From a more critical viewpoint, we could say this very small self-selected dataset shows this example is mostly meaningless. But perhaps with more collections data added… No, it would still be meaningless. But do look at the snuff bottles at Chester Beatty) and at the V&A