Collection with properties:
+.S11 { border-left: 1px solid rgb(217, 217, 217); border-right: 1px solid rgb(217, 217, 217); border-top: 0px none rgb(33, 33, 33); border-bottom: 1px solid rgb(217, 217, 217); border-radius: 0px 0px 4px 4px; padding: 0px 45px 4px 13px; line-height: 18.004px; min-height: 0px; white-space: nowrap; color: rgb(33, 33, 33); font-family: Menlo, Monaco, Consolas, "Courier New", monospace; font-size: 14px; }
Metadata instances and collections
In this example we will create a metadata collection for the crew members of the "Heart of Gold" Spacecraft as described in the openMINDS getting started guide. We start by importing a csv file with crew member information:
filePath = fullfile(openminds.toolboxdir(), "livescripts", "data", "spacecraft_crew_members.csv");
crewMembers = readtable(filePath, "TextType", "String")
crewMembers = 4×5 table
| givenName | familyName | alternateName | email | memberOf |
---|
1 | "Arthur" | "Dent" | <missing> | "arthur-dent@hitchhikers-guide.galaxy" | "Heart of Gold Spacecraft Crew" |
---|
2 | "Ford" | "Prefect" | <missing> | "ford-prefect@hitchhikers-guide.galaxy" | "Heart of Gold Spacecraft Crew" |
---|
3 | "Tricia Marie" | "McMillan" | "Trillian Astra" | "trillian-astra@hitchhikers-guide.galaxy" | "Heart of Gold Spacecraft Crew" |
---|
4 | "Zaphod" | "Beeblebrox" | <missing> | "zaphod-beeblebrox@hitchhikers-guide.galaxy" | "Heart of Gold Spacecraft Crew" |
---|
Create instances
Let us create a set of metadata instances from this table that represents the crew members. We assume that memberOf provides the full name of a consortium each person is affiliated to. Since members might be affiliated to the same consortium we assume further that the same full name means the same consortium. We can also assume that the email is unique for each person.
With these assumptions we will create:
- a metadata Collection for storing metadata instances
- a unique set of Consortium instances based on the name given in the memberOf column
- a ContactInformation instance based on the email column
- a Person instance for each table row with:
- the givenName, familyName, and alternateName (if available)
- a link to the respective ContactInformation instance
- a person-specific embedded Affiliation instance that links to the respective Consortium instance
We start by creating an empty metadata collection for storing metadata instances.
% Create an empty metadata collection
collection = openminds.Collection(...
"Name", "Crew Members", ...
"Description", "Crew members of the 'Heart of Gold' spacecraft")
collection =
Collection with properties:
Name: "Crew Members"
Description: "Crew members of the 'Heart of Gold' spacecraft"
Nodes: dictionary with unset key and value types
-
The collection will hold instances in a dictionary object of the Nodes property. Note: the Name and Description are optional and are currently not stored with the metadata instances.
We move on and start creating instances for the consortia:
% Define a utility function for creating instance ids:
createId = @(str) lower(sprintf('_:%s', replace(str, ' ', '-')));
% Extract the unique "memberOf" names to create dictionary
% with unique "Consortium" instances
uniqueConsortiumNames = unique(crewMembers.memberOf);
for consortiumName = uniqueConsortiumNames'
consortia(consortiumName) = openminds.core.Consortium(...
'id', createId(consortiumName), ...
'fullName', consortiumName );
disp(consortia)
dictionary (string ⟼ openminds.core.actors.Consortium) with 1 entry:
+
The collection will hold instances in a dictionary object of the Nodes property. Note: the Name and Description are optional and are currently not stored with the metadata instances.
We move on and start creating instances for the consortia:
% Define a utility function for creating instance ids:
createId = @(str) lower(sprintf('_:%s', replace(str, ' ', '-')));
% Extract the unique "memberOf" names to create dictionary
% with unique "Consortium" instances
uniqueConsortiumNames = unique(crewMembers.memberOf);
for consortiumName = uniqueConsortiumNames'
consortia(consortiumName) = openminds.core.Consortium(...
'id', createId(consortiumName), ...
'fullName', consortiumName );
disp(consortia)
dictionary (string ⟼ openminds.core.actors.Consortium) with 1 entry:
- "Heart of Gold Spacecraft Crew" ⟼ [Heart of Gold Spacecraft Crew] (Consortium)
We have now created a dictionary that holds the Consortium instances. Since all the persons in this example belongs to the same consortium, this dictionary only holds one instance.
We can also look at the Consortium instance in more detail:
disp(consortia("Heart of Gold Spacecraft Crew"))
Consortium (https://openminds.ebrains.eu/core/Consortium) with properties:
+ "Heart of Gold Spacecraft Crew" ⟼ [Heart of Gold Spacecraft Crew] (Consortium)
We have now created a dictionary that holds the Consortium instances. Since all the persons in this example belongs to the same consortium, this dictionary only holds one instance.
We can also look at the Consortium instance in more detail:
disp(consortia("Heart of Gold Spacecraft Crew"))
Consortium (https://openminds.ebrains.eu/core/Consortium) with properties:
contactInformation: [None] (ContactInformation)
fullName: "Heart of Gold Spacecraft Crew"
homepage: ""
shortName: ""
- Required Properties: fullName
The Consortium instance has four properties, and we have filled out fullName. Whenever you create an openMINDS instance in MATLAB, you can either supply one or more name-value pairs when you create the instance (as we did above), or you can first create the instance and then assign values using dot-indexing on the instance object.
consortium = openminds.core.Consortium();
consortium.fullName = "Heart of Gold Spacecraft Crew"
consortium =
Consortium (https://openminds.ebrains.eu/core/Consortium) with properties:
+ Required Properties: fullName
The Consortium instance has four properties, and we have filled out fullName. Whenever you create an openMINDS instance in MATLAB, you can either supply one or more name-value pairs when you create the instance (as we did above), or you can first create the instance and then assign values using dot-indexing on the instance object.
consortium = openminds.core.Consortium();
consortium.fullName = "Heart of Gold Spacecraft Crew"
consortium =
Consortium (https://openminds.ebrains.eu/core/Consortium) with properties:
contactInformation: [None] (ContactInformation)
fullName: "Heart of Gold Spacecraft Crew"
@@ -62,16 +62,16 @@
shortName: ""
Required Properties: fullName
-
When the instance is displayed, you will see all the properties that are part of the instance type, and which of those are required (Note: at the moment of writing this guide, required properties are not enforced). The display should also give information about what types are expected for each of the property values. For example, the contactInformation property requires a ContactInformation instance (as indicated by the annotation in the brackets). If you want to learn more about the types as you explore the instances, you can always press the links in the instance display and they will take you to the openMINDS documentation page for that instance.
The consortium in this example does not have contact information, but we will move on and create ContactInformation types for each of the persons:
% Create a dictionary to hold "ContactInformation" instances
for email = crewMembers.email'
contacts(email) = openminds.core.ContactInformation(...
'id', createId(email), ...
disp(contacts)
dictionary (string ⟼ openminds.core.actors.ContactInformation) with 4 entries:
+
When the instance is displayed, you will see all the properties that are part of the instance type, and which of those are required (Note: at the moment of writing this guide, required properties are not enforced). The display should also give information about what types are expected for each of the property values. For example, the contactInformation property requires a ContactInformation instance (as indicated by the annotation in the brackets). If you want to learn more about the types as you explore the instances, you can always press the links in the instance display and they will take you to the openMINDS documentation page for that instance.
The consortium in this example does not have contact information, but we will move on and create ContactInformation types for each of the persons:
% Create a dictionary to hold "ContactInformation" instances
for email = crewMembers.email'
contacts(email) = openminds.core.ContactInformation(...
'id', createId(email), ...
disp(contacts)
dictionary (string ⟼ openminds.core.actors.ContactInformation) with 4 entries:
"arthur-dent@hitchhikers-guide.galaxy" ⟼ [arthur-dent@hitchhikers-guide.galaxy] (ContactInformation)
"ford-prefect@hitchhikers-guide.galaxy" ⟼ [ford-prefect@hitchhikers-guide.galaxy] (ContactInformation)
"trillian-astra@hitchhikers-guide.galaxy" ⟼ [trillian-astra@hitchhikers-guide.galaxy] (ContactInformation)
- "zaphod-beeblebrox@hitchhikers-guide.galaxy" ⟼ [zaphod-beeblebrox@hitchhikers-guide.galaxy] (ContactInformation)
This gave us four ContactInformation instances. Finally we will create Person instances and attach the ContactInformation and Consortium instances:
% Extract data to create a list of "Person" instances where each "Person"
% instance will link to their respective "ContactInformation" instance and
% embed an "Affiliation" instance that links to the respective "Consortium" instance
persons = openminds.core.Person.empty;
for iRow = 1:height(crewMembers)
person = crewMembers(iRow,:);
fullName = person.givenName + " " + person.familyName;
persons(end+1) = openminds.core.Person( ...
'id', createId(fullName), ...
'givenName', person.givenName, ...
'familyName', person.familyName, ...
'alternateName', person.alternateName, ...
'contactInformation', contacts(person.email), ...
'affiliation', openminds.core.Affiliation('memberOf', consortia(person.memberOf) )); %#ok<SAGROW>
Add instances to collection and export collection
Now that we have all the instances, we can add them to the collection. It is sufficient to add the Person instances because the collection will automatically detect linked and embedded instances and add them automatically to the Nodes property.
disp(collection)
Collection with properties:
+ "zaphod-beeblebrox@hitchhikers-guide.galaxy" ⟼ [zaphod-beeblebrox@hitchhikers-guide.galaxy] (ContactInformation)
This gave us four ContactInformation instances. Finally we will create Person instances and attach the ContactInformation and Consortium instances:
% Extract data to create a list of "Person" instances where each "Person"
% instance will link to their respective "ContactInformation" instance and
% embed an "Affiliation" instance that links to the respective "Consortium" instance
persons = openminds.core.Person.empty;
for iRow = 1:height(crewMembers)
person = crewMembers(iRow,:);
fullName = person.givenName + " " + person.familyName;
persons(end+1) = openminds.core.Person( ...
'id', createId(fullName), ...
'givenName', person.givenName, ...
'familyName', person.familyName, ...
'alternateName', person.alternateName, ...
'contactInformation', contacts(person.email), ...
'affiliation', openminds.core.Affiliation('memberOf', consortia(person.memberOf) )); %#ok<SAGROW>
Add instances to collection and export collection
Now that we have all the instances, we can add them to the collection. It is sufficient to add the Person instances because the collection will automatically detect linked and embedded instances and add them automatically to the Nodes property.
disp(collection)
Collection with properties:
Name: "Crew Members"
Description: "Crew members of the 'Heart of Gold' spacecraft"
- Nodes: dictionary (string ⟼ cell) with 9 entries
As described above, we see that the Nodes hold 9 instances. We can look at the Nodes and we should expect to see 4 Person instances, 4 ContactInformation instances and 1 Consortium instance.
disp(collection.Nodes)
dictionary (string ⟼ cell) with 9 entries:
+ Nodes: dictionary (string ⟼ cell) with 9 entries
As described above, we see that the Nodes hold 9 instances. We can look at the Nodes and we should expect to see 4 Person instances, 4 ContactInformation instances and 1 Consortium instance.
disp(collection.Nodes)
dictionary (string ⟼ cell) with 9 entries:
"_:arthur-dent" ⟼ {[Dent, Arthur] (Person)}
"_:arthur-dent@hitchhikers-guide.galaxy" ⟼ {[arthur-dent@hitchhikers-guide.galaxy] (ContactInformation)}
@@ -81,7 +81,7 @@
"_:tricia-marie-mcmillan" ⟼ {[McMillan, Tricia Marie] (Person)}
"_:trillian-astra@hitchhikers-guide.galaxy" ⟼ {[trillian-astra@hitchhikers-guide.galaxy] (ContactInformation)}
"_:zaphod-beeblebrox" ⟼ {[Beeblebrox, Zaphod] (Person)}
- "_:zaphod-beeblebrox@hitchhikers-guide.galaxy" ⟼ {[zaphod-beeblebrox@hitchhikers-guide.galaxy] (ContactInformation)}
A note here: Since the collection holds a mix of different types, each type is inside a cell (as indicated by the curly brackets). In order to get an instance from the Nodes, we need to use curly bracket indexing:
person = collection.Nodes{"_:arthur-dent"}
person =
Person (https://openminds.ebrains.eu/core/Person) with properties:
+ "_:zaphod-beeblebrox@hitchhikers-guide.galaxy" ⟼ {[zaphod-beeblebrox@hitchhikers-guide.galaxy] (ContactInformation)}
A note here: Since the collection holds a mix of different types, each type is inside a cell (as indicated by the curly brackets). In order to get an instance from the Nodes, we need to index into a cell object:
if isMATLABReleaseOlderThan("R2023a")
cellValue = collection.Nodes("_:arthur-dent");
person = collection.Nodes{"_:arthur-dent"} % Curly brace syntax introduced in R2023a
end
person =
Person (https://openminds.ebrains.eu/core/Person) with properties:
affiliation: Heart of Gold Spacecraft Crew (Affiliation)
alternateName: <missing>
@@ -92,7 +92,7 @@
givenName: "Arthur"
Required Properties: givenName
-
Finally, we can save the collection
% Save the instances to the openMINDS userdata folder:
savePath = fullfile(userpath, "openMINDS_MATLAB", "demo", "crew_members.jsonld");
collection.save(savePath)
% Check out the saved metadata:
str = fileread(savePath);
Finally, we can save the collection
% Save the instances to the openMINDS userdata folder:
savePath = fullfile(userpath, "openMINDS_MATLAB", "demo", "crew_members.jsonld");
collection.save(savePath)
% Check out the saved metadata:
str = fileread(savePath);
disp(str)
{
"@context": {
"@vocab": "https://openminds.ebrains.eu/vocab/"
},
@@ -333,9 +333,14 @@
%%
% A note here: Since the collection holds a mix of different types, each type
% is inside a cell (as indicated by the curly brackets). In order to get an instance
-% from the |Nodes|, we need to use curly bracket indexing:
+% from the |Nodes|, we need to index into a cell object:
-person = collection.Nodes{"_:arthur-dent"}
+if isMATLABReleaseOlderThan("R2023a")
+ cellValue = collection.Nodes("_:arthur-dent");
+ person = cellValue{1}
+else
+ person = collection.Nodes{"_:arthur-dent"} % Curly brace syntax introduced in R2023a
+end
%%
% Finally, we can save the collection
diff --git a/docs/tutorials/crewMemberCollection.md b/docs/tutorials/crewMemberCollection.md
index e525ee55..c1bda838 100644
--- a/docs/tutorials/crewMemberCollection.md
+++ b/docs/tutorials/crewMemberCollection.md
@@ -194,10 +194,15 @@ disp(collection.Nodes)
"_:zaphod-beeblebrox@hitchhikers-guide.galaxy" ⟼ {[zaphod-beeblebrox@hitchhikers-guide.galaxy] (ContactInformation)}
```
-A note here: Since the collection holds a mix of different types, each type is inside a cell (as indicated by the curly brackets). In order to get an instance from the
Nodes, we need to use curly bracket indexing:
+A note here: Since the collection holds a mix of different types, each type is inside a cell (as indicated by the curly brackets). In order to get an instance from the
Nodes, we need to index into a cell object:
```matlab
-person = collection.Nodes{"_:arthur-dent"}
+if isMATLABReleaseOlderThan("R2023a")
+ cellValue = collection.Nodes("_:arthur-dent");
+ person = cellValue{1}
+else
+ person = collection.Nodes{"_:arthur-dent"} % Curly brace syntax introduced in R2023a
+end
```
```TextOutput
diff --git a/docs/tutorials/gettingStarted.html b/docs/tutorials/gettingStarted.html
index 7ab3194c..aa299332 100644
--- a/docs/tutorials/gettingStarted.html
+++ b/docs/tutorials/gettingStarted.html
@@ -34,8 +34,8 @@
.S7 { border-left: 1px solid rgb(217, 217, 217); border-right: 1px solid rgb(217, 217, 217); border-top: 1px solid rgb(217, 217, 217); border-bottom: 1px solid rgb(217, 217, 217); border-radius: 4px 4px 0px 0px; padding: 6px 45px 4px 13px; line-height: 18.004px; min-height: 0px; white-space: nowrap; color: rgb(33, 33, 33); font-family: Menlo, Monaco, Consolas, "Courier New", monospace; font-size: 14px; }
.S8 { border-left: 1px solid rgb(217, 217, 217); border-right: 1px solid rgb(217, 217, 217); border-top: 1px solid rgb(217, 217, 217); border-bottom: 1px solid rgb(217, 217, 217); border-radius: 4px; padding: 6px 45px 4px 13px; line-height: 18.004px; min-height: 0px; white-space: nowrap; color: rgb(33, 33, 33); font-family: Menlo, Monaco, Consolas, "Courier New", monospace; font-size: 14px; }
.S9 { border-left: 1px solid rgb(217, 217, 217); border-right: 1px solid rgb(217, 217, 217); border-top: 0px none rgb(33, 33, 33); border-bottom: 0px none rgb(33, 33, 33); border-radius: 0px; padding: 0px 45px 0px 13px; line-height: 18.004px; min-height: 0px; white-space: nowrap; color: rgb(33, 33, 33); font-family: Menlo, Monaco, Consolas, "Courier New", monospace; font-size: 14px; }
-.S10 { border-left: 1px solid rgb(217, 217, 217); border-right: 1px solid rgb(217, 217, 217); border-top: 1px solid rgb(217, 217, 217); border-bottom: 0px none rgb(33, 33, 33); border-radius: 0px; padding: 6px 45px 0px 13px; line-height: 18.004px; min-height: 0px; white-space: nowrap; color: rgb(33, 33, 33); font-family: Menlo, Monaco, Consolas, "Courier New", monospace; font-size: 14px; }
Before you start
% Verify that openMINDS_MATLAB is installed
disp( openminds.toolboxversion )
If you have installed openMINDS_MATLAB and the above command does not work, most likely openMINDS_MATLAB is not added to MATLAB's search path. If you opened this file in MATLAB Online from the GitHub Demo link, the following steps should add openMINDS_MATLAB to the search path:
1) Open the code folder from the Files panel on the left sidebar.
2) Open and run the startup.m file. Select "Add to Path" if prompted from a popup dialog.
Configure MATLAB's search path to use the latest model versions
Note: The following is only relevant if you have cloned or downloaded openMINDS_MATLAB from GitHub. If you installed the Matlab toolbox, you can skip this part.
The openMINDS_MATLAB toolbox comes packaged with schema classes for all versions of the openMINDS models. Therefore is important to use the openminds.startup function to ensure that the search path only contains schema classes for a specific openMINDS version. Provide the version number as an input, i.e "latest", or "v2.0" openminds.startup("latest") % Add schema classes for the latest version to the search path
Initializing openMINDS_MATLAB...
-Added schemas for version "latest" to path
Import schemas from the core model
Create a Subject
% Create a new demo subject
subject1 = Subject('species', 'musMusculus', 'biologicalSex', 'male', 'lookupLabel', 'demo_subject1');
disp(subject1)
Subject (https://openminds.ebrains.eu/core/Subject) with properties:
+.S10 { border-left: 1px solid rgb(217, 217, 217); border-right: 1px solid rgb(217, 217, 217); border-top: 1px solid rgb(217, 217, 217); border-bottom: 0px none rgb(33, 33, 33); border-radius: 0px; padding: 6px 45px 0px 13px; line-height: 18.004px; min-height: 0px; white-space: nowrap; color: rgb(33, 33, 33); font-family: Menlo, Monaco, Consolas, "Courier New", monospace; font-size: 14px; }
Before you start
% Verify that openMINDS_MATLAB is installed
disp( openminds.toolboxversion )
If you have installed openMINDS_MATLAB and the above command does not work, most likely openMINDS_MATLAB is not added to MATLAB's search path. If you opened this file in MATLAB Online from the GitHub Demo link, the following steps should add openMINDS_MATLAB to the search path:
1) Open the code folder from the Files panel on the left sidebar.
2) Open and run the startup.m file. Select "Add to Path" if prompted from a popup dialog.
Configure MATLAB's search path to use the latest model versions
Note: The following is only relevant if you have cloned or downloaded openMINDS_MATLAB from GitHub. If you installed the Matlab toolbox, you can skip this part.
The openMINDS_MATLAB toolbox comes packaged with schema classes for all versions of the openMINDS models. Therefore is important to use the openminds.startup function to ensure that the search path only contains schema classes for a specific openMINDS version. Provide the version number as an input, i.e "latest", or "v2.0" openminds.startup("latest") % Add schema classes for the latest version to the search path
Initializing openMINDS_MATLAB...
+Added schemas for version "latest" to path
Import schemas from the core model
Create a Subject
% Create a new demo subject
subject1 = Subject('species', 'musMusculus', 'biologicalSex', 'male', 'lookupLabel', 'demo_subject1');
disp(subject1)
Subject (https://openminds.ebrains.eu/core/Subject) with properties:
biologicalSex: male (BiologicalSex)
internalIdentifier: ""
@@ -44,7 +44,7 @@
species: Mus musculus (One of: Species, Strain)
studiedState: [None] (SubjectState)
- Required Properties: species, studiedState
Create a Subject State
subjectState = openminds.core.SubjectState('lookupLabel', 'demo_state')
subjectState =
SubjectState (https://openminds.ebrains.eu/core/SubjectState) with properties:
+ Required Properties: species, studiedState
Create a Subject State
subjectState = openminds.core.SubjectState('lookupLabel', 'demo_state')
subjectState =
SubjectState (https://openminds.ebrains.eu/core/SubjectState) with properties:
additionalRemarks: ""
age: [None] (One of: QuantitativeValue, QuantitativeValueRange)
@@ -59,7 +59,7 @@
weight: [None] (One of: QuantitativeValue, QuantitativeValueRange)
Required Properties: ageCategory
-
% Add subject state to subject
subject1.studiedState = subjectState;
disp(subject1)
Subject (https://openminds.ebrains.eu/core/Subject) with properties:
+
% Add subject state to subject
subject1.studiedState = subjectState;
disp(subject1)
Subject (https://openminds.ebrains.eu/core/Subject) with properties:
biologicalSex: male (BiologicalSex)
internalIdentifier: ""
@@ -68,7 +68,7 @@
species: Mus musculus (One of: Species, Strain)
studiedState: demo_state (SubjectState)
- Required Properties: species, studiedState
% Update the value of the lookup label
subjectState.lookupLabel = "demo_subjectstate_pre_recording";
% Create a new subject state
subjectStatePost = openminds.core.SubjectState('lookupLabel', 'demo_subjectstate_post_recording')
subjectStatePost =
SubjectState (https://openminds.ebrains.eu/core/SubjectState) with properties:
+ Required Properties: species, studiedState
% Update the value of the lookup label
subjectState.lookupLabel = "demo_subjectstate_pre_recording";
% Create a new subject state
subjectStatePost = openminds.core.SubjectState('lookupLabel', 'demo_subjectstate_post_recording')
subjectStatePost =
SubjectState (https://openminds.ebrains.eu/core/SubjectState) with properties:
additionalRemarks: ""
age: [None] (One of: QuantitativeValue, QuantitativeValueRange)
@@ -83,7 +83,7 @@
weight: [None] (One of: QuantitativeValue, QuantitativeValueRange)
Required Properties: ageCategory
-
% Append the new subject state to the subject's studiedState property
subject1.studiedState(end+1) = subjectStatePost;
disp(subject1)
Subject (https://openminds.ebrains.eu/core/Subject) with properties:
+
% Append the new subject state to the subject's studiedState property
subject1.studiedState(end+1) = subjectStatePost;
disp(subject1)
Subject (https://openminds.ebrains.eu/core/Subject) with properties:
biologicalSex: male (BiologicalSex)
internalIdentifier: ""