Imported all the notebooks
[tm351-notebooks.git] / notebooks / Example Linked Data Notebooks / LD.05 Federated Linked Data Demo.ipynb
1 {
2 "metadata": {
3 "name": "",
4 "signature": "sha256:07442bade4260807f42b4b69b3706e377b361830c122cdcd1341877b7eb427c4"
5 },
6 "nbformat": 3,
7 "nbformat_minor": 0,
8 "worksheets": [
9 {
10 "cells": [
11 {
12 "cell_type": "heading",
13 "level": 1,
14 "metadata": {},
15 "source": [
16 "Federated Linked Data Demo"
17 ]
18 },
19 {
20 "cell_type": "markdown",
21 "metadata": {},
22 "source": [
23 "One of the great promises of Linked Data is the ability to use common identifiers to run queries that pull in data elements from multiple data sources, something we might think of as akin to a distributed or federated JOIN.\n",
24 "\n",
25 "In [Federating SPARQL Queries Across Government Linked Data](http://johngoodwin225.wordpress.com/2014/03/22/federating-sparql-queries-across-government-linked-data/) and [Tell Me About Hampshire \u2013 Linking Government Data using SPARQL federation 2](http://johngoodwin225.wordpress.com/2014/03/23/tell-me-about-hamsphire-linking-government-data-using-sparql-federation-2/), the Ordnance Survey's Jon Goodwin describes how to run SPARQL queries across multiple sources. This notebook draws heavily on those articles."
26 ]
27 },
28 {
29 "cell_type": "code",
30 "collapsed": false,
31 "input": [
32 "#Import the necessary packages\n",
33 "from SPARQLWrapper import SPARQLWrapper, JSON\n",
34 "\n",
35 "#Add some helper functions\n",
36 "def runQuery(endpoint,prefix,q):\n",
37 " ''' Run a SPARQL query with a declared prefix over a specified endpoint '''\n",
38 " sparql = SPARQLWrapper(endpoint)\n",
39 " sparql.setQuery(prefix+q)\n",
40 " sparql.setReturnFormat(JSON)\n",
41 " return sparql.query().convert()\n",
42 "\n",
43 "import pandas as pd\n",
44 "\n",
45 "def dict2df(results):\n",
46 " ''' Hack a function to flatten the SPARQL query results and return the column values '''\n",
47 " data=[]\n",
48 " for result in results[\"results\"][\"bindings\"]:\n",
49 " tmp={}\n",
50 " for el in result:\n",
51 " tmp[el]=result[el]['value']\n",
52 " data.append(tmp)\n",
53 "\n",
54 " df = pd.DataFrame(data)\n",
55 " return df\n",
56 "\n",
57 "def dfResults(endpoint,prefix,q):\n",
58 " ''' Generate a data frame containing the results of running\n",
59 " a SPARQL query with a declared prefix over a specified endpoint '''\n",
60 " return dict2df( runQuery( endpoint, prefix, q ) )\n",
61 " \n",
62 "def printQuery(results,limit=''):\n",
63 " ''' Print the results from the SPARQL query '''\n",
64 " resdata=results[\"results\"][\"bindings\"]\n",
65 " if limit!='': resdata=results[\"results\"][\"bindings\"][:limit]\n",
66 " for result in resdata:\n",
67 " for ans in result:\n",
68 " print('{0}: {1}'.format(ans,result[ans]['value']))\n",
69 " print()\n",
70 "\n",
71 "def printRunQuery(endpoint,prefix,q,limit=''):\n",
72 " ''' Print the results from the SPARQL query '''\n",
73 " results=runQuery(endpoint,prefix,q)\n",
74 " printQuery(results,limit)"
75 ],
76 "language": "python",
77 "metadata": {},
78 "outputs": []
79 },
80 {
81 "cell_type": "markdown",
82 "metadata": {},
83 "source": [
84 "We are going to make use of several endpoints in this demonstration, so we need to declare each of them separately."
85 ]
86 },
87 {
88 "cell_type": "code",
89 "collapsed": false,
90 "input": [
91 "endpoint_envAgency='http://environment.data.gov.uk/sparql/bwq/query'"
92 ],
93 "language": "python",
94 "metadata": {},
95 "outputs": []
96 },
97 {
98 "cell_type": "markdown",
99 "metadata": {},
100 "source": [
101 "Let's try a simple query from the Environment Agency's Bathing Water Linked Data store to see what districts are covered."
102 ]
103 },
104 {
105 "cell_type": "code",
106 "collapsed": false,
107 "input": [
108 "prefix='''\n",
109 "'''\n",
110 "\n",
111 "q='''\n",
112 "SELECT ?x ?name ?district\n",
113 "WHERE {\n",
114 "?x a <http://environment.data.gov.uk/def/bathing-water/BathingWater> .\n",
115 "?x <http://www.w3.org/2000/01/rdf-schema#label> ?name .\n",
116 "?x <http://statistics.data.gov.uk/def/administrative-geography/district> ?district .}\n",
117 "'''\n",
118 "\n",
119 "df=dfResults(endpoint_envAgency,prefix,q)\n",
120 "df[:5]"
121 ],
122 "language": "python",
123 "metadata": {},
124 "outputs": []
125 },
126 {
127 "cell_type": "markdown",
128 "metadata": {},
129 "source": [
130 "Notice that the district codes include identifiers that are Ordnance Survey identifiers..."
131 ]
132 },
133 {
134 "cell_type": "markdown",
135 "metadata": {},
136 "source": [
137 "We can also query by name."
138 ]
139 },
140 {
141 "cell_type": "code",
142 "collapsed": false,
143 "input": [
144 "prefix='''\n",
145 "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>\n",
146 "PREFIX admingeo: <http://statistics.data.gov.uk/def/administrative-geography/>\n",
147 "'''\n",
148 "\n",
149 "q='''\n",
150 "SELECT ?x ?name ?district\n",
151 "WHERE {\n",
152 " #?x rdfs:label \"Selsey\" .\n",
153 "\n",
154 " ?x a <http://environment.data.gov.uk/def/bathing-water/BathingWater> .\n",
155 " ?x rdfs:label ?name .\n",
156 " ?x admingeo:district ?district .\n",
157 "}\n",
158 "'''\n",
159 "\n",
160 "printRunQuery(endpoint_envAgency,prefix,q,3)"
161 ],
162 "language": "python",
163 "metadata": {},
164 "outputs": []
165 },
166 {
167 "cell_type": "markdown",
168 "metadata": {},
169 "source": [
170 "Let's have a quick look at some Ordnance Survey Linked Data."
171 ]
172 },
173 {
174 "cell_type": "code",
175 "collapsed": false,
176 "input": [
177 "#endpoint_os='http://data.ordnancesurvey.co.uk/datasets/os-linked-data/apis/sparql'\n",
178 "endpoint_os='http://data.ordnancesurvey.co.uk/datasets/boundary-line/apis/sparql'"
179 ],
180 "language": "python",
181 "metadata": {},
182 "outputs": []
183 },
184 {
185 "cell_type": "markdown",
186 "metadata": {},
187 "source": [
188 "The OS identifier http://data.ordnancesurvey.co.uk/id/7000000000041421 corresponds to the South East region of the UK. We can query the Ordnance Survery endpoint to find other administrative regions contained within that area."
189 ]
190 },
191 {
192 "cell_type": "code",
193 "collapsed": false,
194 "input": [
195 "prefix='''\n",
196 "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>\n",
197 "PREFIX admingeo: <http://statistics.data.gov.uk/def/administrative-geography/>\n",
198 "PREFIX ossr: <http://data.ordnancesurvey.co.uk/ontology/spatialrelations/>\n",
199 "'''\n",
200 "\n",
201 "q='''\n",
202 "SELECT ?district ?districtname\n",
203 "WHERE {\n",
204 " ?district ossr:within <http://data.ordnancesurvey.co.uk/id/7000000000041421> .\n",
205 " ?district rdfs:label ?districtname .\n",
206 "}\n",
207 "'''\n",
208 "\n",
209 "df=dfResults(endpoint_os,prefix,q)\n",
210 "df[:5]"
211 ],
212 "language": "python",
213 "metadata": {},
214 "outputs": []
215 },
216 {
217 "cell_type": "code",
218 "collapsed": false,
219 "input": [
220 "#What's the code for the Isle of Wight?\n",
221 "for i in df[df['districtname']=='Isle of Wight']['district']: print(i)"
222 ],
223 "language": "python",
224 "metadata": {},
225 "outputs": []
226 },
227 {
228 "cell_type": "markdown",
229 "metadata": {},
230 "source": [
231 "If we look these up separately we see that one code (http://data.ordnancesurvey.co.uk/id/7000000000025195) refers to the Westminster constituency and the other (http://data.ordnancesurvey.co.uk/id/7000000000025469) to the Unitary Authority."
232 ]
233 },
234 {
235 "cell_type": "code",
236 "collapsed": false,
237 "input": [
238 "#This suggests we could have asked a more direct question of the Ordnance Survey\n",
239 "prefix='''\n",
240 "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>\n",
241 "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>\n",
242 "PREFIX admingeo: <http://statistics.data.gov.uk/def/administrative-geography/>\n",
243 "PREFIX ossr: <http://data.ordnancesurvey.co.uk/ontology/spatialrelations/>\n",
244 "PREFIX osadmingeo: <http://data.ordnancesurvey.co.uk/ontology/admingeo/>\n",
245 "'''\n",
246 "\n",
247 "q='''\n",
248 "SELECT ?district ?districtname ?type\n",
249 "WHERE {\n",
250 " ?district rdfs:label \"Isle of Wight\" ;\n",
251 " rdf:type osadmingeo:UnitaryAuthority .\n",
252 "}\n",
253 "'''\n",
254 "\n",
255 "printRunQuery(endpoint_os,prefix,q)"
256 ],
257 "language": "python",
258 "metadata": {},
259 "outputs": []
260 },
261 {
262 "cell_type": "code",
263 "collapsed": false,
264 "input": [
265 "#7000000000002625\n",
266 "q='''\n",
267 "SELECT ?district\n",
268 "WHERE {\n",
269 " ?district rdfs:label \"East Sussex\" .\n",
270 "}\n",
271 "'''\n",
272 "\n",
273 "printRunQuery(endpoint_os,prefix,q)"
274 ],
275 "language": "python",
276 "metadata": {},
277 "outputs": []
278 },
279 {
280 "cell_type": "markdown",
281 "metadata": {},
282 "source": [
283 "Let's see if the Environment Agency has any information about bathing water around the coast of East Sussex. One way would be to use the unitary authority identifier for this to anchor the search for areas that declare East Sussex as their administrative district."
284 ]
285 },
286 {
287 "cell_type": "code",
288 "collapsed": false,
289 "input": [
290 "q='''\n",
291 "SELECT ?x ?name ?districtname \n",
292 "WHERE {\n",
293 "\n",
294 " ?x <http://statistics.data.gov.uk/def/administrative-geography/district> <http://data.ordnancesurvey.co.uk/id/7000000000002625> .\n",
295 "\n",
296 " ?x a <http://environment.data.gov.uk/def/bathing-water/BathingWater> .\n",
297 " ?x <http://www.w3.org/2000/01/rdf-schema#label> ?name .\n",
298 " ?x <http://statistics.data.gov.uk/def/administrative-geography/district> ?district .\n",
299 " \n",
300 " ?district <http://www.w3.org/2000/01/rdf-schema#label> ?districtname .\n",
301 "}\n",
302 "ORDER BY ?districtname\n",
303 "'''\n",
304 "\n",
305 "runQuery(endpoint_envAgency,prefix,q)"
306 ],
307 "language": "python",
308 "metadata": {},
309 "outputs": []
310 },
311 {
312 "cell_type": "markdown",
313 "metadata": {},
314 "source": [
315 "Hmm.. no results...\n",
316 "\n",
317 "Note also that tt's probably easier to just query by name, as this example for the Isle of Wight shows."
318 ]
319 },
320 {
321 "cell_type": "code",
322 "collapsed": false,
323 "input": [
324 "q='''\n",
325 "SELECT ?x ?name ?districtname \n",
326 "WHERE {\n",
327 "\n",
328 " ?district <http://www.w3.org/2000/01/rdf-schema#label> 'Isle of Wight' .\n",
329 " \n",
330 " ?x a <http://environment.data.gov.uk/def/bathing-water/BathingWater> .\n",
331 " ?x <http://www.w3.org/2000/01/rdf-schema#label> ?name .\n",
332 " ?x <http://statistics.data.gov.uk/def/administrative-geography/district> ?district .\n",
333 " ?district <http://www.w3.org/2000/01/rdf-schema#label> ?districtname. \n",
334 "}\n",
335 "ORDER BY ?districtname\n",
336 "'''\n",
337 "\n",
338 "printRunQuery(endpoint_envAgency,prefix,q,3)"
339 ],
340 "language": "python",
341 "metadata": {},
342 "outputs": []
343 },
344 {
345 "cell_type": "markdown",
346 "metadata": {},
347 "source": [
348 "It seems that what we might need to do is search the Environment Agency for data about bathing water areas *within* East Sussex. To do that, we need to \"join\" queries onto both the Ordnance Survey and Environment Agency endpoints."
349 ]
350 },
351 {
352 "cell_type": "code",
353 "collapsed": false,
354 "input": [
355 "q='''\n",
356 "SELECT ?location ?districtname ?name ?sedimentname ?lat ?long\n",
357 "WHERE {\n",
358 "\n",
359 " SERVICE <http://data.ordnancesurvey.co.uk/datasets/boundary-line/apis/sparql> { \n",
360 "\n",
361 " ?area rdfs:label \"East Sussex\".\n",
362 " \n",
363 " ?district ossr:within ?area.\n",
364 " ?district rdfs:label ?districtname.\n",
365 " }\n",
366 " \n",
367 " ?location a <http://environment.data.gov.uk/def/bathing-water/BathingWater> .\n",
368 " ?location <http://environment.data.gov.uk/def/bathing-water/sedimentTypesPresent> ?sediment .\n",
369 " ?location <http://statistics.data.gov.uk/def/administrative-geography/district> ?district .\n",
370 " ?location rdfs:label ?name.\n",
371 " ?sediment rdfs:label ?sedimentname.\n",
372 " \n",
373 " ?location <http://location.data.gov.uk/def/ef/SamplingPoint/samplingPoint> ?samplingpoint.\n",
374 " ?samplingpoint <http://www.w3.org/2003/01/geo/wgs84_pos#lat> ?lat.\n",
375 " ?samplingpoint <http://www.w3.org/2003/01/geo/wgs84_pos#long> ?long.\n",
376 "\n",
377 " \n",
378 " FILTER(LANG(?sedimentname) = \"\" || LANGMATCHES(LANG(?sedimentname), \"en\"))\n",
379 " \n",
380 "}\n",
381 "ORDER BY ?districtname\n",
382 "'''\n",
383 "\n",
384 "printRunQuery(endpoint_envAgency,prefix,q,5)"
385 ],
386 "language": "python",
387 "metadata": {},
388 "outputs": []
389 },
390 {
391 "cell_type": "markdown",
392 "metadata": {},
393 "source": [
394 "Just by the by, let's plot those points to see where the locations are situated on a map."
395 ]
396 },
397 {
398 "cell_type": "code",
399 "collapsed": false,
400 "input": [
401 "#The master version of folium currently has an issue running on Python3\n",
402 "#!pip3 install git+https://github.com/tbicr/folium.git@fixed#folium\n",
403 "import folium\n",
404 "folium.initialize_notebook()"
405 ],
406 "language": "python",
407 "metadata": {},
408 "outputs": []
409 },
410 {
411 "cell_type": "code",
412 "collapsed": false,
413 "input": [
414 "df=dfResults(endpoint_envAgency,prefix,q)\n",
415 "df[:3]"
416 ],
417 "language": "python",
418 "metadata": {},
419 "outputs": []
420 },
421 {
422 "cell_type": "code",
423 "collapsed": false,
424 "input": [
425 "#Check that the lat and long values are numbers\n",
426 "df.dtypes"
427 ],
428 "language": "python",
429 "metadata": {},
430 "outputs": []
431 },
432 {
433 "cell_type": "code",
434 "collapsed": false,
435 "input": [
436 "#Cast the lat and long values to floats\n",
437 "df['lat']=df['lat'].astype(float)\n",
438 "df['long']=df['long'].astype(float)\n",
439 "\n",
440 "#Find their mean values to centre the map\n",
441 "latMean=df['lat'].mean()\n",
442 "longMean=df['long'].mean()"
443 ],
444 "language": "python",
445 "metadata": {},
446 "outputs": []
447 },
448 {
449 "cell_type": "code",
450 "collapsed": false,
451 "input": [
452 "#Create the map with an appropriate zoom level, and centre it\n",
453 "bathingwater = folium.Map(location=[latMean, longMean], zoom_start=10)\n",
454 "\n",
455 "#Iterate through the dataframe, adding each sample point as a marker on the map\n",
456 "for ix,row in df[['name','lat','long','sedimentname']].iterrows():\n",
457 " bathingwater.simple_marker( location=[row['lat'],row['long']], popup=row['name'] )\n",
458 "\n",
459 "#Render the map\n",
460 "bathingwater"
461 ],
462 "language": "python",
463 "metadata": {},
464 "outputs": []
465 },
466 {
467 "cell_type": "markdown",
468 "metadata": {},
469 "source": [
470 "As you can see, we can blend a variety of tools and techniques to help us make sense of the data and better understand it."
471 ]
472 },
473 {
474 "cell_type": "markdown",
475 "metadata": {},
476 "source": [
477 "Here are a couple of other data sources relating to geography that may be linkable?\n",
478 "\n",
479 "- British Geological Survey http://data.bgs.ac.uk/\n"
480 ]
481 },
482 {
483 "cell_type": "heading",
484 "level": 2,
485 "metadata": {},
486 "source": [
487 "Looking At Local Administrative Data"
488 ]
489 },
490 {
491 "cell_type": "markdown",
492 "metadata": {},
493 "source": [
494 "In this section, we'll show how a query similar to the one used in [Tell Me About Hampshire \u2013 Linking Government Data using SPARQL federation 2](http://johngoodwin225.wordpress.com/2014/03/23/tell-me-about-hamsphire-linking-government-data-using-sparql-federation-2/) can be pieced together."
495 ]
496 },
497 {
498 "cell_type": "markdown",
499 "metadata": {},
500 "source": [
501 "The area we'll explore is the Isle of Wight. The following query applied to the Ordnance Survey endpoint gives us a list of administrative regions contained within the Isle of Wight."
502 ]
503 },
504 {
505 "cell_type": "code",
506 "collapsed": false,
507 "input": [
508 "q='''\n",
509 "SELECT ?districtname\n",
510 "WHERE {\n",
511 "\n",
512 " ?iw rdfs:label \"Isle of Wight\" ;\n",
513 " rdf:type osadmingeo:UnitaryAuthority .\n",
514 "\n",
515 " ?district ossr:within ?iw .\n",
516 " ?district rdfs:label ?districtname.\n",
517 "}\n",
518 "'''\n",
519 "\n",
520 "printRunQuery(endpoint_os,prefix,q,5)"
521 ],
522 "language": "python",
523 "metadata": {},
524 "outputs": []
525 },
526 {
527 "cell_type": "markdown",
528 "metadata": {},
529 "source": [
530 "The next query shows how to pull in data from Open Data Communities, the Department for Communities and Local Government's (DCLG) Linked Data platfrom. In particular, let's pull back the URL for the website of the local authority for a specficied region and the council's IMD (Index of Multiple Deprivation) rank."
531 ]
532 },
533 {
534 "cell_type": "code",
535 "collapsed": false,
536 "input": [
537 "#Open Data Communities\n",
538 "endpoint_odc='http://opendatacommunities.org/sparql'\n",
539 "\n",
540 "q='''\n",
541 "SELECT ?councilwebsite ?imdrank ?authority ?authorityname \n",
542 "WHERE {\n",
543 "\n",
544 " ?iw rdfs:label \"Isle of Wight\" ;\n",
545 " rdf:type osadmingeo:UnitaryAuthority .\n",
546 " ?s <http://purl.org/linked-data/sdmx/2009/dimension#refArea> ?iw .\n",
547 " ?s <http://opendatacommunities.org/def/IMD#IMD-rank> ?imdrank . \n",
548 "\n",
549 "\n",
550 " ?authority <http://opendatacommunities.org/def/local-government/governs> ?iw .\n",
551 " ?authority <http://xmlns.com/foaf/0.1/page> ?councilwebsite .\n",
552 " ?authority rdfs:label ?authorityname.\n",
553 "}\n",
554 "'''\n",
555 "\n",
556 "printRunQuery(endpoint_odc,prefix,q,5)"
557 ],
558 "language": "python",
559 "metadata": {},
560 "outputs": []
561 },
562 {
563 "cell_type": "markdown",
564 "metadata": {},
565 "source": [
566 "We can combine those two queries together in a single query, whose execution starts at one of the endpoints, in this case the Ordnance Survey endpoint. The `SERVICE` command than executes another query fragment on a remote endpoint, in this case the Open Data Communities endpoint."
567 ]
568 },
569 {
570 "cell_type": "code",
571 "collapsed": false,
572 "input": [
573 "q='''\n",
574 "SELECT ?districtname ?councilwebsite ?imdrank ?authority ?authorityname \n",
575 "WHERE {\n",
576 "\n",
577 " ?iw rdfs:label \"Isle of Wight\" ;\n",
578 " rdf:type osadmingeo:UnitaryAuthority .\n",
579 "\n",
580 " ?district ossr:within ?iw .\n",
581 " ?district rdfs:label ?districtname.\n",
582 " \n",
583 " SERVICE <http://opendatacommunities.org/sparql> {\n",
584 "\n",
585 " ?s <http://purl.org/linked-data/sdmx/2009/dimension#refArea> ?iw .\n",
586 " ?s <http://opendatacommunities.org/def/IMD#IMD-rank> ?imdrank . \n",
587 "\n",
588 "\n",
589 " ?authority <http://opendatacommunities.org/def/local-government/governs> ?iw .\n",
590 " ?authority <http://xmlns.com/foaf/0.1/page> ?councilwebsite .\n",
591 " ?authority rdfs:label ?authorityname.\n",
592 " \n",
593 " }\n",
594 "}\n",
595 "'''\n",
596 "\n",
597 "printRunQuery(endpoint_os,prefix,q,5)"
598 ],
599 "language": "python",
600 "metadata": {},
601 "outputs": []
602 },
603 {
604 "cell_type": "markdown",
605 "metadata": {},
606 "source": [
607 "As well as using OS administrative codes, the districts also have Office of National Statistics (ONS) identifiers. For example:"
608 ]
609 },
610 {
611 "cell_type": "code",
612 "collapsed": false,
613 "input": [
614 "q='''\n",
615 "SELECT ?districtname ?onsdist \n",
616 "WHERE {\n",
617 "\n",
618 " ?iw rdfs:label \"Isle of Wight\" ;\n",
619 " rdf:type osadmingeo:UnitaryAuthority .\n",
620 "\n",
621 " ?district ossr:within ?iw .\n",
622 " ?district rdfs:label ?districtname.\n",
623 " ?district <http://www.w3.org/2002/07/owl#sameAs> ?onsdist .\n",
624 "}\n",
625 "'''\n",
626 "printRunQuery(endpoint_os,prefix,q,5)"
627 ],
628 "language": "python",
629 "metadata": {},
630 "outputs": []
631 },
632 {
633 "cell_type": "markdown",
634 "metadata": {},
635 "source": [
636 "Let's see what we can find out about a district from the ONS open Linked Data endpoint."
637 ]
638 },
639 {
640 "cell_type": "code",
641 "collapsed": false,
642 "input": [
643 "endpoint_ons='http://statistics.data.gov.uk/sparql'\n",
644 "\n",
645 "q='''\n",
646 "SELECT ?districtname ?x ?y\n",
647 "WHERE {\n",
648 " \n",
649 " <http://statistics.data.gov.uk/id/statistical-geography/E04001302> ?x ?y ;\n",
650 " rdfs:label ?districtname\n",
651 "}\n",
652 "'''\n",
653 "\n",
654 "runQuery(endpoint_ons,prefix,q)"
655 ],
656 "language": "python",
657 "metadata": {},
658 "outputs": []
659 },
660 {
661 "cell_type": "markdown",
662 "metadata": {},
663 "source": [
664 "We can now add this further element to our compund, federated query, using *another* `SERVICE` command to run this part of the query via the ONS endpoint."
665 ]
666 },
667 {
668 "cell_type": "code",
669 "collapsed": false,
670 "input": [
671 "q='''\n",
672 "SELECT ?districtname ?councilwebsite ?imdrank ?authority ?authorityname ?changeorder ?onsdist ?onscode\n",
673 "WHERE {\n",
674 "\n",
675 " ?iw rdfs:label \"Isle of Wight\" ;\n",
676 " rdf:type osadmingeo:UnitaryAuthority .\n",
677 "\n",
678 " ?district ossr:within ?iw .\n",
679 " ?district rdfs:label ?districtname.\n",
680 " \n",
681 " SERVICE <http://opendatacommunities.org/sparql> {\n",
682 "\n",
683 " ?s <http://purl.org/linked-data/sdmx/2009/dimension#refArea> ?iw .\n",
684 " ?s <http://opendatacommunities.org/def/IMD#IMD-rank> ?imdrank . \n",
685 "\n",
686 "\n",
687 " ?authority <http://opendatacommunities.org/def/local-government/governs> ?iw .\n",
688 " ?authority <http://xmlns.com/foaf/0.1/page> ?councilwebsite .\n",
689 " ?authority rdfs:label ?authorityname.\n",
690 " \n",
691 " }\n",
692 " \n",
693 " ?district <http://www.w3.org/2002/07/owl#sameAs> ?onsdist\n",
694 "\n",
695 " SERVICE <http://statistics.data.gov.uk/sparql> {\n",
696 " ?onsdist <http://statistics.data.gov.uk/def/boundary-change/originatingChangeOrder> ?changeorder .\n",
697 " ?onsdist <http://statistics.data.gov.uk/def/boundary-change/operativedate> ?opdate ;\n",
698 " <http://www.w3.org/2004/02/skos/core#notation> ?onscode.\n",
699 " FILTER (isURI(?changeorder))\n",
700 " }\n",
701 " \n",
702 "}\n",
703 "'''\n",
704 "\n",
705 "printRunQuery(endpoint_os,prefix,q,5)"
706 ],
707 "language": "python",
708 "metadata": {},
709 "outputs": []
710 },
711 {
712 "cell_type": "markdown",
713 "metadata": {},
714 "source": [
715 "For me, the first time I saw a demonstration of the `SERVICE` invocation, the promise of Linked Data started to make more sense..."
716 ]
717 }
718 ],
719 "metadata": {}
720 }
721 ]
722 }