Skip to content

Commit

Permalink
working walkthrough
Browse files Browse the repository at this point in the history
  • Loading branch information
valentin-pinkau committed Dec 10, 2024
1 parent 97ea54f commit 1d8d6f3
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 154 deletions.
97 changes: 70 additions & 27 deletions +siibra/+internal/API.m
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@
% The API class holds all the api calls in one place

properties (Constant=true)
Endpoint = "https://siibra-api-stable.apps.hbp.eu/v1_0/"
EndpointV2 = "https://siibra-api-stable.apps.hbp.eu/v2_0"
EndpointV3 = "https://siibra-api-stable.apps.hbp.eu/v3_0"
%Endpoint = "https://siibra-api-stable.apps.hbp.eu/v1_0/"
%EndpointV2 = "https://siibra-api-stable.apps.hbp.eu/v2_0"
EndpointV3 = "https://siibra-api-stable.apps.hbp.eu/v3_0/"
%EndpointV3 = "https://siibra-api-prod.apps.tc.humanbrainproject.eu/v3_0/"
end

methods (Static)
function link = absoluteLink(relativeLink)
link = siibra.internal.API.Endpoint + relativeLink;
end
function link = absoluteLinkV2(relativeLink)
link = siibra.internal.API.EndpointV2 + relativeLink;
end
%function link = absoluteLink(relativeLink)
% link = siibra.internal.API.Endpoint + relativeLink;
%end
%function link = absoluteLinkV2(relativeLink)
% link = siibra.internal.API.EndpointV2 + relativeLink;
%end
function link = absoluteLinkV3(relativeLink)
link = siibra.internal.API.EndpointV3 + relativeLink;
end
Expand All @@ -32,21 +33,63 @@
absoluteLink, ...
options);
end
function atlases = atlases()
absoluteLink = siibra.internal.API.absoluteLink("atlases");
atlases = siibra.internal.API.doWebreadWithLongTimeout( ...

function parameterString = parametersToString(parameters)
parameterString = "?" + strjoin(parameters, "&");
end

function items = collectItemsAcrossPages(absoluteLink, parameters)
if nargin < 2
parameters = [];
end

first_result = siibra.internal.API.doWebreadWithLongTimeout(absoluteLink + ...
siibra.internal.API.parametersToString([parameters, "page=1"]));
items = first_result.items;
page = first_result.page;
pages = first_result.pages;
while page < pages
page = page + 1;
next_result = siibra.internal.API.doWebreadWithLongTimeout(absoluteLink ...
+ siibra.internal.API.parametersToString([parameters, "page=" + page]));
items = [items; next_result.items];
end

end

function atlasJsons = atlases()
absoluteLink = siibra.internal.API.absoluteLinkV3("atlases");
atlasJsons = siibra.internal.API.collectItemsAcrossPages( ...
absoluteLink);
end
function absoluteLink = regionInfoForSpace(atlasId, parcellationId, regionName, spaceId)
relativeLink = "atlases/" + atlasId + ...
"/parcellations/" + parcellationId + ...
"/regions/" + regionName + ...
"?space_id=" + spaceId;
absoluteLink = siibra.internal.API.absoluteLink(relativeLink);

function spaceJson = space(spaceId)
absoluteLink = siibra.internal.API.absoluteLinkV3("spaces/" + spaceId);
spaceJson = siibra.internal.API.doWebreadWithLongTimeout(absoluteLink);
end

function parcellationJson = parcellation(parcellationId)
absoluteLink = siibra.internal.API.absoluteLinkV3("parcellations/" + parcellationId);
parcellationJson = siibra.internal.API.doWebreadWithLongTimeout(absoluteLink);
end

function regionsJson = regions(parcellationId)
absoluteLink = siibra.internal.API.absoluteLinkV3("regions");
parameters = ["parcellation_id=" + parcellationId];
regionsJson = siibra.internal.API.collectItemsAcrossPages( ...
absoluteLink, parameters);
end

function absoluteLink = regionInfoForSpace(parcellationId, regionName, spaceId)
relativeLink = "map/statistical_map.info.json" + ...
"?parcellation_id=" + parcellationId + ...
"&region_id=" + regionName + ...
"&space_id=" + spaceId;
absoluteLink = siibra.internal.API.absoluteLinkV3(relativeLink);
end

function absoluteLink = regionMap(parcellationId, regionName, spaceId)
relativeLink = "/map/statistical_map.nii.gz" + ...
relativeLink = "map/statistical_map.nii.gz" + ...
"?parcellation_id=" + parcellationId + ...
"&space_id=" + spaceId + ...
"&region_id=" + regionName;
Expand All @@ -59,26 +102,26 @@
parcellationId string
regionName string = string.empty
end
relativeLink = "/map/labelled_map.nii.gz?parcellation_id=" + parcellationId + ...
relativeLink = "map/labelled_map.nii.gz?parcellation_id=" + parcellationId + ...
"&space_id=" + spaceId;
if ~isempty(regionName)
relativeLink = relativeLink + "&region_id=" + regionName;
end
absoluteLink = siibra.internal.API.absoluteLinkV3(relativeLink);
end

function absoluteLink = templateForParcellationMap(spaceId, parcellationId)
function absoluteLink = templateForParcellationMap(parcellationId, spaceId)
arguments
spaceId string
parcellationId string
spaceId string
end
relativeLink = "/map/resampled_template?parcellation_id=" + parcellationId + ...
relativeLink = "map/resampled_template?parcellation_id=" + parcellationId + ...
"&space_id=" + spaceId;
absoluteLink = siibra.internal.API.absoluteLinkV3(relativeLink);
end

function absoluteLink = featuresPageForParcellation(atlasId, parcellationId, page, size)
relativeLink = "/atlases/" + atlasId + ...
relativeLink = "atlases/" + atlasId + ...
"/parcellations/" + parcellationId + ...
"/features?page=" + page + ...
"&size=" + size;
Expand Down Expand Up @@ -114,19 +157,19 @@
end
function absoluteLink = parcellationFeature(atlasId, parcellationId, featureId)
% get specific feature by feature id.
relativeLink = "/atlases/" + atlasId + ...
relativeLink = "atlases/" + atlasId + ...
"/parcellations/" + parcellationId + ...
"/features/" + featureId;
absoluteLink = siibra.internal.API.absoluteLinkV2(relativeLink);
end
function absoluteLink = featuresForRegion(atlasId, parcellationId, regionName)
relativeLink = "/atlases/" +atlasId + ...
relativeLink = "atlases/" +atlasId + ...
"/parcellations/" + parcellationId + ...
"/regions/" + regionName + "/features";
absoluteLink = siibra.internal.API.absoluteLinkV2(relativeLink);
end
function absoluteLink = regionFeature(atlasId, parcellationId, regionName, featureId)
relativeLink = "/atlases/" +atlasId + ...
relativeLink = "atlases/" +atlasId + ...
"/parcellations/" + parcellationId + ...
"/regions/" + regionName + ...
"/features/" + featureId;
Expand Down
31 changes: 0 additions & 31 deletions +siibra/+items/+maps/ContinuousRegionMap.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,37 +16,6 @@
function obj = ContinuousRegionMap(region, space)
obj.Region = region;
obj.Space = space;
regionMapInfoJson = siibra.internal.API.doWebreadWithLongTimeout( ...
siibra.internal.API.regionInfoForSpace( ...
obj.Region.Parcellation.Atlas.Id, ...
obj.Region.Parcellation.Id, ...
obj.Region.Name, ...
obj.Space.Id ...
) ...
);
if ~regionMapInfoJson.hasRegionalMap
error('StatisticalMap:NotFound', "Region " + region.Name + " has no statistical map!")
end
datasetSpecs = regionMapInfoJson.x_dataset_specs;
if ~iscell(datasetSpecs)
datasetSpecs = num2cell(datasetSpecs);
end
datasetIndex = find( ...
cell2mat( ...
cellfun( ...
@(dataset) ...
isequal(dataset.x_type, 'minds/core/dataset/v1.0.0'), ...
datasetSpecs, ...
'UniformOutput', false)));
if isempty(datasetIndex)
obj.Name = "Not available";
obj.Description = "Not available";
obj.DOI = string.empty;
else
obj.Name = datasetSpecs{datasetIndex}.name;
obj.Description = datasetSpecs{datasetIndex}.description;
obj.DOI = datasetSpecs{datasetIndex}.urls.doi;
end
end

function cachePath = get.CachePath(obj)
Expand Down
8 changes: 3 additions & 5 deletions +siibra/+items/Atlas.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,14 @@
end
methods
function atlas = Atlas(atlasJson)
atlas.Id = atlasJson.id;
atlas.Id = atlasJson.x_id;
atlas.Name = atlasJson.name;

% Spaces
spacesJson = webread(atlasJson.links.spaces.href);
atlas.Spaces = arrayfun(@(j) siibra.items.Space(j, atlas.Name), spacesJson);
atlas.Spaces = arrayfun(@(spaceRef) siibra.items.Space(siibra.internal.API.space(spaceRef.x_id), atlas.Name), atlasJson.spaces);

% Parcellations
parcellationsJson = webread(atlasJson.links.parcellations.href);
atlas.Parcellations = arrayfun(@(json) siibra.items.Parcellation(json, atlas), parcellationsJson);
atlas.Parcellations = arrayfun(@(parcellationRef) siibra.items.Parcellation(siibra.internal.API.parcellation(parcellationRef.x_id), atlas), atlasJson.parcellations);

end
function parcellation = getParcellation(obj, parcellationNameQuery)
Expand Down
63 changes: 35 additions & 28 deletions +siibra/+items/Parcellation.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@
Modality (1, 1) string
Description (1, 1) string
RegionTree (1, 1) digraph
Regions (1, :) siibra.items.Region
Spaces (1, :) siibra.items.Space
end

methods
function parcellation = Parcellation(parcellationJson, atlas)
parcellation.Id = strcat(parcellationJson.id.kg.kgSchema, '/', parcellationJson.id.kg.kgId);
parcellation.Id = parcellationJson.x_id;
parcellation.Name = parcellationJson.name;
parcellation.Atlas = atlas;

Expand All @@ -24,53 +25,59 @@
parcellation.Modality = parcellationJson.modality;
end

% some parcellations do have a description
if ~ isempty(parcellationJson.infos)
parcellation.Description = parcellationJson.infos(1).description;
spaceIds = arrayfun(@(atlasVersion) atlasVersion.coordinateSpace, parcellationJson.brainAtlasVersions);
spaces = arrayfun(@(spaceId) atlas.Spaces([atlas.Spaces.Id] == spaceId.x_id), spaceIds);
if isempty(spaces)
parcellation.Spaces = siibra.items.Space.empty();
else
parcellation.Spaces = spaces;
end

% link spaces from atlas
parcellation.Spaces = siibra.items.Space.empty;
% retrieve available spaces from atlas
for idx = 1:numel(parcellationJson.availableSpaces)
% store handle to space object
for atlasSpaceIndex = 1:numel(atlas.Spaces)
if isequal(atlas.Spaces(atlasSpaceIndex).Id, parcellationJson.availableSpaces(idx).id)
parcellation.Spaces(end +1) = atlas.Spaces(atlasSpaceIndex);
end

regionsJson = siibra.internal.API.regions(parcellation.Id);
function result = getSrc(regionJson)
if isempty(regionJson.hasParent)
result = regionJson.x_id;
else
result = regionJson.hasParent.x_id;
end

end

% call api to get parcellation tree
regions = webread(parcellationJson.links.regions.href);

% the api returns the same regions multiple times. so we filter
% them here.
[~, uniqueRegionIndices, ~] = unique({regionsJson.x_id});
parcellation.Regions = arrayfun(@(regionJson) siibra.items.Region(regionJson.x_id, regionJson.name, parcellation), regionsJson(uniqueRegionIndices));
srcIds = arrayfun(@(regionJson) getSrc(regionJson), regionsJson(uniqueRegionIndices), "UniformOutput",false);
regionIds = [parcellation.Regions.Id];
src = arrayfun(@(srcId) find(regionIds == srcId), srcIds);
dst = 1:numel(src);

nodeTable = table([parcellation.Regions.Id].', [parcellation.Regions.Name].', parcellation.Regions.', 'VariableNames', ["Name", "RegionName", "Region"]);
% store graph
parcellation.RegionTree = siibra.items.Parcellation.createParcellationTree(parcellation, regions);
parcellation.RegionTree = digraph(src, dst, zeros(length(src), 1), nodeTable);
end

function map = parcellationMap(obj, spaceName)
idx = siibra.internal.fuzzyMatching(spaceName, [obj.Spaces.Name]);
map = siibra.items.maps.ParcellationMap(obj, obj.Spaces(idx));
function map = parcellationMap(obj, space)
map = siibra.items.maps.ParcellationMap(obj, space);
end

function regionNames = findRegion(obj, regionNameQuery)
regionNames = obj.RegionTree.Nodes(contains(obj.RegionTree.Nodes.Name, regionNameQuery), 1);
regionNames = obj.RegionTree.Nodes(contains(obj.RegionTree.Nodes.RegionName, regionNameQuery), 2);
end
function region = decodeRegion(obj, regionNameQuery)
index = siibra.internal.fuzzyMatching(regionNameQuery, [obj.RegionTree.Nodes.Name]);
index = siibra.internal.fuzzyMatching(regionNameQuery, [obj.RegionTree.Nodes.RegionName]);
region = obj.RegionTree.Nodes.Region(index);
end
function region = getRegion(obj, regionNameQuery)
nodeId = obj.RegionTree.findnode(regionNameQuery);
region = obj.RegionTree.Nodes.Region(nodeId);
end
function children = getChildRegions(obj, regionName)
nodeId = obj.RegionTree.findnode(regionName);
function children = getChildRegions(obj, region)
nodeId = obj.RegionTree.findnode(region.Id);
childrenIds = obj.RegionTree.successors(nodeId);
children = obj.RegionTree.Nodes.Region(childrenIds);
end
function parentRegion = getParentRegion(obj, regionName)
nodeId = obj.RegionTree.findnode(regionName);
function parentRegion = getParentRegion(obj, region)
nodeId = obj.RegionTree.findnode(region.Id);
parents = obj.RegionTree.predecessors(nodeId);
assert(length(parents) == 1, "Expect just one parent in a tree structure");
parentId = parents(1);
Expand Down
Loading

0 comments on commit 1d8d6f3

Please sign in to comment.