Quick Start

If you are familiar with using a REST based API already, this page contains some of the most common operations you are likely to want to use with our API.

If you are not familiar with REST APIs, we can recommend reading Introduction to Populating a Website with API Data from the excellent Programming Historian site.

You might also find the worked examples at our Data Explorations site useful to see how you can explore the collections data within a Python Jupyter notebook.

import sys
sys.path.append("/srv/explore-the-collections/code/ivpy/src/")
from ivpy import attach,show,compose,montage,histogram,scatter

Retrieve a single object record

The simplest operation. If you already know the system number assigned to the object you want to retrieve, then you can just retrieve it with a GET request.

import requests
req = requests.get('https://api.vam.ac.uk/v2/museumobject/O828146')
object_data = req.json()
print("The object you requested has the title '%s'" % object_data["record"]["titles"][0]["title"])
The object you requested has the title 'Picturesque Holland'

Here we just print out the first (‘primary’) title from the record. An overview of the most commonly used fields is in Field (Summary).

Searching object record(s)

If you are looking for records that match some word(s), you can use the ‘q’ parameter to query all fields in all object records and return those that match. Below we are searching for any records with the word ‘Etruria’

import requests
import pandas as pd

object_df = pd.read_csv("https://api.vam.ac.uk/v2/objects/search?q=Etruria&page_size=45&response_format=csv")
object_df.head()
accessionNumber accessionYear systemNumber objectType _primaryTitle _primaryPlace _primaryMaker__name _primaryMaker__association _primaryDate _primaryImageId _sampleMaterial _sampleTechnique _sampleStyle _currentLocation__displayName _objectContentWarning _imageContentWarning
0 S.1897-2013 2013 O1263636 Dish Mr Punch dish Staffordshire Wedgwood of Etruria and Barlaston makers mid 20th century 2013GL4747 earthenware moulding NaN In store False False
1 E.2084-1949 1949 O596454 Watercolour Wedgwood Works, Etruria Etruria Puller artist 1943 2008BV7718 watercolour painting NaN Prints & Drawings Study Room, level H False False
2 CIRC.737&A-1956 1956 O308545 Teapot and cover NaN england Etruria NaN c.1785 2019LN7745 stoneware NaN NaN In store False False
3 C.307-1951 1951 O278785 Plate NaN england Etruria NaN c.1812-1816 2010EC4842 porcelain NaN NaN Ceramics, Room 139, The Curtain Foundation Gal... False False
4 C.129 to A-1956 1956 O332163 Vase and cover NaN Staffordshire Etruria NaN 1869 2019LX6435 stoneware NaN NaN In store False False

Note

Some other common parameters you might want to use with searching (and filtering) are:

  • Pagination (page_size, page_offset) - Allows you to request results of different sizes and to skip through them

  • Ordering (order_by) - Order the results in particular order

  • Order Direction (order_sort) - Sort the results in a direction (increasing/decreasing)

See Restriction for full details on these parameters, see Searching on problems you might encounter with searching across all fields and how you might find more relevant results using more selective search parameters.

Let’s look at some object images (when available) all in one go using the Ivpy library. First we need to turn the image identifier into a IIIF URL, to request a (maximum of) 100 by 100 pixel thumbnail image.

IIIF_IMAGE_URL = "https://framemark.vam.ac.uk/collections/%s/full/!100,100/0/default.jpg"
object_df._primaryImageId = [IIIF_IMAGE_URL % item for item in object_df._primaryImageId]
object_df.head()
accessionNumber accessionYear systemNumber objectType _primaryTitle _primaryPlace _primaryMaker__name _primaryMaker__association _primaryDate _primaryImageId _sampleMaterial _sampleTechnique _sampleStyle _currentLocation__displayName _objectContentWarning _imageContentWarning
0 S.1897-2013 2013 O1263636 Dish Mr Punch dish Staffordshire Wedgwood of Etruria and Barlaston makers mid 20th century https://framemark.vam.ac.uk/collections/2013GL... earthenware moulding NaN In store False False
1 E.2084-1949 1949 O596454 Watercolour Wedgwood Works, Etruria Etruria Puller artist 1943 https://framemark.vam.ac.uk/collections/2008BV... watercolour painting NaN Prints & Drawings Study Room, level H False False
2 CIRC.737&A-1956 1956 O308545 Teapot and cover NaN england Etruria NaN c.1785 https://framemark.vam.ac.uk/collections/2019LN... stoneware NaN NaN In store False False
3 C.307-1951 1951 O278785 Plate NaN england Etruria NaN c.1812-1816 https://framemark.vam.ac.uk/collections/2010EC... porcelain NaN NaN Ceramics, Room 139, The Curtain Foundation Gal... False False
4 C.129 to A-1956 1956 O332163 Vase and cover NaN Staffordshire Etruria NaN 1869 https://framemark.vam.ac.uk/collections/2019LX... stoneware NaN NaN In store False False

Now we’ve updated the _primaryImageId column to contain the full URL to get the thumbnail image, we can pass this to the attach method from Ivpy, telling it to use that field to create a montage of all the images.

attach(object_df, "_primaryImageId")
show()
_images/quick-start_11_0.png

Some of the objects don’t have images hence the gaps, we could remove those by adding the parameter ‘images_exist=1’ to our query to only retrieve objects with images.

Filtering object records(s)

Rather than searching for words occuring anywhere in a record, filtering matches on identifiers assigned to a concept such as a type of material, a production technnique, a person, etc. The fields that make us of these identifiers are called controlled vocabulary fields. For example, to find all object records that mention the use of ‘jet’ (which has the identifier ‘AAT45514’) as a material:

import requests
import pandas as pd

object_df = pd.read_csv("https://api.vam.ac.uk/v2/objects/search?id_material=AAT45514&page_size=50&response_format=csv")
object_df.head()
accessionNumber accessionYear systemNumber objectType _primaryTitle _primaryPlace _primaryMaker__name _primaryMaker__association _primaryDate _primaryImageId _sampleMaterial _sampleTechnique _sampleStyle _currentLocation__displayName _objectContentWarning _imageContentWarning
0 S.1440-1984 1984 O101999 Hat NaN NaN L & H Nathan Ltd Costumier 1950 2019MK5645 velvet NaN NaN In store False False
1 S.1369-1984 1984 O100800 Sleeve NaN NaN NaN NaN Early 19th century 2017KJ9878 velvet embroidering NaN In store False False
2 CIRC.68-1950 1950 O110902 Brooch NaN Germany Unknown NaN ca. 1860 2006BJ4470 porcelain NaN NaN Jewellery, Rooms 91, The William and Judith Bo... False False
3 A.12-1953 1953 O256858 Rosary bead Christ on the Cross and St James the Greater Santiago de Compostela Unknown NaN 1600-1700 2006AF2948 jet NaN NaN In store False False
4 T.236B&C-1986 1986 O1174801 Pair of earrings NaN NaN Unknown NaN before 1986 2019MD7121 jet cutting (glassworking) NaN In store False False

Note

See much more on this Filtering. Some common identifiers are listed in Identifiers to get you started.

Clustering object records

If you are more interested in the numbers of objects that match a query than the individual objects themselves, you can use the Introduction endpoints which returns the counts of objects matching on one or more of the controlled vocabulary fields in the record. There are two endpoints, one returns counts for all controlled vocab. fields, the other will only return the counts for the controlled vocab. field of interest (material, technique, person, etc).

All clusters

import requests
import pandas as pd
import altair as alt

req = requests.get('https://api.vam.ac.uk/v2/objects/clusters/search?q=Paris')
object_data = req.json()
object_info = object_data["info"]
record_count = object_info["record_count"]
object_clusters = object_data["clusters"]

print(f"The matching {record_count} object records for the query 'Paris' have these clusters:")

for cluster_type in object_clusters:
    print("  Cluster type '%s' has the most common value '%s'" % (cluster_type, object_clusters[cluster_type]["terms"][0]["value"]))
The matching 74190 object records for the query 'Paris' have these clusters:
  Cluster type 'category' has the most common value 'Designs'
  Cluster type 'person' has the most common value 'Jean-Charles Worth'
  Cluster type 'organisation' has the most common value 'Worth'
  Cluster type 'collection' has the most common value 'Prints, Drawings & Paintings Collection'
  Cluster type 'gallery' has the most common value 'Prints & Drawings Study Room, level E'
  Cluster type 'style' has the most common value 'French School'
  Cluster type 'place' has the most common value 'Paris'
  Cluster type 'object_type' has the most common value 'Fashion design'
  Cluster type 'technique' has the most common value 'watercolour drawing'
  Cluster type 'material' has the most common value 'watercolour'
  Cluster type 'maker' has the most common value 'Worth'
  Cluster type 'associated' has the most common value 'Louvre (Paris)'
  Cluster type 'depicts' has the most common value 'Paris'
  Cluster type 'accession_year' has the most common value '1957'

Single cluster type(s)

If you already know the controlled vocab field you want to retrieve (for example materials), you have two choices. You can pass a ‘cluster_type’ parameter to the same endpoint as above, the response is the same but returns only the field you specified. For example

import requests
import pandas as pd
import altair as alt

req = requests.get('https://api.vam.ac.uk/v2/objects/clusters/search?cluster_type=material&id_place=x29337&made_after_year=1700&made_before_year=1800&cluster_size=10')
object_data = req.json()
object_clusters = object_data["clusters"]
materials = object_clusters["material"]["terms"]

materials_df = pd.DataFrame(materials[0:10])
alt.Chart(materials_df, title="Materials used in C18th Welsh objects").mark_bar().encode(
    x=alt.X('value', sort='-y', title='Material'),
    y=alt.Y('count', title='Number of Objects'))

Specified cluster type

Alternatively, you can use a different endpoint to request only the single cluster type. This returns only the counts without any other information, making it slightly easy to load into programmes such as Pandas.

import pandas as pd
import altair as alt

materials_df = pd.read_json('https://api.vam.ac.uk/v2/objects/clusters/material/search?id_place=x29337&made_after_year=1700&made_before_year=1800&cluster_size=10', orient='columns')
alt.Chart(materials_df, title="Materials used in C18th Welsh objects held at the V&A").mark_bar().encode(
    x=alt.X('value', sort='-y', title='Material'),
    y=alt.Y('count', title='Number of Objects'))