The BNB Linked Data Platform provides access to the British National Bibliography (BNB) published as linked open data and made available through SPARQL services.
This notebook explains how to query the repository and obtain places of publication (fields blt:publication and blt:projectedPublication ) to show an interactive map. Thanks that the works are linked to GeoNames, the records can be linked to external repositories. This notebook obtains information from Wikidata, showing the benefits of Linked Open Data.
In this section, you can set the author from the BNB by using its identifier.
#bnbIdAuthor = 'http://bnb.data.bl.uk/id/person/DickensCharles1812-1870'
#bnbIdAuthor = 'http://bnb.data.bl.uk/id/person/BlakeWilliam1757-1827'
bnbIdAuthor = 'http://bnb.data.bl.uk/id/person/WoolfVirginia1882-1941'
#bnbIdAuthor = 'http://bnb.data.bl.uk/id/person/ShakespeareWilliam1564-1616'
import folium
import requests
import pandas as pd
import json
import csv
import matplotlib.pyplot as plt
from pandas.io.json import json_normalize
We will use the SPARQL endpoint to create the query and configure the request to retrieve json as a result.
url = 'https://bnb.data.bl.uk/sparql'
query = """
PREFIX bibo: <http://purl.org/ontology/bibo/>
PREFIX bio: <http://purl.org/vocab/bio/0.1/>
PREFIX blt: <http://www.bl.uk/schemas/bibliographic/blterms#>
PREFIX dct: <http://purl.org/dc/terms/>
PREFIX event: <http://purl.org/NET/c4dm/event.owl#>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX geo: <http://www.w3.org/2003/01/geo/wgs84_pos#>
PREFIX isbd: <http://iflastandards.info/ns/isbd/elements/>
PREFIX org: <http://www.w3.org/ns/org#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX rdau: <http://rdaregistry.info/Elements/u/>
PREFIX madsrdf: <http://www.loc.gov/mads/rdf/v1#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
PREFIX void: <http://rdfs.org/ns/void#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX umbel: <http://umbel.org/umbel#>
PREFIX schema: <http://schema.org/>
PREFIX c4dm: <http://purl.org/NET/c4dm/event.owl#>
SELECT DISTINCT ?resource ?title ?date ?place WHERE {{
graph <http://bnb.data.bl.uk/id/graph/BNBCIP> {{
?resource ?p <{0}> ;
dct:title ?title ;
schema:datePublished ?date .
OPTIONAL {{
?resource blt:projectedPublication ?publication .
?publication c4dm:place ?place .
FILTER regex(?place, "geonames", "i")
}}
OPTIONAL {{
?resource blt:publication ?publication .
?publication c4dm:place ?place .
FILTER regex(?place, "geonames", "i")
}}
}}
}} LIMIT 500
"""
query = query.format(bnbIdAuthor)
# use json as a result
headers = {'Accept': 'application/sparql-results+json'}
r = requests.get(url, params = {'format': 'application/sparql-results+json', 'query': query}, headers=headers)
print('Elements retrieved!')
print(r.text)
Elements retrieved! { "head": { "link": [], "vars": ["resource", "title", "date", "place"] }, "results": { "distinct": false, "ordered": true, "bindings": [ { "resource": { "type": "uri", "value": "http://bnb.data.bl.uk/id/resource/013001764" } , "title": { "type": "literal", "value": "The years" } , "date": { "type": "literal", "value": "2004-12" } , "place": { "type": "uri", "value": "http://sws.geonames.org/6269131/" }}, { "resource": { "type": "uri", "value": "http://bnb.data.bl.uk/id/resource/019599487" } , "title": { "type": "literal", "value": "Mrs Dalloway" } , "date": { "type": "literal", "value": "2020-01" } , "place": { "type": "uri", "value": "http://sws.geonames.org/6269131/" }}, { "resource": { "type": "uri", "value": "http://bnb.data.bl.uk/id/resource/017816985" } , "title": { "type": "literal", "value": "Mrs Dalloway" } , "date": { "type": "literal", "value": "2016-05" } , "place": { "type": "uri", "value": "http://sws.geonames.org/6269131/" }}, { "resource": { "type": "uri", "value": "http://bnb.data.bl.uk/id/resource/015711457" } , "title": { "type": "literal", "value": "Mrs Dalloway" } , "date": { "type": "literal", "value": "2011-04" } , "place": { "type": "uri", "value": "http://sws.geonames.org/6252001/" }}, { "resource": { "type": "uri", "value": "http://bnb.data.bl.uk/id/resource/018460540" } , "title": { "type": "literal", "value": "Orlando" } , "date": { "type": "literal", "value": "2017-10" } , "place": { "type": "uri", "value": "http://sws.geonames.org/6269131/" }}, { "resource": { "type": "uri", "value": "http://bnb.data.bl.uk/id/resource/018460544" } , "title": { "type": "literal", "value": "A room of one's own" } , "date": { "type": "literal", "value": "2017-10" } , "place": { "type": "uri", "value": "http://sws.geonames.org/6269131/" }}, { "resource": { "type": "uri", "value": "http://bnb.data.bl.uk/id/resource/018460549" } , "title": { "type": "literal", "value": "Mrs Dalloway" } , "date": { "type": "literal", "value": "2017-10" } , "place": { "type": "uri", "value": "http://sws.geonames.org/6269131/" }}, { "resource": { "type": "uri", "value": "http://bnb.data.bl.uk/id/resource/018460551" } , "title": { "type": "literal", "value": "To the lighthouse" } , "date": { "type": "literal", "value": "2017-10" } , "place": { "type": "uri", "value": "http://sws.geonames.org/6269131/" }}, { "resource": { "type": "uri", "value": "http://bnb.data.bl.uk/id/resource/018462175" } , "title": { "type": "literal", "value": "The illustrated letters of Virginia Woolf" } , "date": { "type": "literal", "value": "2017-10" } , "place": { "type": "uri", "value": "http://sws.geonames.org/6269131/" }}, { "resource": { "type": "uri", "value": "http://bnb.data.bl.uk/id/resource/018463437" } , "title": { "type": "literal", "value": "Monday or Tuesday" } , "date": { "type": "literal", "value": "2017-08" } , "place": { "type": "uri", "value": "http://sws.geonames.org/6252001/" }}, { "resource": { "type": "uri", "value": "http://bnb.data.bl.uk/id/resource/019345275" } , "title": { "type": "literal", "value": "A room of one's own" } , "date": { "type": "literal", "value": "2019-06" } , "place": { "type": "uri", "value": "http://sws.geonames.org/6269131/" }}, { "resource": { "type": "uri", "value": "http://bnb.data.bl.uk/id/resource/019428998" } , "title": { "type": "literal", "value": "Flush" } , "date": { "type": "literal", "value": "2019-08" } , "place": { "type": "uri", "value": "http://sws.geonames.org/6269131/" }}, { "resource": { "type": "uri", "value": "http://bnb.data.bl.uk/id/resource/019701723" } , "title": { "type": "literal", "value": "Jacob's room" } , "date": { "type": "literal", "value": "2020-04" } , "place": { "type": "uri", "value": "http://sws.geonames.org/6269131/" }}, { "resource": { "type": "uri", "value": "http://bnb.data.bl.uk/id/resource/018827821" } , "title": { "type": "literal", "value": "Mrs Dalloway" } , "date": { "type": "literal", "value": "2018-06" } , "place": { "type": "uri", "value": "http://sws.geonames.org/6269131/" }}, { "resource": { "type": "uri", "value": "http://bnb.data.bl.uk/id/resource/018827843" } , "title": { "type": "literal", "value": "To the lighthouse" } , "date": { "type": "literal", "value": "2018-06" } , "place": { "type": "uri", "value": "http://sws.geonames.org/6269131/" }}, { "resource": { "type": "uri", "value": "http://bnb.data.bl.uk/id/resource/018832597" } , "title": { "type": "literal", "value": "A room of one's own" } , "date": { "type": "literal", "value": "2018-06" } , "place": { "type": "uri", "value": "http://sws.geonames.org/6269131/" }}, { "resource": { "type": "uri", "value": "http://bnb.data.bl.uk/id/resource/012936730" } , "title": { "type": "literal", "value": "A room of one's own" } , "date": { "type": "literal", "value": "2004-09" } , "place": { "type": "uri", "value": "http://sws.geonames.org/6269131/" }}, { "resource": { "type": "uri", "value": "http://bnb.data.bl.uk/id/resource/016530866" } , "title": { "type": "literal", "value": "Virginia Woolf : selected novels" } , "date": { "type": "literal", "value": "2014-01" } , "place": { "type": "uri", "value": "http://sws.geonames.org/6269131/" }}, { "resource": { "type": "uri", "value": "http://bnb.data.bl.uk/id/resource/006890884" } , "title": { "type": "literal", "value": "Night and day" } , "date": { "type": "literal", "value": "2002-06" } , "place": { "type": "uri", "value": "http://sws.geonames.org/6252001/" }}, { "resource": { "type": "uri", "value": "http://bnb.data.bl.uk/id/resource/016094837" } , "title": { "type": "literal", "value": "Virginia Woolf : selected novels" } , "date": { "type": "literal", "value": "2012-09" } , "place": { "type": "uri", "value": "http://sws.geonames.org/6269131/" }}, { "resource": { "type": "uri", "value": "http://bnb.data.bl.uk/id/resource/018519568" } , "title": { "type": "literal", "value": "Between the acts" } , "date": { "type": "literal", "value": "2017-07" } , "place": { "type": "uri", "value": "http://sws.geonames.org/6269131/" }}, { "resource": { "type": "uri", "value": "http://bnb.data.bl.uk/id/resource/018934357" } , "title": { "type": "literal", "value": "Virginia Woolf in Richmond" } , "date": { "type": "literal", "value": "2018-09" } , "place": { "type": "uri", "value": "http://sws.geonames.org/6269131/" }}, { "resource": { "type": "uri", "value": "http://bnb.data.bl.uk/id/resource/018009117" } , "title": { "type": "literal", "value": "Selected diaries" } , "date": { "type": "literal", "value": "2016-10" } , "place": { "type": "uri", "value": "http://sws.geonames.org/6269131/" }}, { "resource": { "type": "uri", "value": "http://bnb.data.bl.uk/id/resource/019242375" } , "title": { "type": "literal", "value": "The years" } , "date": { "type": "literal", "value": "2019-04" } , "place": { "type": "uri", "value": "http://sws.geonames.org/6269131/" }}, { "resource": { "type": "uri", "value": "http://bnb.data.bl.uk/id/resource/019280192" } , "title": { "type": "literal", "value": "Between the acts" } , "date": { "type": "literal", "value": "2019-05" } , "place": { "type": "uri", "value": "http://sws.geonames.org/6269131/" }}, { "resource": { "type": "uri", "value": "http://bnb.data.bl.uk/id/resource/019280193" } , "title": { "type": "literal", "value": "Selected short stories" } , "date": { "type": "literal", "value": "2019-05" } , "place": { "type": "uri", "value": "http://sws.geonames.org/6269131/" }}, { "resource": { "type": "uri", "value": "http://bnb.data.bl.uk/id/resource/019242373" } , "title": { "type": "literal", "value": "Mrs Dalloway" } , "date": { "type": "literal", "value": "2019-04" } , "place": { "type": "uri", "value": "http://sws.geonames.org/6269131/" }}, { "resource": { "type": "uri", "value": "http://bnb.data.bl.uk/id/resource/019635379" } , "title": { "type": "literal", "value": "Mrs. Dalloway" } , "date": { "type": "literal", "value": "2020-02" } , "place": { "type": "uri", "value": "http://sws.geonames.org/6252001/" }}, { "resource": { "type": "uri", "value": "http://bnb.data.bl.uk/id/resource/019049782" } , "title": { "type": "literal", "value": "A passionate apprentice : the early journals 1897-1909" } , "date": { "type": "literal", "value": "2018-11" } , "place": { "type": "uri", "value": "http://sws.geonames.org/6269131/" }}, { "resource": { "type": "uri", "value": "http://bnb.data.bl.uk/id/resource/019394492" } , "title": { "type": "literal", "value": "Night and day" } , "date": { "type": "literal", "value": "2019-07" } , "place": { "type": "uri", "value": "http://sws.geonames.org/6252001/" }}, { "resource": { "type": "uri", "value": "http://bnb.data.bl.uk/id/resource/019201393" } , "title": { "type": "literal", "value": "Orlando" } , "date": { "type": "literal", "value": "2019-03" } , "place": { "type": "uri", "value": "http://sws.geonames.org/6269131/" }}, { "resource": { "type": "uri", "value": "http://bnb.data.bl.uk/id/resource/019201394" } , "title": { "type": "literal", "value": "A room of one's own ; and, Three guineas" } , "date": { "type": "literal", "value": "2019-03" } , "place": { "type": "uri", "value": "http://sws.geonames.org/6269131/" }}, { "resource": { "type": "uri", "value": "http://bnb.data.bl.uk/id/resource/019529568" } , "title": { "type": "literal", "value": "Genius and ink : Virginia Woolf on how to read" } , "date": { "type": "literal", "value": "2019-11" } , "place": { "type": "uri", "value": "http://sws.geonames.org/6269131/" }}, { "resource": { "type": "uri", "value": "http://bnb.data.bl.uk/id/resource/019664287" } , "title": { "type": "literal", "value": "Mrs Dalloway" } , "date": { "type": "literal", "value": "2020-03" } , "place": { "type": "uri", "value": "http://sws.geonames.org/6269131/" }}, { "resource": { "type": "uri", "value": "http://bnb.data.bl.uk/id/resource/019664288" } , "title": { "type": "literal", "value": "A room of one's own" } , "date": { "type": "literal", "value": "2020-03" } , "place": { "type": "uri", "value": "http://sws.geonames.org/6269131/" }}, { "resource": { "type": "uri", "value": "http://bnb.data.bl.uk/id/resource/019664289" } , "title": { "type": "literal", "value": "Orlando" } , "date": { "type": "literal", "value": "2020-03" } , "place": { "type": "uri", "value": "http://sws.geonames.org/6269131/" }} ] } }
bnbdata = json.loads(r.text)
with open('bnb_records.csv', 'w', newline='') as file:
csv_out = csv.writer(file, delimiter = ',', quotechar = '"', quoting = csv.QUOTE_MINIMAL)
#csv_out = csv.writer(open('bnb_records.csv', 'w'), delimiter = ',', quotechar = '"', quoting = csv.QUOTE_MINIMAL)
csv_out.writerow(['resource', 'place', 'title', 'date'])
for i in bnbdata['results']['bindings']:
resource = place = title = date =''
resource = i['resource']['value']
#if "place" in i:
place = i['place']['value']
title = i['title']['value']
date = i['date']['value']
csv_out.writerow([resource,place,title,date])
# Load the CSV file from GitHub.
# This puts the data in a Pandas DataFrame
df = pd.read_csv('bnb_records.csv')
df
resource | place | title | date | |
---|---|---|---|---|
0 | http://bnb.data.bl.uk/id/resource/013001764 | http://sws.geonames.org/6269131/ | The years | 2004-12 |
1 | http://bnb.data.bl.uk/id/resource/019599487 | http://sws.geonames.org/6269131/ | Mrs Dalloway | 2020-01 |
2 | http://bnb.data.bl.uk/id/resource/017816985 | http://sws.geonames.org/6269131/ | Mrs Dalloway | 2016-05 |
3 | http://bnb.data.bl.uk/id/resource/015711457 | http://sws.geonames.org/6252001/ | Mrs Dalloway | 2011-04 |
4 | http://bnb.data.bl.uk/id/resource/018460540 | http://sws.geonames.org/6269131/ | Orlando | 2017-10 |
5 | http://bnb.data.bl.uk/id/resource/018460544 | http://sws.geonames.org/6269131/ | A room of one's own | 2017-10 |
6 | http://bnb.data.bl.uk/id/resource/018460549 | http://sws.geonames.org/6269131/ | Mrs Dalloway | 2017-10 |
7 | http://bnb.data.bl.uk/id/resource/018460551 | http://sws.geonames.org/6269131/ | To the lighthouse | 2017-10 |
8 | http://bnb.data.bl.uk/id/resource/018462175 | http://sws.geonames.org/6269131/ | The illustrated letters of Virginia Woolf | 2017-10 |
9 | http://bnb.data.bl.uk/id/resource/018463437 | http://sws.geonames.org/6252001/ | Monday or Tuesday | 2017-08 |
10 | http://bnb.data.bl.uk/id/resource/019345275 | http://sws.geonames.org/6269131/ | A room of one's own | 2019-06 |
11 | http://bnb.data.bl.uk/id/resource/019428998 | http://sws.geonames.org/6269131/ | Flush | 2019-08 |
12 | http://bnb.data.bl.uk/id/resource/019701723 | http://sws.geonames.org/6269131/ | Jacob's room | 2020-04 |
13 | http://bnb.data.bl.uk/id/resource/018827821 | http://sws.geonames.org/6269131/ | Mrs Dalloway | 2018-06 |
14 | http://bnb.data.bl.uk/id/resource/018827843 | http://sws.geonames.org/6269131/ | To the lighthouse | 2018-06 |
15 | http://bnb.data.bl.uk/id/resource/018832597 | http://sws.geonames.org/6269131/ | A room of one's own | 2018-06 |
16 | http://bnb.data.bl.uk/id/resource/012936730 | http://sws.geonames.org/6269131/ | A room of one's own | 2004-09 |
17 | http://bnb.data.bl.uk/id/resource/016530866 | http://sws.geonames.org/6269131/ | Virginia Woolf : selected novels | 2014-01 |
18 | http://bnb.data.bl.uk/id/resource/006890884 | http://sws.geonames.org/6252001/ | Night and day | 2002-06 |
19 | http://bnb.data.bl.uk/id/resource/016094837 | http://sws.geonames.org/6269131/ | Virginia Woolf : selected novels | 2012-09 |
20 | http://bnb.data.bl.uk/id/resource/018519568 | http://sws.geonames.org/6269131/ | Between the acts | 2017-07 |
21 | http://bnb.data.bl.uk/id/resource/018934357 | http://sws.geonames.org/6269131/ | Virginia Woolf in Richmond | 2018-09 |
22 | http://bnb.data.bl.uk/id/resource/018009117 | http://sws.geonames.org/6269131/ | Selected diaries | 2016-10 |
23 | http://bnb.data.bl.uk/id/resource/019242375 | http://sws.geonames.org/6269131/ | The years | 2019-04 |
24 | http://bnb.data.bl.uk/id/resource/019280192 | http://sws.geonames.org/6269131/ | Between the acts | 2019-05 |
25 | http://bnb.data.bl.uk/id/resource/019280193 | http://sws.geonames.org/6269131/ | Selected short stories | 2019-05 |
26 | http://bnb.data.bl.uk/id/resource/019242373 | http://sws.geonames.org/6269131/ | Mrs Dalloway | 2019-04 |
27 | http://bnb.data.bl.uk/id/resource/019635379 | http://sws.geonames.org/6252001/ | Mrs. Dalloway | 2020-02 |
28 | http://bnb.data.bl.uk/id/resource/019049782 | http://sws.geonames.org/6269131/ | A passionate apprentice : the early journals 1... | 2018-11 |
29 | http://bnb.data.bl.uk/id/resource/019394492 | http://sws.geonames.org/6252001/ | Night and day | 2019-07 |
30 | http://bnb.data.bl.uk/id/resource/019201393 | http://sws.geonames.org/6269131/ | Orlando | 2019-03 |
31 | http://bnb.data.bl.uk/id/resource/019201394 | http://sws.geonames.org/6269131/ | A room of one's own ; and, Three guineas | 2019-03 |
32 | http://bnb.data.bl.uk/id/resource/019529568 | http://sws.geonames.org/6269131/ | Genius and ink : Virginia Woolf on how to read | 2019-11 |
33 | http://bnb.data.bl.uk/id/resource/019664287 | http://sws.geonames.org/6269131/ | Mrs Dalloway | 2020-03 |
34 | http://bnb.data.bl.uk/id/resource/019664288 | http://sws.geonames.org/6269131/ | A room of one's own | 2020-03 |
35 | http://bnb.data.bl.uk/id/resource/019664289 | http://sws.geonames.org/6269131/ | Orlando | 2020-03 |
# How many items?
len(df)
36
places_by_number = df.groupby("place")["resource"].count()
places_by_number
place http://sws.geonames.org/6252001/ 5 http://sws.geonames.org/6269131/ 31 Name: resource, dtype: int64
### We can access the count of each place
places_by_number[['http://sws.geonames.org/6269131/']][0]
31
This chart shows the number of resources by date.
ax = df['date'].value_counts().plot(kind='bar',
figsize=(14,8),
title="Number of resources per date")
ax.set_xlabel("Dates")
ax.set_ylabel("Resources")
plt.show()
# First we create a new column in pandas with the year
df['year'] = pd.DatetimeIndex(df['date']).year
df['year']
0 2004 1 2020 2 2016 3 2011 4 2017 5 2017 6 2017 7 2017 8 2017 9 2017 10 2019 11 2019 12 2020 13 2018 14 2018 15 2018 16 2004 17 2014 18 2002 19 2012 20 2017 21 2018 22 2016 23 2019 24 2019 25 2019 26 2019 27 2020 28 2018 29 2019 30 2019 31 2019 32 2019 33 2020 34 2020 35 2020 Name: year, dtype: int64
ax = df['year'].value_counts().plot(kind='bar',
figsize=(14,8),
title="Number of resources per year")
ax.set_xlabel("Dates")
ax.set_ylabel("Resources")
plt.show()
# Get unique values
places = pd.unique(df['place']).tolist()
strplaces = ''
for a in sorted(places):
print(a)
strplaces = strplaces + ' \"' + a.replace("http://sws.geonames.org/", "").replace("/", "") + '\"'
http://sws.geonames.org/6252001/ http://sws.geonames.org/6269131/
url = 'https://query.wikidata.org/sparql'
query = """
PREFIX bibo: <http://purl.org/ontology/bibo/>
SELECT ?idgeonames ?lat ?lon ?x ?xLabel
WHERE {{
values ?idgeonames {{ {0} }}
?x wdt:P1566 ?idgeonames ;
p:P625 [
psv:P625 [
wikibase:geoLatitude ?lat ;
wikibase:geoLongitude ?lon ;
wikibase:geoGlobe ?globe ;
];
ps:P625 ?coord
]
SERVICE wikibase:label {{ bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en". }}
}}
"""
query = query.format(strplaces)
print(query)
# use json as a result
r = requests.get(url, params = {'format': 'json', 'query': query})
geopoints = r.json()
PREFIX bibo: <http://purl.org/ontology/bibo/> SELECT ?idgeonames ?lat ?lon ?x ?xLabel WHERE { values ?idgeonames { "6252001" "6269131" } ?x wdt:P1566 ?idgeonames ; p:P625 [ psv:P625 [ wikibase:geoLatitude ?lat ; wikibase:geoLongitude ?lon ; wikibase:geoGlobe ?globe ; ]; ps:P625 ?coord ] SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en". } }
map = folium.Map(location=[0,0], zoom_start=1.5)
for geo in geopoints['results']['bindings']:
idwikidata = geo['x']['value']
lat = geo['lat']['value']
lon = geo['lon']['value']
idgeonames = geo['idgeonames']['value']
label = geo['xLabel']['value']
print(lat, lon)
# adding a text to the popup
count = places_by_number[['http://sws.geonames.org/' + idgeonames + '/']][0]
popup = str(count) + " records published in <a hreh='" + str(idwikidata) + "'>" + label + "</a>"
folium.Marker([lat,lon], popup= popup).add_to(map)
38.895 -77.036666666667 53.0 -1.0
map