{ "cells": [ { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "5015a0106025436eb233cd60fca8acae", "version_major": 2, "version_minor": 0 }, "text/plain": [ "VBox(children=(VBox(children=(HTML(value='

Wikidata Graph Browser

', placeholder=''), HBox(children=(VB…" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Creating a knowledge graph browser for the Met from Wikidata:\n", "# By artist, department, type of object, image\n", "# Complex: depicted content (Met tags, and non Met tags), by number of Wikimedia links/articles\n", "# Specific: highlight, TOAH, all\n", "# Near future: by era (start, stop time), made from material (P186), fabrication method (P2079)\n", "# For the future - genre, movement, copyright status\n", "\n", "import ipywidgets as widgets\n", "from ipywidgets import interact, interactive, fixed, interact_manual\n", "from ipywidgets import HBox, VBox, Label\n", "\n", "import requests\n", "import numpy as np\n", "import json\n", "import pandas as pd\n", "import urllib.parse\n", "\n", "# Define API MediaWiki endpoint\n", "wikidata_api_url = u'https://query.wikidata.org/bigdata/namespace/wdq/sparql'\n", "\n", "## Grab all items in Wikidata with Met Object ID (P3634)\n", "# Rewrite URL if needed: BIND ((CONCAT (\"[http://www.metmuseum.org/art/collection/search/\", ?id, \" \", ?inv, \"]\")) as ?meturl) . \n", "\n", "pop_met_artists_query = u'''\n", "# Most popular artists in Wikidata that have Met works\n", "SELECT DISTINCT ?creator ?creatorLabel ?linkcount WHERE { \n", " ?item wdt:P3634 ?metid . \n", " ?item wdt:P170 ?creator . \n", " ?creator wikibase:sitelinks ?linkcount . \n", " FILTER (?linkcount > 0) .\n", " SERVICE wikibase:label { bd:serviceParam wikibase:language \"[AUTO_LANGUAGE],en\". }\n", "} GROUP BY ?creator ?creatorLabel ?linkcount ORDER BY DESC(?linkcount)\n", "'''\n", "\n", "# Replace %s below with a VALUES statement like\n", "# VALUES ?creator { wd:Q41264 }\n", "\n", "creator_depictions_query_template = u'''\n", "# Artists and their works depictions\n", "#defaultView:Graph\n", "SELECT ?item1 ?image1 ?item1Label ?item2 ?image2 ?item2Label ?size ?rgb \n", "WHERE \n", "{\n", " %s\n", " %s\n", " { # Get works and instances\n", " VALUES ?rgb { \"FFBD33\" }\n", " VALUES ?size { 2 }\n", " ?item1 wdt:P170 ?creator .\n", " %s\n", " ?item1 wdt:P31 ?item2 .\n", " OPTIONAL { ?item1 wdt:P18 ?image1. }\n", " } \n", " UNION\n", " { # Depictions\n", " VALUES ?rgb { \"fff033\" }\n", " VALUES ?size { 1 }\n", " ?item1 wdt:P170 ?creator .\n", " %s\n", " ?item1 wdt:P180 ?item2 .\n", " OPTIONAL { ?item1 wdt:P18 ?image1. }\n", " }\n", " SERVICE wikibase:label { bd:serviceParam wikibase:language \"[AUTO_LANGUAGE],en\". }\n", "}\n", "'''\n", "\n", "def sparql_qidlist_to_values_string(inlist: list) -> str:\n", " '''\n", " Converts a list of Q numbers to a VALUES string for SPARQL\n", "\n", " Input: ['wd:Q123', 'wd:Q456', 'wd:Q789']\n", " Output: '{wd:Q123 wd:Q456 wd:Q789}'\n", " '''\n", " try:\n", " values_string ='{' + ' '.join(x for x in inlist) + '}'\n", " return values_string\n", " except:\n", " print ('Error: making values string')\n", " return None\n", "\n", "def create_widget_tuple_list (labels: list, values: list) -> list:\n", " '''\n", " Converts two lists into the list of tuples needed for Jupyter Widgets\n", " \n", " Input: \n", " labels: ['Label1', 'Label2'...]\n", " values: ['Value1', 'Value2'...]\n", " \n", " Output:\n", " [('Label1', 'Value1'),...]\n", " '''\n", " merged = tuple(zip(labels, values))\n", " return merged\n", "\n", "## START EXECUTION\n", "\n", "creator_values = ''\n", "institution_values = ''\n", "institution_statement = ''\n", "\n", "query_dict = {\n", " 'creators': [],\n", " 'institutions': []\n", "}\n", "\n", "try:\n", " # Wikidata SPARQL query to get list of artists with some type of work at The Met\n", " # If you want caching of requests, uncomment next two lines\n", " # import requests_cache\n", " # requests_cache.install_cache('wikidata_sparql_cache', allowable_methods=('GET', 'POST'))\n", " data = requests.post(wikidata_api_url, data={'query': pop_met_artists_query, 'format': 'json'}).json()\n", "except NameError:\n", " print ('jsondecode problem.')\n", " print (data.content)\n", " raise\n", "\n", "# Interpret result from SPARQL query\n", "resultarray = []\n", "for item in data['results']['bindings']:\n", " resultarray.append({\n", " 'qid': str(item['creator']['value'].replace('http://www.wikidata.org/entity/','')),\n", " 'label': str(item['creatorLabel']['value']),\n", " 'linkcount': int(item['linkcount']['value'])\n", " })\n", "\n", "df = pd.DataFrame(resultarray)\n", "\n", "# Make new dataframe to prep the selection box text\n", "new_df = pd.DataFrame()\n", "\n", "# Add new column turning Q123 to wd:Q123\n", "new_df['wdqid'] = df.apply (lambda row: 'wd:'+row['qid'], axis=1)\n", "# Add linkcount to label so it displays like \"Henri Matisse (42)\"\n", "new_df['label'] = df.apply (lambda row: row['label']+' ('+str(row['linkcount'])+')', axis=1)\n", "\n", "# Create a list of tuples to be used by SelectMultiple list\n", "# [(\"Henri Matisse (42)\", )]\n", "creator_options = []\n", "tuple_list = create_widget_tuple_list(new_df['label'].to_list(), new_df['wdqid'].to_list())\n", "creator_options.extend(tuple_list)\n", "\n", "# iframecode = ''\n", "iframecode_blank = ''\n", "\n", "institution_options = [\n", " ('All institutions', 'ALL'),\n", " ('Met Museum', 'wd:Q160236'),\n", " ('National Gallery of Art (US)', 'wd:Q214867'),\n", " ('Smithsonian American Art Museum', 'wd:Q1192305'),\n", " ('National Portrait Gallery (US)','wd:Q1967614'),\n", " ('Cooper Hewitt','wd:Q1129820'),\n", " ('Hirshhorn Museum and Sculpture Garden','wd:Q1620553'),\n", " ('Freer Sackler Gallery','wd:Q105749808'),\n", " ('National Museum of Arfican Art','wd:Q46812'),\n", " ('Cleveland Museum of Art','wd:Q657415'),\n", " ('Yale University Gallery of Art', 'wd:Q1568434'),\n", " ('Rijksmuseum', 'wd:Q190804'),\n", "]\n", "\n", "textheader = widgets.HTML(\n", " value=\"

Wikidata Graph Browser

\",\n", " placeholder='',\n", " description='',\n", ")\n", "\n", "selector = widgets.SelectMultiple(\n", " options=creator_options,\n", " value=[],\n", " rows=10,\n", " description='',\n", " disabled=False\n", ")\n", "\n", "institution_selector = widgets.SelectMultiple(\n", " options=institution_options,\n", " value=[],\n", " rows=10,\n", " description='',\n", " disabled=False\n", ")\n", "\n", "graphoutput = widgets.HTML(\n", " value=iframecode_blank,\n", " placeholder='

Waiting for input

',\n", " description=''\n", ")\n", "\n", "def handle_creators(incoming):\n", " # Record creators into our dict\n", " query_dict['creators'] = incoming['new']\n", " draw_kg()\n", " \n", "def handle_institutions(incoming):\n", " # Record institutions into our dict\n", " if 'ALL' in incoming['new']:\n", " query_dict['institutions'] = []\n", " else:\n", " query_dict['institutions'] = incoming['new']\n", " draw_kg()\n", " \n", "def draw_kg():\n", " creator_values = ''\n", " institution_values = ''\n", " institution_statement = ''\n", " \n", " if (query_dict['creators']):\n", " creator_values = 'VALUES ?creator ' + sparql_qidlist_to_values_string(list(query_dict['creators']))\n", " if (query_dict['institutions']):\n", " institution_values = 'VALUES ?institution ' + sparql_qidlist_to_values_string(list(query_dict['institutions']))\n", " institution_statement = '?item1 wdt:P195 ?institution .'\n", "\n", " # Create the SPARQL query\n", " # graphurl = creator_depictions_query_template_url.format(values_string)\n", " \n", " # TODO - eventually want to support as many UNION subqueries as needed\n", " query = creator_depictions_query_template % \\\n", " (creator_values, institution_values, institution_statement, institution_statement)\n", "\n", " # Create Wikidata query URL\n", " graphurl = 'https://query.wikidata.org/embed.html#' + urllib.parse.quote(query)\n", "\n", " # Poke iframe\n", " iframecode = ''\n", " graphoutput.value=iframecode\n", " \n", "a_selector = VBox([Label('Artists'),selector])\n", "i_selector = VBox([Label('Institutions'),institution_selector])\n", "\n", "topbox = HBox([a_selector, i_selector])\n", "headerbox = VBox([textheader,topbox])\n", "bottombox = HBox([graphoutput])\n", "\n", "bigbox = VBox([headerbox,bottombox])\n", "\n", "display(bigbox)\n", "\n", "selector.observe(handle_creators, names='value')\n", "institution_selector.observe(handle_institutions, names='value')" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.5" } }, "nbformat": 4, "nbformat_minor": 4 }