From dd4b02c5b5c11c2aa955e511d01b22723faffb4d Mon Sep 17 00:00:00 2001 From: Andrew Davison Date: Fri, 7 Mar 2025 17:05:01 +0100 Subject: [PATCH 1/4] first draft --- examples/notebooks/advanced_tutorial.ipynb | 1074 ++++++++++++++++++++ examples/notebooks/images/get-token.png | Bin 0 -> 25256 bytes 2 files changed, 1074 insertions(+) create mode 100644 examples/notebooks/advanced_tutorial.ipynb create mode 100644 examples/notebooks/images/get-token.png diff --git a/examples/notebooks/advanced_tutorial.ipynb b/examples/notebooks/advanced_tutorial.ipynb new file mode 100644 index 00000000..345ad435 --- /dev/null +++ b/examples/notebooks/advanced_tutorial.ipynb @@ -0,0 +1,1074 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Working with data from the EBRAINS Knowledge Graph: an advanced tutorial\n", + "\n", + "This notebook contains a tutorial for working with the [EBRAINS Knowledge Graph](https://docs.kg.ebrains.eu),\n", + "which is the metadata management system of the [EBRAINS Research Infrastructure](https://www.ebrains.eu).\n", + "\n", + "There are many different software tools for working with the Knowledge Graph (KG).\n", + "In this tutorial, we will demonstrate how to work with the [fairgraph](https://fairgraph.readthedocs.io) library for Python,\n", + "which is based on \n", + "- the [ebrains-kg-core](https://pypi.org/project/ebrains-kg-core/) Python library\n", + "- the [openMINDS](https://openminds-documentation.readthedocs.io/) metadata schemas \n", + "\n", + "A tutorial on working with the KG in Javascript is available [here](https://github.com/apdavison/ebrains-kg-tutorial-javascript)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1. Getting started\n", + "\n", + "If you are running this notebook in the [EBRAINS Lab](https://lab.ebrains.eu/) using the latest kernel from the EBRAINS Software Distribution, fairgraph is already installed.\n", + "\n", + "If you are running this elsewhere, install fairgraph using:\n", + "\n", + "```\n", + "pip install fairgraph\n", + "```\n", + "\n", + "### Authentication / authorization\n", + "\n", + "Using the [KG API](https://core.kg.ebrains.eu/swagger-ui.html) is restricted to EBRAINS users who have agreed to the [Terms of Use](https://docs.kg.ebrains.eu/search-terms-of-use.html?v=2.2) (please read them now!) \n", + "When making a request to the API, the user must provide an authorization token.\n", + "\n", + "#### Option A. If you are running this notebook in the EBRAINS Lab\n", + "\n", + "In this case, fairgraph knows how to obtain a token from your environment (since you've already logged into the Lab using your EBRAINS account). \n", + "You can therefore go ahead and create a client for communicating with the KG:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from fairgraph import KGClient\n", + "\n", + "kg_client = KGClient(host=\"core.kg.ebrains.eu\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Option B. If you are running the notebook locally on your own machine\n", + "\n", + "You will need to obtain a token from somewhere else.\n", + "Here are three possibilities:\n", + "\n", + "1. Log-in to the [KG Editor](https://editor.kg.ebrains.eu) app, then click on the Account icon (top right), click on \"Copy token to clipboard\", then paste the token into the code cell below as the variable `auth_token`.\n", + "Note that this token has quite a short validity, only about 10 minutes, so you will need to repeat this process, and re-execute the cell from time to time as you work through the tutorial.\n", + "\n", + "![Screenshot of \"Copy token to clipboard\" button in KG Editor app](images/get-token.png)\n", + "\n", + "2. In a Jupyter notebook in the [EBRAINS Lab](https://lab.ebrains.eu/), run the following code:\n", + "\n", + "```\n", + "from clb_nb_utils.oauth import get_token\n", + "get_token()\n", + "```\n", + "\n", + "and then copy/paste the token as above. Tokens obtained from the Lab are valid for longer." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "from fairgraph import KGClient\n", + "\n", + "auth_token = \"eyJh...\"\n", + "kg_client = KGClient(token=auth_token, host=\"core.kg.ebrains.eu\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "3. Create a KG client without a token, then run any code that needs to access the KG. This will give you a link that you can click to log-in via a web browser, you can then return to this notebook." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "************************************************************************\n", + "To continue, you need to authenticate. To do so, please visit https://iam.ebrains.eu/auth/realms/hbp/device?user_code=VKPH-BWRC\n", + "*************************************************************************\n", + "You are successfully authenticated! Thank you very much!\n", + "*************************************************************************\n" + ] + }, + { + "data": { + "text/plain": [ + "User(alternate_name='adavisontesting', name='Testing Davison', email=None, given_name='Testing', family_name='Davison', identifiers=['18e48ea2-fccb-455b-b42c-df21f4820676'])" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from fairgraph import KGClient\n", + "\n", + "kg_client = KGClient(host=\"core.kg.ebrains.eu\")\n", + "kg_client.user_info()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2. Key concepts\n", + "\n", + "The core of the EBRAINS Knowledge Graph is a [graph database](https://en.wikipedia.org/wiki/Graph_database) containing detailed metadata about neuroscience datasets, models, software, and other research products.\n", + "The actual data/code of the datasets, models, etc. are stored outside the KG, but the KG stores links to the data/code locations.\n", + "The EBRAINS KG is implemented using an open-source software system called MarmotGraph (developed in the Human Brain Project and EBRAINS projects).\n", + "\n", + "The primary user interface of the KG is a web API, whose end-points are [documented interactively here](https://core.kg.ebrains.eu/swagger-ui/index.html).\n", + "In this tutorial we will use the fairgraph Python library to send requests to this API and handle the responses,\n", + "but the API can be accessed using many different programming languages,\n", + "and EBRAINS also provides libraries for [Java](https://central.sonatype.com/artifact/eu.ebrains.kg/kg-core-sdk[) and [Javascript/Typescript](https://www.npmjs.com/package/@ebrains/kg-core) to simplify working with the API.\n", + "\n", + "The primary document type used by the KG API is [JSON-LD](https://json-ld.org).\n", + "This builds on the widely-used JSON format by adding features to support linked data,\n", + "i.e., data that follows a graph structure.\n", + "\n", + "While JSON-LD specifies the form of the data/metadata, it doesn't specify the content.\n", + "[openMINDS](https://openminds-documentation.readthedocs.io/) is a project to develop metadata schemas and libraries for neuroscience and related fields.\n", + "It specifies what types of object we can store metadata about, and what properties each type should have, \n", + "e.g., a [`Person`](https://openminds-documentation.readthedocs.io/en/latest/schema_specifications/core/actors/person.html) should have a `givenName` and a `familyName`.\n", + "All metadata in the KG follows the openMINDS schemas.\n", + "\n", + "fairgraph provides a Python class for each openMINDS type, and lets you create or access KG nodes as Python objects. \n", + "Behind the scenes, fairgraph takes care of:\n", + "- converting the Python objects into/from JSON-LD documents\n", + "- communicating with the KG.\n", + "\n", + "fairgraph also provides a simplified query interface, while still allowing low-level access to the underlying query language if necessary. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 3. Retrieving a metadata node based on its ID\n", + "\n", + "As noted above, each node in the KG can be represented by a Python object. \n", + "If you know the hexadecimal identifier of the node and its type, the object can be retrieved using the `from_id()` method of the appropriate class. Here, we retrieve a specific dataset:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "import fairgraph.openminds.core as omcore\n", + "omcore.set_error_handling(None)\n", + "\n", + "dataset_id = \"bd5f91ff-e829-4b85-92eb-fc56991541f1\"\n", + "dataset_version = omcore.DatasetVersion.from_id(dataset_id, kg_client)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "id https://kg.ebrains.eu/api/instances/bd5f91ff-e829-4b85-92eb-fc56991541f1\n", + "space dataset\n", + "type https://openminds.ebrains.eu/core/DatasetVersion\n", + "accessibility KGProxy([], 'https://kg.ebrains.eu/api/instances/b2ff7a47-b349-48d7-8ce4-cf51868675f1')\n", + "data_types KGProxy([], 'https://kg.ebrains.eu/api/instances/f468ee45-37a6-4e71-8b70-0cbe66d367db')\n", + "description\n", + "digital_identifier KGProxy((, ), 'https://kg.ebrains.eu/api/instances/df93b012-3bb6-4565-bce0-3bd2d3aed63b')\n", + "ethics_assessment KGProxy([], 'https://kg.ebrains.eu/api/instances/a217a2f8-dcb8-4ca9-9923-517af2aebc5b')\n", + "experimental_approaches KGProxy([], 'https://kg.ebrains.eu/api/instances/411b233f-a054-4719-bbd5-e86f1302bc46')\n", + "full_documentation KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/a245c132-30ae-4ba8-a1d1-3a0f44d056aa')\n", + "full_name Excitability profile of CA1 pyramidal neurons in APPPS1 Alzheimer disease mice and control littermates\n", + "keywords KGProxy((, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ), 'https://kg.ebrains.eu/api/instances/62034f18-20fc-46d6-8f0a-277a60cb02e9')\n", + "license KGProxy((, ), 'https://kg.ebrains.eu/api/instances/64c1704b-db12-4b29-9541-b9143d081044')\n", + "preparation_designs KGProxy([], 'https://kg.ebrains.eu/api/instances/9f3abe1b-af7c-446d-b637-6a4f19ab7939')\n", + "related_publications KGProxy((, , , , , , ), 'https://kg.ebrains.eu/api/instances/5f477d01-82c1-4c6a-891c-e902a8c2241c')\n", + "release_date 2020-04-21 00:00:00\n", + "repository KGProxy([], 'https://kg.ebrains.eu/api/instances/1a319b34-4903-4663-8882-b3fe5703cbcb')\n", + "short_name Excitability profile of CA1 pyramidal neurons in APPPS1 Alzheimer disease mice and control littermates\n", + "studied_specimens [KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/d04d00c7-b770-4744-a5f4-2ebba26ba1d1'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/31f9157a-616b-43b4-8a04-8fd8c15a7524'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/853682c7-c317-4091-b3eb-f94ce41a70a5'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/8300e9c8-ddce-4b72-811a-96f1f7dc0d4b'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/eca80107-1908-43cc-8897-5074f50dbe22'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/d74401a9-24a0-4373-b2b7-60b084b66820'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/ed399971-9797-4fc3-8796-094ebdf2432e'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/54e0bc42-9ddb-4503-98be-c1f3c03afea1'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/d5ea0238-23e7-463e-96f3-4da7c06832e4'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/6c00b1a4-d10f-408d-ac00-b07464a73321'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/d352f598-0118-4908-ad01-a2c4b5e06028'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/a9f319fb-9d41-4500-8eb4-08601053f850'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/d2b62075-768e-48f4-ba00-4e8cbbb543e9'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/9a83c827-3638-4bc1-92c2-10749d30500b'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/dd214b93-8c20-4c70-ac90-584d7f66f344'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/d967e53d-277d-4a2f-9090-8c50aaf0a008'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/0cad429a-f738-4d1d-9e56-c907b431a8c9'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/5f40bc15-d813-4560-92a8-a533109777fb'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/0be6ad46-c50d-4a50-8e2b-0eeea708019e'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/a7197a22-0b1d-4069-89b2-17aa92910c00'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/524e0e51-6a9e-410b-8d23-79ce1b7d97b7'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/12f80b23-6bec-4b0a-90c7-b717310fb707'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/ae759252-c8e4-4c60-aa4c-308922613371'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/e168745f-d7cf-4977-87d0-4dbeba51a9f2'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/d44005cd-7d11-471f-9e34-4400463449ee'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/7831a6bc-d329-4ff1-a5cf-270c100f9f8a')]\n", + "study_targets KGProxy((, , , , , , , , , , , , , , , , , , , , , , , , , , , ), 'https://kg.ebrains.eu/api/instances/161baa02-4e08-4cf2-a641-81cf323cc15d')\n", + "techniques [KGProxy((, , , , , ), 'https://kg.ebrains.eu/api/instances/dc0bbc6c-99f5-4d3b-9c5e-e1bb7d59aa63'), KGProxy((, , , , , ), 'https://kg.ebrains.eu/api/instances/ffc1c922-5ba9-4f03-b9be-05eb6fd0f294')]\n", + "version_identifier v1\n", + "version_innovation This is the first version of this research product.\n" + ] + } + ], + "source": [ + "dataset_version.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can view the same dataset in the KG Search UI by clicking on this link: https://search.kg.ebrains.eu/instances/bd5f91ff-e829-4b85-92eb-fc56991541f1.\n", + "\n", + "You will notice in the output from `.show()` that:\n", + "\n", + "1. for many of the properties, the value is a `KGProxy()` object, or a list of such objects. These represent links to other nodes in the graph. To see what these nodes contain, we need to follow them.\n", + "2. the \"description\" property is empty, even though the dataset card in the Search UI contains a description. We'll come back to this in Section 5, below." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 4. Following links in the graph\n", + "\n", + "To follow links in the graph, we use the `resolve()` method:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "id https://kg.ebrains.eu/api/instances/b2ff7a47-b349-48d7-8ce4-cf51868675f1\n", + "space controlled\n", + "type https://openminds.ebrains.eu/controlledTerms/ProductAccessibility\n", + "definition With 'free access' selected, data and metadata are both released and become immediately available without any access restrictions.\n", + "name free access\n" + ] + } + ], + "source": [ + "accessibility = dataset_version.accessibility.resolve(kg_client)\n", + "accessibility.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "id https://kg.ebrains.eu/api/instances/df93b012-3bb6-4565-bce0-3bd2d3aed63b\n", + "space dataset\n", + "type https://openminds.ebrains.eu/core/DOI\n", + "identifier https://doi.org/10.25493/YJFW-HPY\n" + ] + } + ], + "source": [ + "doi = dataset_version.digital_identifier.resolve(kg_client)\n", + "doi.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "current clamp\n", + "whole cell patch clamp\n" + ] + } + ], + "source": [ + "techniques = [tech.resolve(kg_client) for tech in dataset_version.techniques]\n", + "for tech in techniques:\n", + " print(tech.name)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Reverse links\n", + "\n", + "We can also follow *reverse* links, i.e. where the property of another object points *to* the dataset version.\n", + "Reverse properties are not shown by default by `obj.show()`, but you can see them by passing the `include_empty_properties` option:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "id https://kg.ebrains.eu/api/instances/bd5f91ff-e829-4b85-92eb-fc56991541f1\n", + "space dataset\n", + "type https://openminds.ebrains.eu/core/DatasetVersion\n", + "accessibility KGProxy([], 'https://kg.ebrains.eu/api/instances/b2ff7a47-b349-48d7-8ce4-cf51868675f1')\n", + "authors None\n", + "behavioral_protocols None\n", + "copyright None\n", + "custodians None\n", + "data_types KGProxy([], 'https://kg.ebrains.eu/api/instances/f468ee45-37a6-4e71-8b70-0cbe66d367db')\n", + "description\n", + "digital_identifier KGProxy((, ), 'https://kg.ebrains.eu/api/instances/df93b012-3bb6-4565-bce0-3bd2d3aed63b')\n", + "ethics_assessment KGProxy([], 'https://kg.ebrains.eu/api/instances/a217a2f8-dcb8-4ca9-9923-517af2aebc5b')\n", + "experimental_approaches KGProxy([], 'https://kg.ebrains.eu/api/instances/411b233f-a054-4719-bbd5-e86f1302bc46')\n", + "full_documentation KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/a245c132-30ae-4ba8-a1d1-3a0f44d056aa')\n", + "full_name Excitability profile of CA1 pyramidal neurons in APPPS1 Alzheimer disease mice and control littermates\n", + "funding None\n", + "homepage None\n", + "how_to_cite None\n", + "input_data None\n", + "is_alternative_version_of None\n", + "is_new_version_of None\n", + "keywords KGProxy((, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ), 'https://kg.ebrains.eu/api/instances/62034f18-20fc-46d6-8f0a-277a60cb02e9')\n", + "license KGProxy((, ), 'https://kg.ebrains.eu/api/instances/64c1704b-db12-4b29-9541-b9143d081044')\n", + "other_contributions None\n", + "preparation_designs KGProxy([], 'https://kg.ebrains.eu/api/instances/9f3abe1b-af7c-446d-b637-6a4f19ab7939')\n", + "protocols None\n", + "related_publications KGProxy((, , , , , , ), 'https://kg.ebrains.eu/api/instances/5f477d01-82c1-4c6a-891c-e902a8c2241c')\n", + "release_date 2020-04-21 00:00:00\n", + "repository KGProxy([], 'https://kg.ebrains.eu/api/instances/1a319b34-4903-4663-8882-b3fe5703cbcb')\n", + "short_name Excitability profile of CA1 pyramidal neurons in APPPS1 Alzheimer disease mice and control littermates\n", + "studied_specimens [KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/d04d00c7-b770-4744-a5f4-2ebba26ba1d1'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/31f9157a-616b-43b4-8a04-8fd8c15a7524'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/853682c7-c317-4091-b3eb-f94ce41a70a5'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/8300e9c8-ddce-4b72-811a-96f1f7dc0d4b'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/eca80107-1908-43cc-8897-5074f50dbe22'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/d74401a9-24a0-4373-b2b7-60b084b66820'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/ed399971-9797-4fc3-8796-094ebdf2432e'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/54e0bc42-9ddb-4503-98be-c1f3c03afea1'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/d5ea0238-23e7-463e-96f3-4da7c06832e4'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/6c00b1a4-d10f-408d-ac00-b07464a73321'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/d352f598-0118-4908-ad01-a2c4b5e06028'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/a9f319fb-9d41-4500-8eb4-08601053f850'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/d2b62075-768e-48f4-ba00-4e8cbbb543e9'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/9a83c827-3638-4bc1-92c2-10749d30500b'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/dd214b93-8c20-4c70-ac90-584d7f66f344'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/d967e53d-277d-4a2f-9090-8c50aaf0a008'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/0cad429a-f738-4d1d-9e56-c907b431a8c9'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/5f40bc15-d813-4560-92a8-a533109777fb'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/0be6ad46-c50d-4a50-8e2b-0eeea708019e'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/a7197a22-0b1d-4069-89b2-17aa92910c00'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/524e0e51-6a9e-410b-8d23-79ce1b7d97b7'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/12f80b23-6bec-4b0a-90c7-b717310fb707'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/ae759252-c8e4-4c60-aa4c-308922613371'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/e168745f-d7cf-4977-87d0-4dbeba51a9f2'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/d44005cd-7d11-471f-9e34-4400463449ee'), KGProxy((, , , ), 'https://kg.ebrains.eu/api/instances/7831a6bc-d329-4ff1-a5cf-270c100f9f8a')]\n", + "study_targets KGProxy((, , , , , , , , , , , , , , , , , , , , , , , , , , , ), 'https://kg.ebrains.eu/api/instances/161baa02-4e08-4cf2-a641-81cf323cc15d')\n", + "support_channels None\n", + "techniques [KGProxy((, , , , , ), 'https://kg.ebrains.eu/api/instances/dc0bbc6c-99f5-4d3b-9c5e-e1bb7d59aa63'), KGProxy((, , , , , ), 'https://kg.ebrains.eu/api/instances/ffc1c922-5ba9-4f03-b9be-05eb6fd0f294')]\n", + "version_identifier v1\n", + "version_innovation This is the first version of this research product.\n", + "comments KGQuery([], {'about': 'https://kg.ebrains.eu/api/instances/bd5f91ff-e829-4b85-92eb-fc56991541f1'})\n", + "has_parts KGQuery([, , , , , , , ], {'is_part_of': 'https://kg.ebrains.eu/api/instances/bd5f91ff-e829-4b85-92eb-fc56991541f1'})\n", + "is_input_to KGQuery([], {'inputs': 'https://kg.ebrains.eu/api/instances/bd5f91ff-e829-4b85-92eb-fc56991541f1'})\n", + "is_old_version_of KGQuery([], {'is_new_version_of': 'https://kg.ebrains.eu/api/instances/bd5f91ff-e829-4b85-92eb-fc56991541f1'})\n", + "is_part_of KGQuery([, ], {'has_parts': 'https://kg.ebrains.eu/api/instances/bd5f91ff-e829-4b85-92eb-fc56991541f1'})\n", + "is_version_of KGQuery([], {'has_versions': 'https://kg.ebrains.eu/api/instances/bd5f91ff-e829-4b85-92eb-fc56991541f1'})\n", + "learning_resources KGQuery([], {'about': 'https://kg.ebrains.eu/api/instances/bd5f91ff-e829-4b85-92eb-fc56991541f1'})\n", + "publication KGQuery([], {'about': 'https://kg.ebrains.eu/api/instances/bd5f91ff-e829-4b85-92eb-fc56991541f1'})\n" + ] + } + ], + "source": [ + "dataset_version.show(include_empty_properties=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Reverse properties are represented by a `KGQuery` object. These can also be resolved:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "id https://kg.ebrains.eu/api/instances/65b1b9a3-af50-4c9c-a4e6-7556bc700da0\n", + "space dataset\n", + "type https://openminds.ebrains.eu/core/Dataset\n", + "authors [KGProxy([], 'https://kg.ebrains.eu/api/instances/5dff4ef9-bd56-4aee-979a-6ed15f65d235'), KGProxy([], 'https://kg.ebrains.eu/api/instances/2843990a-69dd-468b-a1d3-ff9589b485ae')]\n", + "custodians KGProxy([], 'https://kg.ebrains.eu/api/instances/2843990a-69dd-468b-a1d3-ff9589b485ae')\n", + "description In this study we analyzed the intrinsic electrophysiological properties of CA1 excitatory hippocampal neurons in a mouse model of Alzheimer’s Disease (AD) at two age points: a presymptomatic age (3-4 months) and a symptomatic age: (9-10 months). At this latter age, this APPPS1 model harbors amyloid plaques and hippocampus-dependent cognitive alterations. Little is known about the excitability alterations in the hippocampus that correlate to these cognitive deficits. Using patch clamp electrophysiology we recorded CA1 pyramidal neurons from control littermates (Wild types) and APPPS1 slices of hippocampus at these two age points.\n", + "full_name Excitability profile of CA1 pyramidal neurons in APPPS1 Alzheimer disease mice and control littermates\n", + "has_versions KGProxy([], 'https://kg.ebrains.eu/api/instances/bd5f91ff-e829-4b85-92eb-fc56991541f1')\n", + "short_name Excitability profile of CA1 pyramidal neurons in APPPS1 Alzheimer disease mice and control littermates\n" + ] + } + ], + "source": [ + "dataset = dataset_version.is_version_of.resolve(kg_client)\n", + "dataset.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Following multiple links at once\n", + "\n", + "Following links one at a time can be rather slow, as it requires many network requests.\n", + "\n", + "If you know in advance the paths you wish to follow through the graph, you can specify them in the `follow_links` argument to the `resolve()` method.\n", + "For example:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "# Before\n", + "Digital identifier: \n", + "Ethics assessment: \n", + "Study targets: \n", + "Is version of: \n", + "\n", + "# After\n", + "Digital identifier: \n", + "Ethics assessment: \n", + "Study targets: \n", + "Is version of: \n", + "Authors:\n", + " Ana Rita Salgueiro-Pereira\n", + " Hélène Marie\n" + ] + } + ], + "source": [ + "print(\"# Before\")\n", + "print(f\"Digital identifier: {type(dataset_version.digital_identifier)}\")\n", + "print(f\"Ethics assessment: {type(dataset_version.ethics_assessment)}\")\n", + "print(f\"Study targets: {type(dataset_version.study_targets)}\")\n", + "print(f\"Is version of: {type(dataset_version.is_version_of)}\")\n", + "\n", + "print(\"\\n# After\")\n", + "dataset_version.resolve(\n", + " kg_client,\n", + " follow_links={\n", + " \"digital_identifier\": {},\n", + " \"ethics_assessment\": {},\n", + " \"study_targets\": {},\n", + " \"is_version_of\": {\n", + " \"authors\": {}\n", + " }\n", + " })\n", + "print(f\"Digital identifier: {type(dataset_version.digital_identifier)}\")\n", + "print(f\"Ethics assessment: {type(dataset_version.ethics_assessment)}\")\n", + "print(f\"Study targets: {type(dataset_version.study_targets)}\")\n", + "print(f\"Is version of: {type(dataset_version.is_version_of)}\")\n", + "\n", + "print(\"Authors:\")\n", + "for author in dataset_version.is_version_of[0].authors:\n", + " print(f\" {author.given_name} {author.family_name}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that this request includes following a \"reverse\" link (\"is_version_of\") followed by a \"forward\" link (\"authors\").\n", + "Any combination of forward and reverse links can be followed.\n", + "\n", + "Following links can even be done at the same time as retrieving the base node, reducing the number of network requests to just one:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "id https://kg.ebrains.eu/api/instances/bd5f91ff-e829-4b85-92eb-fc56991541f1\n", + "space dataset\n", + "type https://openminds.ebrains.eu/core/DatasetVersion\n", + "accessibility KGProxy([], 'https://kg.ebrains.eu/api/instances/b2ff7a47-b349-48d7-8ce4-cf51868675f1')\n", + "data_types KGProxy([], 'https://kg.ebrains.eu/api/instances/f468ee45-37a6-4e71-8b70-0cbe66d367db')\n", + "description\n", + "digital_identifier DOI(identifier='https://doi.org/10.25493/YJFW-HPY', space=None, id=https://kg.ebrains.eu/api/instances/df93b012-3bb6-4565-bce0-3bd2d3aed63b)\n", + "ethics_assessment EthicsAssessment(definition=\"'EU compliant, non sensitive' data should be able to provide an ethics approval as part of the metadata. An EBRAINS ethics compliance check is not required.\", description=\"'EU compliant, non sensitive' data should be able to provide an ethics approval as part of the metadata. An EBRAINS ethics compliance check is not required. This is typically true for all non-primate vertebrate animals as well as cephalopods.\", name='EU compliant, non sensitive', space=None, id=https://kg.ebrains.eu/api/instances/a217a2f8-dcb8-4ca9-9923-517af2aebc5b)\n", + "experimental_approaches KGProxy([], 'https://kg.ebrains.eu/api/instances/411b233f-a054-4719-bbd5-e86f1302bc46')\n", + "full_documentation KGProxy([], 'https://kg.ebrains.eu/api/instances/a245c132-30ae-4ba8-a1d1-3a0f44d056aa')\n", + "full_name Excitability profile of CA1 pyramidal neurons in APPPS1 Alzheimer disease mice and control littermates\n", + "keywords KGProxy([], 'https://kg.ebrains.eu/api/instances/62034f18-20fc-46d6-8f0a-277a60cb02e9')\n", + "license KGProxy([], 'https://kg.ebrains.eu/api/instances/64c1704b-db12-4b29-9541-b9143d081044')\n", + "preparation_designs KGProxy([], 'https://kg.ebrains.eu/api/instances/9f3abe1b-af7c-446d-b637-6a4f19ab7939')\n", + "related_publications KGProxy([], 'https://kg.ebrains.eu/api/instances/5f477d01-82c1-4c6a-891c-e902a8c2241c')\n", + "release_date 2020-04-21 00:00:00\n", + "repository KGProxy([], 'https://kg.ebrains.eu/api/instances/1a319b34-4903-4663-8882-b3fe5703cbcb')\n", + "short_name Excitability profile of CA1 pyramidal neurons in APPPS1 Alzheimer disease mice and control littermates\n", + "studied_specimens [KGProxy([], 'https://kg.ebrains.eu/api/instances/d04d00c7-b770-4744-a5f4-2ebba26ba1d1'), KGProxy([], 'https://kg.ebrains.eu/api/instances/31f9157a-616b-43b4-8a04-8fd8c15a7524'), KGProxy([], 'https://kg.ebrains.eu/api/instances/853682c7-c317-4091-b3eb-f94ce41a70a5'), KGProxy([], 'https://kg.ebrains.eu/api/instances/8300e9c8-ddce-4b72-811a-96f1f7dc0d4b'), KGProxy([], 'https://kg.ebrains.eu/api/instances/eca80107-1908-43cc-8897-5074f50dbe22'), KGProxy([], 'https://kg.ebrains.eu/api/instances/d74401a9-24a0-4373-b2b7-60b084b66820'), KGProxy([], 'https://kg.ebrains.eu/api/instances/ed399971-9797-4fc3-8796-094ebdf2432e'), KGProxy([], 'https://kg.ebrains.eu/api/instances/54e0bc42-9ddb-4503-98be-c1f3c03afea1'), KGProxy([], 'https://kg.ebrains.eu/api/instances/d5ea0238-23e7-463e-96f3-4da7c06832e4'), KGProxy([], 'https://kg.ebrains.eu/api/instances/6c00b1a4-d10f-408d-ac00-b07464a73321'), KGProxy([], 'https://kg.ebrains.eu/api/instances/d352f598-0118-4908-ad01-a2c4b5e06028'), KGProxy([], 'https://kg.ebrains.eu/api/instances/a9f319fb-9d41-4500-8eb4-08601053f850'), KGProxy([], 'https://kg.ebrains.eu/api/instances/d2b62075-768e-48f4-ba00-4e8cbbb543e9'), KGProxy([], 'https://kg.ebrains.eu/api/instances/9a83c827-3638-4bc1-92c2-10749d30500b'), KGProxy([], 'https://kg.ebrains.eu/api/instances/dd214b93-8c20-4c70-ac90-584d7f66f344'), KGProxy([], 'https://kg.ebrains.eu/api/instances/d967e53d-277d-4a2f-9090-8c50aaf0a008'), KGProxy([], 'https://kg.ebrains.eu/api/instances/0cad429a-f738-4d1d-9e56-c907b431a8c9'), KGProxy([], 'https://kg.ebrains.eu/api/instances/5f40bc15-d813-4560-92a8-a533109777fb'), KGProxy([], 'https://kg.ebrains.eu/api/instances/0be6ad46-c50d-4a50-8e2b-0eeea708019e'), KGProxy([], 'https://kg.ebrains.eu/api/instances/a7197a22-0b1d-4069-89b2-17aa92910c00'), KGProxy([], 'https://kg.ebrains.eu/api/instances/524e0e51-6a9e-410b-8d23-79ce1b7d97b7'), KGProxy([], 'https://kg.ebrains.eu/api/instances/12f80b23-6bec-4b0a-90c7-b717310fb707'), KGProxy([], 'https://kg.ebrains.eu/api/instances/ae759252-c8e4-4c60-aa4c-308922613371'), KGProxy([], 'https://kg.ebrains.eu/api/instances/e168745f-d7cf-4977-87d0-4dbeba51a9f2'), KGProxy([], 'https://kg.ebrains.eu/api/instances/d44005cd-7d11-471f-9e34-4400463449ee'), KGProxy([], 'https://kg.ebrains.eu/api/instances/7831a6bc-d329-4ff1-a5cf-270c100f9f8a')]\n", + "study_targets KGProxy([], 'https://kg.ebrains.eu/api/instances/161baa02-4e08-4cf2-a641-81cf323cc15d')\n", + "techniques [KGProxy([], 'https://kg.ebrains.eu/api/instances/dc0bbc6c-99f5-4d3b-9c5e-e1bb7d59aa63'), KGProxy([], 'https://kg.ebrains.eu/api/instances/ffc1c922-5ba9-4f03-b9be-05eb6fd0f294')]\n", + "version_identifier v1\n", + "version_innovation This is the first version of this research product.\n", + "is_version_of Dataset(authors=[Person(affiliations=Affiliation(member_of=KGProxy([], 'https://kg.ebrains.eu/api/instances/266b8ab6-1233-46e6-9a00-868380779891')), family_name='Salgueiro-Pereira', given_name='Ana Rita', space=None, id=https://kg.ebrains.eu/api/instances/5dff4ef9-bd56-4aee-979a-6ed15f65d235), Person(affiliations=Affiliation(member_of=KGProxy([], 'https://kg.ebrains.eu/api/instances/266b8ab6-1233-46e6-9a00-868380779891')), family_name='Marie', given_name='Hélène', developed=[KGProxy([], 'https://kg.ebrains.eu/api/instances/d703008d-c4f0-4b37-869f-4a2659e90d35'), KGProxy([], 'https://kg.ebrains.eu/api/instances/403d865e-417c-45fe-97cf-83a9613ae664'), KGProxy([], 'https://kg.ebrains.eu/api/instances/528ec0e6-2f21-413c-9abd-d131f7150882')], is_custodian_of=KGProxy([], 'https://kg.ebrains.eu/api/instances/65b1b9a3-af50-4c9c-a4e6-7556bc700da0'), space=None, id=https://kg.ebrains.eu/api/instances/2843990a-69dd-468b-a1d3-ff9589b485ae)], custodians=KGProxy([], 'https://kg.ebrains.eu/api/instances/2843990a-69dd-468b-a1d3-ff9589b485ae'), description='In this study we analyzed the intrinsic electrophysiological properties of CA1 excitatory hippocampal neurons in a mouse model of Alzheimer’s Disease (AD) at two age points: a presymptomatic age (3-4 months) and a symptomatic age: (9-10 months). At this latter age, this APPPS1 model harbors amyloid plaques and hippocampus-dependent cognitive alterations. Little is known about the excitability alterations in the hippocampus that correlate to these cognitive deficits. Using patch clamp electrophysiology we recorded CA1 pyramidal neurons from control littermates (Wild types) and APPPS1 slices of hippocampus at these two age points.', full_name='Excitability profile of CA1 pyramidal neurons in APPPS1 Alzheimer disease mice and control littermates', has_versions=KGProxy([], 'https://kg.ebrains.eu/api/instances/bd5f91ff-e829-4b85-92eb-fc56991541f1'), short_name='Excitability profile of CA1 pyramidal neurons in APPPS1 Alzheimer disease mice and control littermates', space=None, id=https://kg.ebrains.eu/api/instances/65b1b9a3-af50-4c9c-a4e6-7556bc700da0)\n", + "learning_resources KGProxy([], 'https://kg.ebrains.eu/api/instances/5f4a2cfb-3f94-430d-a44e-00ed5924c1ce')\n" + ] + } + ], + "source": [ + "dataset_version = omcore.DatasetVersion.from_id(\n", + " dataset_id,\n", + " kg_client,\n", + " follow_links={\n", + " \"digital_identifier\": {},\n", + " \"ethics_assessment\": {},\n", + " \"is_version_of\": {\n", + " \"authors\": {}\n", + " }\n", + " }\n", + ")\n", + "dataset_version.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note: due to underlying restrictions on the length of queries to the KG, trying to follow too many links at once can fail with a 500 error. This is being worked on." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 5. Searching the Knowledge Graph\n", + "\n", + "So far in this tutorial, all the metadata we've retrieved has been based on knowing the hexadecimal identifier of the node.\n", + "Very often, however, we don't know the identifier.\n", + "We may know the title of the dataset, its DOI, or we may wish to retrieve a group of nodes that share some property.\n", + "\n", + "For all such queries, we use the `list()` method:\n", + "\n", + "### Retrieving a dataset based on its name" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Found 1 dataset(s)\n" + ] + } + ], + "source": [ + "dataset_versions = omcore.DatasetVersion.list(kg_client, full_name=\"Excitability profile of CA1 pyramidal neurons in APPPS1 Alzheimer disease mice and control littermates\")\n", + "print(f\"Found {len(dataset_versions)} dataset(s)\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that you don't need the complete name, fairgraph will also search for fragments of the name, e.g.:" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Found 1 dataset(s)\n" + ] + }, + { + "data": { + "text/plain": [ + "'Excitability profile of CA1 pyramidal neurons in APPPS1 Alzheimer disease mice and control littermates'" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dataset_versions = omcore.DatasetVersion.list(kg_client, full_name=\"APPPS1 Alzheimer\")\n", + "print(f\"Found {len(dataset_versions)} dataset(s)\")\n", + "dataset_versions[0].full_name\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Retrieving a dataset based on its DOI\n", + "\n", + "Since the \"digital_identifier\" property links to a node of type `DOI`, we need to search on the \"identifier\" property of the `DOI` node, which contains the actual text string.\n", + "\n", + "To do this, we join the terms with a double underscore, i.e. \"digital_identifier__identifier\"." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Found 1 dataset(s)\n" + ] + }, + { + "data": { + "text/plain": [ + "'Excitability profile of CA1 pyramidal neurons in APPPS1 Alzheimer disease mice and control littermates'" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dataset_version = omcore.DatasetVersion.list(\n", + " kg_client,\n", + " digital_identifier__identifier=\"10.25493/YJFW-HPY\",\n", + " follow_links={\"digital_identifier\": {}} # this argument is optional\n", + ")\n", + "print(f\"Found {len(dataset_versions)} dataset(s)\")\n", + "dataset_versions[0].full_name\n", + "#dataset_versions[0].digital_identifier.identifier\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "\n", + "### Finding all datasets with \"Alzheimer\" in their name\n" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Found 1 dataset(s)\n" + ] + } + ], + "source": [ + "alzheimers_datasets = omcore.DatasetVersion.list(kg_client, full_name=\"Alzheimer\")\n", + "print(f\"Found {len(alzheimers_datasets)} dataset(s)\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "It may surprise you that we get only a single result for \"Alzheimer\" with this query,\n", + "but [multiple responses in the KG Search UI](https://search.kg.ebrains.eu/?category=Dataset&q=Alzheimer).\n", + "\n", + "One reason for this is that the Search UI searches both the \"full_name\" and \"description\" properties.\n", + "Another is that sometimes the full_name property comes from the parent dataset record, and is not set on an individual dataset version.\n", + "\n", + "openMINDS distinguishes between a `Dataset` and a `DatasetVersion`.\n", + "Each dataset can have multiple versions.\n", + "Both `Dataset` and `DatasetVersion` have \"name\" and \"description\" properties.\n", + "The convention in the EBRAINS Knowledge Graph [Search UI](https://search.kg.ebrains.eu/) is that if the \"name\" property of a `DatasetVersion` is empty, it should inherit it from the parent `DataSet`.\n", + "\n", + "Fortunately, we can do the same thing in our query:" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Found 5 dataset(s)\n" + ] + } + ], + "source": [ + "alzheimers_datasets = omcore.DatasetVersion.list(kg_client, is_version_of__full_name=\"Alzheimer\")\n", + "print(f\"Found {len(alzheimers_datasets)} dataset(s)\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we find 5 datasets. If we also search in the description of the parent dataset, we find even more:" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Found 11 dataset(s)\n" + ] + } + ], + "source": [ + "alzheimers_datasets = omcore.DatasetVersion.list(\n", + " kg_client,\n", + " is_version_of__full_name=\"Alzheimer\",\n", + " is_version_of__description=\"Alzheimer\"\n", + ")\n", + "print(f\"Found {len(alzheimers_datasets)} dataset(s)\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Finding all datasets with \"Alzheimers' Disease\" as a study target\n", + "\n", + "Many properties in openMINDS, like \"study_targets\", use controlled vocabularies, which means that the property is a link to a node, which in turn contains both the term itself and other information about the term, such as a definition.\n", + "\n", + "To help us build our query, we can look at the possible node types that can be linked from the property \"study_targets\":" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(fairgraph.openminds.controlled_terms.auditory_stimulus_type.AuditoryStimulusType,\n", + " fairgraph.openminds.controlled_terms.biological_order.BiologicalOrder,\n", + " fairgraph.openminds.controlled_terms.biological_sex.BiologicalSex,\n", + " fairgraph.openminds.controlled_terms.breeding_type.BreedingType,\n", + " fairgraph.openminds.controlled_terms.cell_culture_type.CellCultureType,\n", + " fairgraph.openminds.controlled_terms.cell_type.CellType,\n", + " fairgraph.openminds.controlled_terms.disease.Disease,\n", + " fairgraph.openminds.controlled_terms.disease_model.DiseaseModel,\n", + " fairgraph.openminds.controlled_terms.electrical_stimulus_type.ElectricalStimulusType,\n", + " fairgraph.openminds.controlled_terms.genetic_strain_type.GeneticStrainType,\n", + " fairgraph.openminds.controlled_terms.gustatory_stimulus_type.GustatoryStimulusType,\n", + " fairgraph.openminds.controlled_terms.handedness.Handedness,\n", + " fairgraph.openminds.controlled_terms.molecular_entity.MolecularEntity,\n", + " fairgraph.openminds.controlled_terms.olfactory_stimulus_type.OlfactoryStimulusType,\n", + " fairgraph.openminds.controlled_terms.optical_stimulus_type.OpticalStimulusType,\n", + " fairgraph.openminds.controlled_terms.organ.Organ,\n", + " fairgraph.openminds.controlled_terms.organism_substance.OrganismSubstance,\n", + " fairgraph.openminds.controlled_terms.organism_system.OrganismSystem,\n", + " fairgraph.openminds.controlled_terms.species.Species,\n", + " fairgraph.openminds.controlled_terms.subcellular_entity.SubcellularEntity,\n", + " fairgraph.openminds.controlled_terms.tactile_stimulus_type.TactileStimulusType,\n", + " fairgraph.openminds.controlled_terms.term_suggestion.TermSuggestion,\n", + " fairgraph.openminds.controlled_terms.tissue_sample_type.TissueSampleType,\n", + " fairgraph.openminds.controlled_terms.uberon_parcellation.UBERONParcellation,\n", + " fairgraph.openminds.controlled_terms.visual_stimulus_type.VisualStimulusType,\n", + " fairgraph.openminds.sands.non_atlas.custom_anatomical_entity.CustomAnatomicalEntity,\n", + " fairgraph.openminds.sands.atlas.parcellation_entity.ParcellationEntity,\n", + " fairgraph.openminds.sands.atlas.parcellation_entity_version.ParcellationEntityVersion)" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "omcore.DatasetVersion._property_lookup[\"study_targets\"].types" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\"Alzheimer's disease\" is probably a controlled term of type \"Disease\", so let's look at the properties of the `Disease` class:" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['definition',\n", + " 'description',\n", + " 'interlex_identifier',\n", + " 'knowledge_space_link',\n", + " 'name',\n", + " 'preferred_ontology_identifier',\n", + " 'synonyms',\n", + " 'describes',\n", + " 'is_modeled_by',\n", + " 'is_used_to_group',\n", + " 'specimen_state',\n", + " 'studied_in']" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import fairgraph.openminds.controlled_terms as terms\n", + "\n", + "terms.Disease.property_names" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's first see if we can find a term with that name:" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Found 1 term(s)\n", + "id https://kg.ebrains.eu/api/instances/161baa02-4e08-4cf2-a641-81cf323cc15d\n", + "space controlled\n", + "type https://openminds.ebrains.eu/controlledTerms/Disease\n", + "name Alzheimer's disease\n", + "preferred_ontology_identifier http://purl.obolibrary.org/obo/DOID_10652\n", + "specimen_state [KGProxy([], 'https://kg.ebrains.eu/api/instances/6f0d62b4-7ed0-4580-9db8-c2302b87a0af'), KGProxy([], 'https://kg.ebrains.eu/api/instances/9d3ed4e7-1c12-44ca-a053-3483e33607a3'), KGProxy([], 'https://kg.ebrains.eu/api/instances/948981a3-ab75-4420-87e5-5a6f5c05cfd9'), KGProxy([], 'https://kg.ebrains.eu/api/instances/ec57f83a-b597-44b5-8d32-45f77313db74'), KGProxy([], 'https://kg.ebrains.eu/api/instances/a7f7ffe3-79e1-4e9f-bf35-1d4b9e91e2d3'), KGProxy([], 'https://kg.ebrains.eu/api/instances/8e23df4a-a8b2-4c09-8bae-70abfae78955'), KGProxy([], 'https://kg.ebrains.eu/api/instances/3d93bb5a-bb13-421b-855a-2adb49d04a95'), KGProxy([], 'https://kg.ebrains.eu/api/instances/641c9c1d-49ac-45fb-bd02-59210870e5c6'), KGProxy([], 'https://kg.ebrains.eu/api/instances/13cc7154-7640-421a-8a14-83f17606d6ff'), KGProxy([], 'https://kg.ebrains.eu/api/instances/241553d5-d61f-4fcb-8670-f56600c841ee'), KGProxy([], 'https://kg.ebrains.eu/api/instances/077f741d-3cbf-4c1c-b803-9b5fa60b323e'), KGProxy([], 'https://kg.ebrains.eu/api/instances/8c6c6e02-097f-4ee4-a9a2-8c4edb3a8765'), KGProxy([], 'https://kg.ebrains.eu/api/instances/0f65056f-12c5-4d34-b765-f2e158488666'), KGProxy([], 'https://kg.ebrains.eu/api/instances/0f401f83-e210-45d3-8d27-4a241cca5e55'), KGProxy([], 'https://kg.ebrains.eu/api/instances/75250b12-18df-48ed-9824-5079e1066c4d'), KGProxy([], 'https://kg.ebrains.eu/api/instances/cae25860-78fe-49ed-adb4-809a400ad961'), KGProxy([], 'https://kg.ebrains.eu/api/instances/407f72f7-84f4-4f49-a598-4eed2018965e'), KGProxy([], 'https://kg.ebrains.eu/api/instances/1cb93569-f47d-4d88-8819-da21024a3c90'), KGProxy([], 'https://kg.ebrains.eu/api/instances/76ed8c4b-692b-4594-8637-b4a449261c7e'), KGProxy([], 'https://kg.ebrains.eu/api/instances/ea75d572-b9df-4cc1-adf4-246a93183bbe'), KGProxy([], 'https://kg.ebrains.eu/api/instances/f2d2004f-fd9a-47d0-9216-690c8c9b164d'), KGProxy([], 'https://kg.ebrains.eu/api/instances/68f3ab73-fe7c-49c4-ba9f-b146f4c9ad11'), KGProxy([], 'https://kg.ebrains.eu/api/instances/023c4698-ec40-4547-b087-ea9cc75178b5'), KGProxy([], 'https://kg.ebrains.eu/api/instances/29889c0a-4723-445b-9326-c4b38c34b810'), KGProxy([], 'https://kg.ebrains.eu/api/instances/d6b9019e-87ec-4f58-899a-700f6b97f660'), KGProxy([], 'https://kg.ebrains.eu/api/instances/728451a2-2de8-4dfd-a0b0-3b0572914792'), KGProxy([], 'https://kg.ebrains.eu/api/instances/c891e596-81e2-4a84-a58e-436f4adb22d6'), KGProxy([], 'https://kg.ebrains.eu/api/instances/77eac412-7b03-46e5-81f0-77c005b80b9e'), KGProxy([], 'https://kg.ebrains.eu/api/instances/c5f648ac-f7ee-41d3-a526-6c33016fa7c0'), KGProxy([], 'https://kg.ebrains.eu/api/instances/815bcb03-b2b7-4179-a302-c58339bd890d'), KGProxy([], 'https://kg.ebrains.eu/api/instances/2c0e6550-1a95-4889-9f3e-ce47c74cfe09'), KGProxy([], 'https://kg.ebrains.eu/api/instances/b139ba65-dcb6-40b6-9d26-beedccc900ec'), KGProxy([], 'https://kg.ebrains.eu/api/instances/8276d643-fb5b-417c-a9ba-f9bcee2d3d03'), KGProxy([], 'https://kg.ebrains.eu/api/instances/fb26e428-7d11-4204-b86b-bee9666510bd'), KGProxy([], 'https://kg.ebrains.eu/api/instances/c5333c66-1536-42e1-b289-0d47a5b15ee9'), KGProxy([], 'https://kg.ebrains.eu/api/instances/5acb7d0c-9d2a-4cfe-a81a-830ea586b0bc'), KGProxy([], 'https://kg.ebrains.eu/api/instances/baf2f411-8fa7-44db-8ffd-7510483a7fcb'), KGProxy([], 'https://kg.ebrains.eu/api/instances/8c765e58-8e76-4d3f-838e-3961cd543d06'), KGProxy([], 'https://kg.ebrains.eu/api/instances/9906a367-735e-4f3c-a8eb-085131629ade'), KGProxy([], 'https://kg.ebrains.eu/api/instances/23f49507-c2bc-4e8f-9c04-193a8c3fc2a5'), KGProxy([], 'https://kg.ebrains.eu/api/instances/359cf2cc-ee56-4a59-8527-58f96ebd90de'), KGProxy([], 'https://kg.ebrains.eu/api/instances/ce895d7a-4487-4424-909f-fe471c11b343'), KGProxy([], 'https://kg.ebrains.eu/api/instances/38e8e02f-fc28-4b2b-86c8-7d95346b45c0'), KGProxy([], 'https://kg.ebrains.eu/api/instances/4999a5b1-ac80-49dd-960e-a5d683d4f281'), KGProxy([], 'https://kg.ebrains.eu/api/instances/c0b43b67-562c-426e-bbdb-fb8107e19e39'), KGProxy([], 'https://kg.ebrains.eu/api/instances/eabaa009-93a6-4452-9bd0-3c5a4a7cd99f'), KGProxy([], 'https://kg.ebrains.eu/api/instances/a23704c9-8e9b-46e1-b4b3-7e74db3937ee'), KGProxy([], 'https://kg.ebrains.eu/api/instances/10786a2d-01f1-415b-9e51-92fb5606bb7c'), KGProxy([], 'https://kg.ebrains.eu/api/instances/847022e6-894b-4daf-8ecd-e4dcf7d89f83'), KGProxy([], 'https://kg.ebrains.eu/api/instances/18d3eb3e-9a43-4c5d-bbea-1671f0e74498'), KGProxy([], 'https://kg.ebrains.eu/api/instances/84ff2a0e-4a0f-442b-9ecd-ede34402ce07'), KGProxy([], 'https://kg.ebrains.eu/api/instances/6daa2eb7-5a33-48ef-a4cc-5ceafa8d46eb'), KGProxy([], 'https://kg.ebrains.eu/api/instances/1f0d44f2-63ce-4c8e-809a-3b71a5c3b90f'), KGProxy([], 'https://kg.ebrains.eu/api/instances/dbe041e9-419e-45e9-a111-7d7281331621'), KGProxy([], 'https://kg.ebrains.eu/api/instances/eadfe0a3-9360-4b96-aca1-72644f4c7045'), KGProxy([], 'https://kg.ebrains.eu/api/instances/41706256-3206-4fd9-b3ee-c24c5de61570'), KGProxy([], 'https://kg.ebrains.eu/api/instances/4f81c8d5-b029-4cd7-aa3d-3cb8afb70d5c'), KGProxy([], 'https://kg.ebrains.eu/api/instances/32eb8af8-f104-41aa-8bdd-10efe7d8e1d7'), KGProxy([], 'https://kg.ebrains.eu/api/instances/56f602f8-7868-4dc2-ab3f-86c668100217'), KGProxy([], 'https://kg.ebrains.eu/api/instances/9f419b04-db56-4b60-92b9-36cf2cba2c3c'), KGProxy([], 'https://kg.ebrains.eu/api/instances/6e3f267a-859a-4fe0-937f-460cab4f62ae'), KGProxy([], 'https://kg.ebrains.eu/api/instances/2934334c-154c-40ce-951b-7c4235c7f92f'), KGProxy([], 'https://kg.ebrains.eu/api/instances/db3b26ce-23bb-429e-9fee-dbe4c4f37821'), KGProxy([], 'https://kg.ebrains.eu/api/instances/c43d881c-7700-42a0-8796-a33602b49cf9'), KGProxy([], 'https://kg.ebrains.eu/api/instances/c7e9f68c-0d60-40d7-aa11-35a3fa09252a'), KGProxy([], 'https://kg.ebrains.eu/api/instances/ad51c99c-2e31-426b-ad06-cbc27dd76ffe'), KGProxy([], 'https://kg.ebrains.eu/api/instances/db23405f-5521-491c-aab0-50cb4c282eda'), KGProxy([], 'https://kg.ebrains.eu/api/instances/80cd4922-3d0a-42ea-9735-d838b2c3265a'), KGProxy([], 'https://kg.ebrains.eu/api/instances/2c3ce393-d3b4-4101-b6ce-48accc53a2f4'), KGProxy([], 'https://kg.ebrains.eu/api/instances/d7353778-4e91-4363-9e70-62093aa0b418'), KGProxy([], 'https://kg.ebrains.eu/api/instances/8e12ad4c-94a5-4b1d-821f-0679c5f427ae'), KGProxy([], 'https://kg.ebrains.eu/api/instances/6018bcea-0ded-40a3-a926-4dfce2f2ac55'), KGProxy([], 'https://kg.ebrains.eu/api/instances/8a12b1af-e431-4ede-84d4-d5c7cba769a4'), KGProxy([], 'https://kg.ebrains.eu/api/instances/101b3988-7b65-4f28-be60-0c5529da60bb'), KGProxy([], 'https://kg.ebrains.eu/api/instances/284afb08-ecf0-416e-8d94-dd446344dead'), KGProxy([], 'https://kg.ebrains.eu/api/instances/fcbebe74-e3ca-4aa6-884d-889d020563ab'), KGProxy([], 'https://kg.ebrains.eu/api/instances/64578374-1fa1-4067-8a9b-eec9f26b4e1d'), KGProxy([], 'https://kg.ebrains.eu/api/instances/f01e6044-e386-422b-acff-8784995bb1b1'), KGProxy([], 'https://kg.ebrains.eu/api/instances/f4cb5fb0-2eac-4f00-9876-bfd85822e6de'), KGProxy([], 'https://kg.ebrains.eu/api/instances/314ec38a-35b4-4e62-9953-503447e19611'), KGProxy([], 'https://kg.ebrains.eu/api/instances/3931824a-a2b5-4d1e-85ca-5f49044735f2'), KGProxy([], 'https://kg.ebrains.eu/api/instances/9b4ea705-22b0-4311-964f-a24e244297f3'), KGProxy([], 'https://kg.ebrains.eu/api/instances/87ccd7a9-794a-4f3c-8598-64f29f78e1c1'), KGProxy([], 'https://kg.ebrains.eu/api/instances/f4513dd8-5e0b-457e-a3a2-9b7dd6250bbf'), KGProxy([], 'https://kg.ebrains.eu/api/instances/cbe48d77-46aa-4391-9159-3ed2abb5cb71'), KGProxy([], 'https://kg.ebrains.eu/api/instances/d8b615e2-a042-4091-8d2a-b00195bbbf0c'), KGProxy([], 'https://kg.ebrains.eu/api/instances/2ec008e2-549c-4c52-aea7-f1e4e74d135b'), KGProxy([], 'https://kg.ebrains.eu/api/instances/7e803a48-a6bb-4f8e-b39b-396806afa345'), KGProxy([], 'https://kg.ebrains.eu/api/instances/385580b4-92be-40c6-aab8-0c0335b9bdfc'), KGProxy([], 'https://kg.ebrains.eu/api/instances/ca58bbae-dff0-423c-8f70-d872f7e1ec9b'), KGProxy([], 'https://kg.ebrains.eu/api/instances/59ae29d2-1815-4af3-897b-4f1eb3c7784a')]\n", + "studied_in [KGProxy([], 'https://kg.ebrains.eu/api/instances/f885f773-ffeb-4244-a96b-2a9bc797a307'), KGProxy([], 'https://kg.ebrains.eu/api/instances/4df8c324-af31-4cfc-a8af-a7ebf1d59fa1'), KGProxy([], 'https://kg.ebrains.eu/api/instances/9df1a57c-3d54-4b9d-beff-88c24902a00d'), KGProxy([], 'https://kg.ebrains.eu/api/instances/685b5844-7627-459c-a184-be1bab132c9d'), KGProxy([], 'https://kg.ebrains.eu/api/instances/e3bcc696-9f24-46a9-ae21-4761caafb068'), KGProxy([], 'https://kg.ebrains.eu/api/instances/54719155-54c7-4456-8987-36b7d5dce071'), KGProxy([], 'https://kg.ebrains.eu/api/instances/2b600072-be7f-423f-a979-1e35283acaca'), KGProxy([], 'https://kg.ebrains.eu/api/instances/e5f79837-c907-4439-8f31-dc4c601990fa'), KGProxy([], 'https://kg.ebrains.eu/api/instances/ffa2faab-b7ed-4c61-83ec-800689d024d1'), KGProxy([], 'https://kg.ebrains.eu/api/instances/c404e7f6-9a18-4a5c-ae3c-27f159f4f96a'), KGProxy([], 'https://kg.ebrains.eu/api/instances/bd5f91ff-e829-4b85-92eb-fc56991541f1'), KGProxy([], 'https://kg.ebrains.eu/api/instances/bf268b89-1420-476b-b428-b85a913eb523')]\n" + ] + } + ], + "source": [ + "possible_terms = terms.Disease.list(kg_client, name=\"Alzheimer's disease\")\n", + "print(f\"Found {len(possible_terms)} term(s)\")\n", + "\n", + "alzheimers = possible_terms[0]\n", + "alzheimers.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we have the graph node for that term, there are two ways we can find dataset versions that link to it:\n", + "\n", + "1. Starting from `DatasetVersion`" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Found 11 datasets(s)\n" + ] + } + ], + "source": [ + "alzheimers_datasets1 = omcore.DatasetVersion.list(kg_client, study_targets=alzheimers)\n", + "print(f\"Found {len(alzheimers_datasets1)} datasets(s)\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2. Starting from the controlled term node:\n", + "\n", + "In fact, the query for the term already gave us links to all the dataset versions that link to that term, using the property \"studied_in\", which is the reverse of \"study_targets\"." + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Found 12 datasets(s)\n" + ] + } + ], + "source": [ + "alzheimers_datasets2 = [link.resolve(kg_client) for link in alzheimers.studied_in]\n", + "print(f\"Found {len(alzheimers_datasets2)} datasets(s)\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You may ask why the first query gave 11 results and the second query gave 12?!\n", + "\n", + "The answer is that the KG contains far more than just datasets. Let's look at the types of node that the Alzheimer node links to:" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[fairgraph.openminds.core.products.dataset_version.DatasetVersion,\n", + " fairgraph.openminds.core.products.dataset_version.DatasetVersion,\n", + " fairgraph.openminds.core.products.dataset_version.DatasetVersion,\n", + " fairgraph.openminds.core.products.dataset_version.DatasetVersion,\n", + " fairgraph.openminds.core.products.dataset_version.DatasetVersion,\n", + " fairgraph.openminds.core.products.dataset_version.DatasetVersion,\n", + " fairgraph.openminds.core.products.model.Model,\n", + " fairgraph.openminds.core.products.dataset_version.DatasetVersion,\n", + " fairgraph.openminds.core.products.dataset_version.DatasetVersion,\n", + " fairgraph.openminds.core.products.dataset_version.DatasetVersion,\n", + " fairgraph.openminds.core.products.dataset_version.DatasetVersion,\n", + " fairgraph.openminds.core.products.dataset_version.DatasetVersion]" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "[link.cls for link in alzheimers.studied_in]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The mystery is explained! One of the 12 linked nodes is a model, not a dataset version." + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "id https://kg.ebrains.eu/api/instances/2b600072-be7f-423f-a979-1e35283acaca\n", + "space model\n", + "type https://openminds.ebrains.eu/core/Model\n", + "abstraction_level KGProxy([], 'https://kg.ebrains.eu/api/instances/75d660a3-ca3a-4bcc-933b-3bd8b6fea162')\n", + "custodians KGProxy((, , ), 'https://kg.ebrains.eu/api/instances/9a729478-8ad1-485c-b9ad-9a8a3d767f3d')\n", + "description Age-dependent accumulation of amyloid-b, provoking increasing brain amyloidopathy, triggers abnormal patterns of neuron activity and circuit synchronization in Alzheimer’s disease (AD) as observed in human AD patients and AD mouse models. Recent studies on AD mouse models, mimicking this age-dependent amyloidopathy, identified alterations in CA1 neuron excitability. However, these models generally also overexpress mutated amyloid precursor protein (APP) and presenilin 1 (PS1) and there is a lack of a clear correlation of neuronal excitability alterations with progressive amyloidopathy. The active development of computational models of AD points out the need of collecting such experimental data to build a reliable disease model exhibiting AD-like disease progression. We therefore used the feature extraction tool of the Human Brain Project (HBP) Brain Simulation Platform to systematically analyze the excitability profile of CA1 pyramidal neuron in the APPPS1 mouse model. We identified specific features of neuron excitability that best correlate either with over-expression of mutated APP and PS1 or increasing Ab amyloidopathy. Notably, we report strong alterations in membrane time constant and action potential width and weak alterations in firing behavior. Also, using a CA1 pyramidal neuron model, we evidence amyloidopathy-dependent alterations in Ih. Finally, cluster analysis of these recordings showed that we could reliably assign a trace to its correct group, opening the door to a more refined, less variable analysis of AD-affected neurons. This inter-disciplinary analysis, bringing together experimentalists and modelers, helps to further unravel the neuronal mechanisms most affected by AD and to build a biologically plausible computational model of the AD brain.\n", + "developers [KGProxy((, , ), 'https://kg.ebrains.eu/api/instances/5f009b50-4422-43fa-84b1-7d3a7dbe34e8'), KGProxy((, , ), 'https://kg.ebrains.eu/api/instances/9a729478-8ad1-485c-b9ad-9a8a3d767f3d')]\n", + "full_name Age-dependent excitability of CA1 pyramidal neurons in APPPS1 Alzheimer's model\n", + "has_versions KGProxy([], 'https://kg.ebrains.eu/api/instances/e1267b8b-96ec-4759-acb4-2d8ffc23f524')\n", + "homepage https://modeldb.science/266848\n", + "model_scope KGProxy([], 'https://kg.ebrains.eu/api/instances/3daa5868-9dae-401d-8bd6-76b7fd34ef71')\n", + "short_name ca1-pyr-excitability-appps1\n", + "study_targets [KGProxy((, , , , , , , , , , , , , , , , , , , , , , , , , , , ), 'https://kg.ebrains.eu/api/instances/161baa02-4e08-4cf2-a641-81cf323cc15d'), KGProxy((, , , , , , , , , , , , , , , , , , , , , , , , , , , ), 'https://kg.ebrains.eu/api/instances/499b52ed-fb94-4291-a4fd-99a043a9af31'), KGProxy((, , , , , , , , , , , , , , , , , , , , , , , , , , , ), 'https://kg.ebrains.eu/api/instances/d77eb055-3ee9-484f-9c53-b2e621afcb45'), KGProxy((, , , , , , , , , , , , , , , , , , , , , , , , , , , ), 'https://kg.ebrains.eu/api/instances/d9875ebd-260e-4337-a637-b62fed4aa91d')]\n" + ] + } + ], + "source": [ + "alzheimers_model = [item for item in alzheimers_datasets2 if isinstance(item, omcore.Model)][0]\n", + "alzheimers_model.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 6. Writing to the Knowledge Graph" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 7. Conclusions\n", + "\n", + "This is the end of the tutorial.\n", + "The aim was to give you an understanding of some of the key concepts, and to give you experience with querying, retrieving, and creating metadata nodes in the EBRAINS Knowledge Graph, using fairgraph.\n", + "\n", + "You may also be interested in our tutorial on [working with the EBRAINS Knowledge Graph using Javascript](https://github.com/apdavison/ebrains-kg-tutorial-javascript)." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "env", + "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.9.6" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/notebooks/images/get-token.png b/examples/notebooks/images/get-token.png new file mode 100644 index 0000000000000000000000000000000000000000..cfe241234fece31d9aa3d34470431d51015e4f3d GIT binary patch literal 25256 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 Date: Fri, 7 Mar 2025 17:37:09 +0100 Subject: [PATCH 2/4] set kernel for EBRAINS Lab --- examples/notebooks/advanced_tutorial.ipynb | 34 ++++------------------ 1 file changed, 6 insertions(+), 28 deletions(-) diff --git a/examples/notebooks/advanced_tutorial.ipynb b/examples/notebooks/advanced_tutorial.ipynb index 345ad435..960b6681 100644 --- a/examples/notebooks/advanced_tutorial.ipynb +++ b/examples/notebooks/advanced_tutorial.ipynb @@ -99,31 +99,9 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "************************************************************************\n", - "To continue, you need to authenticate. To do so, please visit https://iam.ebrains.eu/auth/realms/hbp/device?user_code=VKPH-BWRC\n", - "*************************************************************************\n", - "You are successfully authenticated! Thank you very much!\n", - "*************************************************************************\n" - ] - }, - { - "data": { - "text/plain": [ - "User(alternate_name='adavisontesting', name='Testing Davison', email=None, given_name='Testing', family_name='Davison', identifiers=['18e48ea2-fccb-455b-b42c-df21f4820676'])" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "from fairgraph import KGClient\n", "\n", @@ -1052,9 +1030,9 @@ ], "metadata": { "kernelspec": { - "display_name": "env", + "display_name": "EBRAINS-experimental", "language": "python", - "name": "python3" + "name": "ebrains-experimental" }, "language_info": { "codemirror_mode": { @@ -1066,9 +1044,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.6" + "version": "3.8.11" } }, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 4 } From 4dbb2a33d26bfb7e85d349ef750bd58c356e1e9b Mon Sep 17 00:00:00 2001 From: Andrew Davison Date: Fri, 7 Mar 2025 18:18:49 +0100 Subject: [PATCH 3/4] Added "Writing to the Knowledge Graph" section --- examples/notebooks/advanced_tutorial.ipynb | 361 ++++++++++++++++++++- 1 file changed, 360 insertions(+), 1 deletion(-) diff --git a/examples/notebooks/advanced_tutorial.ipynb b/examples/notebooks/advanced_tutorial.ipynb index 960b6681..a03d36da 100644 --- a/examples/notebooks/advanced_tutorial.ipynb +++ b/examples/notebooks/advanced_tutorial.ipynb @@ -1012,7 +1012,366 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## 6. Writing to the Knowledge Graph" + "## 6. Writing to the Knowledge Graph\n", + "\n", + "When sharing scientific data and the associated metadata,\n", + "especially sensitive or pre-publication data,\n", + "it is important to consider who has access to the data,\n", + "and who has permissions to create or modify metadata.\n", + "\n", + "The EBRAINS Knowledge Graph is divided into different spaces,\n", + "each with its own access control permissions.\n", + "By default, the core API searches across all spaces for which a user has \"read\" permission,\n", + "although it is possible to restrict searches to specific spaces.\n", + "\n", + "Public metadata in the EBRAINS KG are stored in curated spaces,\n", + "to which only nominated curators have write access.\n", + "This ensures high standards of quality control.\n", + "\n", + "However, each user has their own private space in the KG, called \"myspace\",\n", + "and user may also create shared private spaces,\n", + "associated with a collab workspace in the [EBRAINS Collaboratory](https://wiki.ebrains.eu/).\n", + "\n", + "In this part of the tutorial, we will create our own openMINDS nodes, and save them to your \"myspace\".\n", + "Let's try adding some people. To see what properties the `Person` type has, we can examine the `property_name` attribute:" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['affiliations',\n", + " 'alternate_names',\n", + " 'associated_accounts',\n", + " 'contact_information',\n", + " 'digital_identifiers',\n", + " 'family_name',\n", + " 'given_name',\n", + " 'activities',\n", + " 'comments',\n", + " 'coordinated_projects',\n", + " 'developed',\n", + " 'funded',\n", + " 'is_custodian_of',\n", + " 'is_owner_of',\n", + " 'is_provider_of',\n", + " 'manufactured',\n", + " 'published',\n", + " 'started']" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "omcore.Person.property_names" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To see more information, like what Python type each property expects, and whether a property can contain multiple items in a list, we can use the `properties` attribute:" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[Property(name='affiliations', types=(,), path='vocab:affiliation', required=False, multiple=True),\n", + " Property(name='alternate_names', types=(,), path='vocab:alternateName', required=False, multiple=True),\n", + " Property(name='associated_accounts', types=(,), path='vocab:associatedAccount', required=False, multiple=True),\n", + " Property(name='contact_information', types=(,), path='vocab:contactInformation', required=False, multiple=False),\n", + " Property(name='digital_identifiers', types=(,), path='vocab:digitalIdentifier', required=False, multiple=True),\n", + " Property(name='family_name', types=(,), path='vocab:familyName', required=False, multiple=False),\n", + " Property(name='given_name', types=(,), path='vocab:givenName', required=True, multiple=False)]" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "omcore.Person.properties" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We'll stick to something simple: adding the \"given_name\", \"family_name\" and \"affiliation\" properties." + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [], + "source": [ + "mgm = omcore.Organization(full_name=\"Metro-Goldwyn-Mayer\", short_name=\"MGM\")\n", + "stan = omcore.Person(given_name=\"Stan\", family_name=\"Laurel\", affiliations=omcore.Affiliation(member_of=mgm))\n", + "ollie = omcore.Person(given_name=\"Oliver\", family_name=\"Hardy\", alternate_names=[\"Ollie\"], affiliations=omcore.Affiliation(member_of=mgm))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can save these as nodes in the KG. \n", + "\n", + "Note that we use the \"recursive\" option, so that the \"mgm\" node will also be saved, as it is a child of the \"stan\" and \"ollie\" nodes. Alternatively, we could have saved \"mgm\" explicitly, and then saved \"stan\" and \"ollie\" with `recursive=False`.\n", + "In general, it is safer and faster to use `recursive=False` and to manage saving all nodes explicitly, but it does take more effort." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "stan.save(kg_client, space=\"myspace\", recursive=True)\n", + "ollie.save(kg_client, space=\"myspace\", recursive=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's check this worked:" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "- Bilbo Baggins (39a51d78-a181-402b-a6ee-cee868a3f864)\n", + "- Oliver Hardy (b359d7f3-8e7a-440b-a4d4-9c393f428508)\n", + "- Stan Laurel (c187464f-4529-417c-9c1b-84496922e8b5)\n" + ] + } + ], + "source": [ + "for person in omcore.Person.list(kg_client, scope=\"in progress\", space=\"myspace\"):\n", + " print(f\"- {person.full_name} ({person.uuid})\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "One more important thing to note: when querying the KG to get a list of people,\n", + "we pass the option `scope=\"in progress\"`.\n", + "\n", + "When first creating a new node in the KG, it is set to the status \"In progress\".\n", + "Only after quality control checks, and when we wish to publish the metadata,\n", + "is the node set to \"Released\" status." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "What happens if we create a new Stan Laurel node and save it?" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "- Bilbo Baggins (39a51d78-a181-402b-a6ee-cee868a3f864)\n", + "- Oliver Hardy (b359d7f3-8e7a-440b-a4d4-9c393f428508)\n", + "- Stan Laurel (c187464f-4529-417c-9c1b-84496922e8b5)\n" + ] + } + ], + "source": [ + "new_stan = omcore.Person(given_name=\"Stan\", family_name=\"Laurel\", affiliations=omcore.Affiliation(member_of=mgm))\n", + "new_stan.save(kg_client, space=\"myspace\", recursive=True)\n", + "\n", + "for person in omcore.Person.list(kg_client, scope=\"in progress\", space=\"myspace\"):\n", + " print(f\"- {person.full_name} ({person.uuid})\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We have the same list, and our local Python objects `stan` and `new_stan` have the same IDs." + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "c187464f-4529-417c-9c1b-84496922e8b5\n", + "c187464f-4529-417c-9c1b-84496922e8b5\n" + ] + } + ], + "source": [ + "print(stan.uuid)\n", + "print(new_stan.uuid)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This happens because fairgraph checks whether a node already exists in the KG before creating a new one. To do this, it uses the attribute `existence_query_properties`:" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "('given_name', 'family_name')" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "omcore.Person.existence_query_properties" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "so any `Person` object with the same \"given_name\" and \"family_name\" will be considered to represent the same person, even if other properties, such as \"affiliations\", differ between the two objects.\n", + "\n", + "If you really need to add a new object with the same \"existence query\" properties, you could create the object with slightly modified attributes, then change it back to the original value and save the modifications." + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "dae57942-ea76-4283-9439-b368b5e26fb6\n", + "- Bilbo Baggins (39a51d78-a181-402b-a6ee-cee868a3f864)\n", + "- Oliver Hardy (b359d7f3-8e7a-440b-a4d4-9c393f428508)\n", + "- Stan Laurel (c187464f-4529-417c-9c1b-84496922e8b5)\n", + "- Stan Laurel (dae57942-ea76-4283-9439-b368b5e26fb6)\n" + ] + } + ], + "source": [ + "new_stan = omcore.Person(given_name=\"Stan_CHANGETHIS\", family_name=\"Laurel\")\n", + "new_stan.save(kg_client, space=\"myspace\")\n", + "new_stan.given_name = \"Stan\"\n", + "new_stan.save(kg_client)\n", + "\n", + "print(new_stan.uuid)\n", + "\n", + "for person in omcore.Person.list(kg_client, scope=\"in progress\", space=\"myspace\"):\n", + " print(f\"- {person.full_name} ({person.uuid})\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "(Note that when saving modifications to an existing node, you don't need to specify the space, since fairgraph keeps track of this).\n", + "\n", + "The alternative approach is to generate the ID locally:" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "- Bilbo Baggins (39a51d78-a181-402b-a6ee-cee868a3f864)\n", + "- Oliver Hardy (b359d7f3-8e7a-440b-a4d4-9c393f428508)\n", + "- Stan Laurel (c187464f-4529-417c-9c1b-84496922e8b5)\n", + "- Stan Laurel (dae57942-ea76-4283-9439-b368b5e26fb6)\n", + "- Stan Laurel (e0f45937-1948-44ac-accd-d6045c2494b9)\n" + ] + } + ], + "source": [ + "from uuid import uuid4\n", + "\n", + "another_new_stan = omcore.Person(\n", + " given_name=\"Stan\",\n", + " family_name=\"Laurel\",\n", + " id=kg_client.uri_from_uuid(uuid4())\n", + ")\n", + "another_new_stan.save(kg_client, space=\"myspace\")\n", + "\n", + "for person in omcore.Person.list(kg_client, scope=\"in progress\", space=\"myspace\"):\n", + " print(f\"- {person.full_name} ({person.uuid})\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "But there was only one Stan Laurel, so let's delete the extra ones!" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "- Bilbo Baggins (39a51d78-a181-402b-a6ee-cee868a3f864)\n", + "- Oliver Hardy (b359d7f3-8e7a-440b-a4d4-9c393f428508)\n", + "- Stan Laurel (c187464f-4529-417c-9c1b-84496922e8b5)\n" + ] + } + ], + "source": [ + "new_stan.delete(kg_client)\n", + "another_new_stan.delete(kg_client)\n", + "\n", + "for person in omcore.Person.list(kg_client, scope=\"in progress\", space=\"myspace\"):\n", + " print(f\"- {person.full_name} ({person.uuid})\")" ] }, { From 1c024e55a986d0af8533c4db6cc9dd4b8c171080 Mon Sep 17 00:00:00 2001 From: Andrew Davison Date: Fri, 7 Mar 2025 18:21:51 +0100 Subject: [PATCH 4/4] Added Stan photo --- examples/notebooks/advanced_tutorial.ipynb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/examples/notebooks/advanced_tutorial.ipynb b/examples/notebooks/advanced_tutorial.ipynb index a03d36da..280b7b10 100644 --- a/examples/notebooks/advanced_tutorial.ipynb +++ b/examples/notebooks/advanced_tutorial.ipynb @@ -1374,6 +1374,13 @@ " print(f\"- {person.full_name} ({person.uuid})\")" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![Stan Laurel (1920) from Wikimedia Commons. This work is in the Public Domain.](https://upload.wikimedia.org/wikipedia/commons/thumb/3/34/Stan_Laurel_c1920.jpg/183px-Stan_Laurel_c1920.jpg)" + ] + }, { "cell_type": "markdown", "metadata": {},