Skip to content

Commit

Permalink
Merge pull request #188 from the-virtual-brain/TVB-2731
Browse files Browse the repository at this point in the history
TVB-2731: REST API - provide extra information for various TS analysis results
  • Loading branch information
bogdanvalean1 authored Sep 9, 2020
2 parents 4e53cbb + e810bf5 commit a3b3aa0
Show file tree
Hide file tree
Showing 15 changed files with 121 additions and 4 deletions.
6 changes: 6 additions & 0 deletions framework_tvb/tvb/adapters/datatypes/db/fcd.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ class FcdIndex(DataTypeMatrix):

labels_ordering = Column(String)

def get_extra_info(self):
labels_dict = {}
labels_dict["labels_ordering"] = self.source.labels_ordering
labels_dict["labels_dimensions"] = self.source.labels_dimensions
return labels_dict

def fill_from_has_traits(self, datatype):
# type: (Fcd) -> None
super(FcdIndex, self).fill_from_has_traits(datatype)
Expand Down
6 changes: 6 additions & 0 deletions framework_tvb/tvb/adapters/datatypes/db/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ class CorrelationCoefficientsIndex(DataTypeMatrix):

labels_ordering = Column(String)

def get_extra_info(self):
labels_dict = {}
labels_dict["labels_ordering"] = self.source.labels_ordering
labels_dict["labels_dimensions"] = self.source.labels_dimensions
return labels_dict

def fill_from_has_traits(self, datatype):
# type: (CorrelationCoefficients) -> None
super(CorrelationCoefficientsIndex, self).fill_from_has_traits(datatype)
Expand Down
12 changes: 12 additions & 0 deletions framework_tvb/tvb/adapters/datatypes/db/mode_decompositions.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ def fill_from_has_traits(self, datatype):
super(PrincipalComponentsIndex, self).fill_from_has_traits(datatype)
self.fk_source_gid = datatype.source.gid

def get_extra_info(self):
labels_dict = {}
labels_dict["labels_ordering"] = self.source.labels_ordering
labels_dict["labels_dimensions"] = self.source.labels_dimensions
return labels_dict


class IndependentComponentsIndex(DataType):
id = Column(Integer, ForeignKey(DataType.id), primary_key=True)
Expand All @@ -70,6 +76,12 @@ def fill_from_has_traits(self, datatype):
self.ndim = len(datatype.unmixing_matrix.shape)
self.array_has_complex = numpy.iscomplex(datatype.unmixing_matrix).any().item()

def get_extra_info(self):
labels_dict = {}
labels_dict["labels_ordering"] = self.source.labels_ordering
labels_dict["labels_dimensions"] = self.source.labels_dimensions
return labels_dict

@property
def parsed_shape(self):
try:
Expand Down
24 changes: 24 additions & 0 deletions framework_tvb/tvb/adapters/datatypes/db/spectral.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ def fill_from_has_traits(self, datatype):
self.max_frequency = datatype.max_frequency
self.fk_source_gid = datatype.source.gid.hex

def get_extra_info(self):
labels_dict = {}
labels_dict["labels_ordering"] = self.source.labels_ordering
labels_dict["labels_dimensions"] = self.source.labels_dimensions
return labels_dict


class WaveletCoefficientsIndex(DataTypeMatrix):
id = Column(Integer, ForeignKey(DataTypeMatrix.id), primary_key=True)
Expand Down Expand Up @@ -83,6 +89,12 @@ def fill_from_has_traits(self, datatype):
self.frequencies_min, self.frequencies_max, _ = from_ndarray(datatype.frequencies)
self.fk_source_gid = datatype.source.gid.hex

def get_extra_info(self):
labels_dict = {}
labels_dict["labels_ordering"] = self.source.labels_ordering
labels_dict["labels_dimensions"] = self.source.labels_dimensions
return labels_dict


class CoherenceSpectrumIndex(DataTypeMatrix):
id = Column(Integer, ForeignKey(DataTypeMatrix.id), primary_key=True)
Expand All @@ -101,6 +113,12 @@ def fill_from_has_traits(self, datatype):
self.frequencies_min, self.frequencies_max, _ = from_ndarray(datatype.frequency)
self.fk_source_gid = datatype.source.gid.hex

def get_extra_info(self):
labels_dict = {}
labels_dict["labels_ordering"] = self.source.labels_ordering
labels_dict["labels_dimensions"] = self.source.labels_dimensions
return labels_dict


class ComplexCoherenceSpectrumIndex(DataTypeMatrix):
id = Column(Integer, ForeignKey(DataTypeMatrix.id), primary_key=True)
Expand All @@ -124,3 +142,9 @@ def fill_from_has_traits(self, datatype):
self.frequency_step = datatype.freq_step
self.max_frequency = datatype.max_freq
self.fk_source_gid = datatype.source.gid.hex

def get_extra_info(self):
labels_dict = {}
labels_dict["labels_ordering"] = self.source.labels_ordering
labels_dict["labels_dimensions"] = self.source.labels_dimensions
return labels_dict
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ class CrossCorrelationIndex(DataTypeMatrix):

labels_ordering = Column(String, nullable=False)

def get_extra_info(self):
labels_dict = {}
labels_dict["labels_ordering"] = self.source.labels_ordering
labels_dict["labels_dimensions"] = self.source.labels_dimensions
return labels_dict

def fill_from_has_traits(self, datatype):
# type: (CrossCorrelation) -> None
super(CrossCorrelationIndex, self).fill_from_has_traits(datatype)
Expand Down
6 changes: 6 additions & 0 deletions framework_tvb/tvb/adapters/datatypes/db/time_series.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ class TimeSeriesIndex(DataType):
has_volume_mapping = Column(Boolean, nullable=False, default=False)
has_surface_mapping = Column(Boolean, nullable=False, default=False)

def get_extra_info(self):
labels_dict = {}
labels_dict["labels_ordering"] = self.labels_ordering
labels_dict["labels_dimensions"] = self.labels_dimensions
return labels_dict

def fill_from_has_traits(self, datatype):
# type: (TimeSeries) -> None
super(TimeSeriesIndex, self).fill_from_has_traits(datatype)
Expand Down
3 changes: 3 additions & 0 deletions framework_tvb/tvb/core/entities/model/model_datatype.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ class DataType(HasTraitsIndex):
# Transient info
fixed_generic_attributes = False

def get_extra_info(self):
return {}

def __init__(self, gid=None, **kwargs):

self.gid = gid
Expand Down
8 changes: 7 additions & 1 deletion framework_tvb/tvb/core/entities/storage/datatype_dao.py
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,11 @@ def get_datatype_details(self, datatype_gid):
return result_dt


def get_datatype_by_gid(self, gid, load_lazy=True):
def get_datatype_extra_info(self, datatype_gid):
datatype = self.get_datatype_by_gid(datatype_gid, False, True)
return datatype.get_extra_info()

def get_datatype_by_gid(self, gid, load_lazy=True, load_lazy_extra_info=False):
"""
Retrieve a DataType DB reference by a global identifier.
"""
Expand All @@ -393,6 +397,8 @@ def get_datatype_by_gid(self, gid, load_lazy=True):
result_dt.parent_operation.algorithm.algorithm_category
result_dt.parent_operation.operation_group
result_dt._parent_burst
if load_lazy_extra_info:
result_dt.get_extra_info()

return result_dt
except NoResultFound as excep:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ def get_operations_for_datatype(self, datatype_gid):
})))
return response, AlgorithmDto

@handle_response
def get_extra_info(self, datatype_gid):
response = self.secured_request().get(
self.build_request_url(RestLink.DATATYPE_EXTRA_INFO.compute_url(True, {
LinkPlaceholder.DATATYPE_GID.value: datatype_gid
})))
return response, dict

def load_datatype_from_file(self, datatype_path):
datatype, _ = h5.load_with_links(datatype_path)
return datatype
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,17 @@ def fire_simulation_example(tvb_client_instance):
operation_gid = tvb_client_instance.launch_operation(project_gid, FourierAdapter, fourier_model)
logger.info("Fourier Analyzer operation has launched with gid {}".format(operation_gid))

data_in_project = tvb_client_instance.get_data_in_project(project_gid)
logger.info("We have {} datatypes".format(len(data_in_project)))
ggid = None
for datatype in data_in_project:
if datatype.type == 'FourierSpectrum':
ggid = datatype.gid
break

extra_info = tvb_client_instance.get_extra_info(ggid)
logger.info("The extra information for Fourier {}".format(extra_info))

logger.info("Download the connectivity file...")
connectivity_path = tvb_client_instance.retrieve_datatype(connectivity_gid, tvb_client_instance.temp_folder)
logger.info("The connectivity file location is: {}".format(connectivity_path))
Expand Down
6 changes: 6 additions & 0 deletions framework_tvb/tvb/interfaces/rest/client/tvb_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,3 +237,9 @@ def get_operation_results(self, operation_gid):
operation if it has finished and an empty list, if the operation is still running, has failed or simply has no results.
"""
return self.operation_api.get_operations_results(operation_gid)

def get_extra_info(self, datatype_gid):
"""
Given an datatype gid, this function returns a dict containing the extra information of the datatype.
"""
return self.datatype_api.get_extra_info(datatype_gid)
3 changes: 2 additions & 1 deletion framework_tvb/tvb/interfaces/rest/commons/strings.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ class RestLink(Enum):
# DATATYPES
GET_DATATYPE = "/{" + LinkPlaceholder.DATATYPE_GID.value + "}"
DATATYPE_OPERATIONS = "/{" + LinkPlaceholder.DATATYPE_GID.value + "}/operations"
DATATYPE_EXTRA_INFO = "/{" + LinkPlaceholder.DATATYPE_GID.value + "}/extra_info"

# OPERATIONS
LAUNCH_OPERATION = "/{" + LinkPlaceholder.PROJECT_GID.value + "}/algorithm/{" + LinkPlaceholder.ALG_MODULE.value + "}/{" + LinkPlaceholder.ALG_CLASSNAME.value + "}"
Expand All @@ -111,7 +112,7 @@ def compute_url(self, include_namespace=False, values=None):
_namespace_url_dict = {
RestNamespace.USERS: [RestLink.LOGIN, RestLink.PROJECTS, RestLink.USEFUL_URLS],
RestNamespace.PROJECTS: [RestLink.DATA_IN_PROJECT, RestLink.OPERATIONS_IN_PROJECT, RestLink.PROJECT_MEMBERS],
RestNamespace.DATATYPES: [RestLink.GET_DATATYPE, RestLink.DATATYPE_OPERATIONS],
RestNamespace.DATATYPES: [RestLink.GET_DATATYPE, RestLink.DATATYPE_OPERATIONS, RestLink.DATATYPE_EXTRA_INFO],
RestNamespace.OPERATIONS: [RestLink.LAUNCH_OPERATION, RestLink.OPERATION_STATUS, RestLink.OPERATION_RESULTS],
RestNamespace.SIMULATION: [RestLink.FIRE_SIMULATION]
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
from tvb.core.entities.storage import dao
from tvb.core.neocom.h5 import h5_file_for_index
from tvb.core.services.algorithm_service import AlgorithmService
from tvb.interfaces.rest.commons.dtos import AlgorithmDto
from tvb.interfaces.rest.commons.dtos import AlgorithmDto, DataTypeDto


class DatatypeFacade:
Expand All @@ -49,3 +49,11 @@ def get_datatype_operations(self, datatype_gid):
datatype = dao.get_datatype_by_gid(datatype_gid)
_, filtered_adapters, _ = self.algorithm_service.get_launchable_algorithms_for_datatype(datatype, categories)
return [AlgorithmDto(algorithm) for algorithm in filtered_adapters]

@staticmethod
def get_extra_info(datatype_gid):
extra_info = dao.get_datatype_extra_info(datatype_gid)
if extra_info is None:
return None

return extra_info
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,18 @@ def get(self, datatype_gid):
file_name = os.path.basename(h5_file_path)
return flask.send_file(h5_file_path, as_attachment=True, attachment_filename=file_name)

class GetExtraInfoForDatatypeResource(RestResource):

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.datatypes_facade = DatatypeFacade()

@check_permission(DataTypeAccessPermission, 'datatype_gid')
def get(self, datatype_gid):
"""
:return the results of DataType.
"""
return self.datatypes_facade.get_extra_info(datatype_gid)

class GetOperationsForDatatypeResource(RestResource):

Expand Down
4 changes: 3 additions & 1 deletion framework_tvb/tvb/interfaces/rest/server/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
from tvb.interfaces.rest.commons.strings import RestNamespace, RestLink, LinkPlaceholder, Strings
from tvb.interfaces.rest.server.decorators.encoders import CustomFlaskEncoder
from tvb.interfaces.rest.server.resources.datatype.datatype_resource import RetrieveDatatypeResource, \
GetOperationsForDatatypeResource
GetOperationsForDatatypeResource, GetExtraInfoForDatatypeResource
from tvb.interfaces.rest.server.resources.operation.operation_resource import GetOperationStatusResource, \
GetOperationResultsResource, LaunchOperationResource
from tvb.interfaces.rest.server.resources.project.project_resource import GetOperationsInProjectResource, \
Expand Down Expand Up @@ -110,6 +110,8 @@ def initialize_flask():
values={LinkPlaceholder.DATATYPE_GID.value: '<string:datatype_gid>'}))
name_space_datatypes.add_resource(GetOperationsForDatatypeResource, RestLink.DATATYPE_OPERATIONS.compute_url(
values={LinkPlaceholder.DATATYPE_GID.value: '<string:datatype_gid>'}))
name_space_datatypes.add_resource(GetExtraInfoForDatatypeResource, RestLink.DATATYPE_EXTRA_INFO.compute_url(
values={LinkPlaceholder.DATATYPE_GID.value: '<string:datatype_gid>'}))

# Operations namespace
name_space_operations = api.namespace(build_path(RestNamespace.OPERATIONS),
Expand Down

0 comments on commit a3b3aa0

Please sign in to comment.