diff --git a/app/controllers/geneInteraction.py b/app/controllers/geneInteraction.py index 5e29257..c5b4f16 100644 --- a/app/controllers/geneInteraction.py +++ b/app/controllers/geneInteraction.py @@ -1,7 +1,7 @@ import sqlalchemy as sa import os from flask import jsonify -from sqlalchemy import desc, or_, and_ +from sqlalchemy import desc, literal_column, or_, and_ from sqlalchemy.sql import text from app.controllers.dataset import _dataset_query import app.models as models @@ -1017,7 +1017,7 @@ def getGeneCounts(dataset_ID: int = None, disease_name=None, ensg_number=None, g def get_gene_network(dataset_ID: int = None, disease_name=None, minBetweenness:float = None, minNodeDegree:float = None, minEigenvector:float = None, maxPValue=0.05, minMscor=None, minCorrelation=None, - edgeSorting: str = None, nodeSorting: str = None, + edgeSorting: str = None, nodeSorting: list[str] = None, maxNodes: int = 100, maxEdges: int = 100, offsetNodes: int = None, offsetEdges: int = None, sponge_db_version: int = LATEST): @@ -1032,7 +1032,7 @@ def get_gene_network(dataset_ID: int = None, disease_name=None, :param minMscor: mscor cutoff (>) :param minCorrelation: correlation cutoff (>) :param edgeSorting: sorting key for edges - :param nodeSorting: sorting key for nodes + :param nodeSorting: sorting key(s) for nodes (options are 'betweenness', 'degree', 'eigenvector') :param maxNodes: maximum number of nodes :param maxEdges: maximum number of edges :param offsetNodes: offset for node pagination @@ -1080,17 +1080,15 @@ def get_gene_network(dataset_ID: int = None, disease_name=None, if minEigenvector: node_query = node_query.filter(models.networkAnalysis.eigenvector >= minEigenvector) - # Sorting nodes - if nodeSorting == "betweenness": - node_query = node_query.order_by(models.networkAnalysis.betweenness.desc()) - elif nodeSorting == "degree": - node_query = node_query.order_by(models.networkAnalysis.node_degree.desc()) - elif nodeSorting == "eigenvector": - node_query = node_query.order_by(models.networkAnalysis.eigenvector.desc()) - else: - raise ValueError("Invalid node sorting key. Choose one of 'betweenness', 'degree', 'eigenvector'") + # Sorting nodes: if more than one sorting key, rank by each key individually and sort by the mean of the ranks + if nodeSorting: + if any([key not in ['betweenness', 'node_degree', 'eigenvector'] for key in nodeSorting]): + raise ValueError("Invalid node sorting key. Choose from 'betweenness', 'node_degree', 'eigenvector'") + rank_columns = [db.func.rank().over(order_by=getattr(models.networkAnalysis, col).desc()).label(f"{col}_rank") for col in nodeSorting] + mean_rank = sum(rank_columns) / len(rank_columns) + node_query = node_query.order_by(mean_rank) - # node agination + # node pagination node_query = node_query.offset(offsetNodes).limit(maxNodes) # filter edges based on filtered nodes diff --git a/app/controllers/transcriptInteraction.py b/app/controllers/transcriptInteraction.py index 45cf5de..444193e 100644 --- a/app/controllers/transcriptInteraction.py +++ b/app/controllers/transcriptInteraction.py @@ -845,7 +845,7 @@ def getTranscriptCounts(dataset_ID: int = None, disease_name=None, enst_number=N def get_transcript_network(dataset_ID: int = None, disease_name=None, minBetweenness:float = None, minNodeDegree:float = None, minEigenvector:float = None, maxPValue=0.05, minMscor=None, minCorrelation=None, - edgeSorting: str = None, nodeSorting: str = None, + edgeSorting: str = None, nodeSorting: list[str] = None, maxNodes: int = 100, maxEdges: int = 100, offsetNodes: int = None, offsetEdges: int = None, sponge_db_version: int = LATEST): @@ -860,7 +860,7 @@ def get_transcript_network(dataset_ID: int = None, disease_name=None, :param minMscor: mscor cutoff (>) :param minCorrelation: correlation cutoff (>) :param edgeSorting: sorting key for edges - :param nodeSorting: sorting key for nodes + :param nodeSorting: sorting key(s) for nodes (options are 'betweenness', 'node_degree', 'eigenvector') :param maxNodes: maximum number of nodes :param maxEdges: maximum number of edges :param offsetNodes: offset for node pagination @@ -910,15 +910,13 @@ def get_transcript_network(dataset_ID: int = None, disease_name=None, if minEigenvector: node_query = node_query.filter(models.networkAnalysisTranscript.eigenvector >= minEigenvector) - # Sorting nodes - if nodeSorting == "betweenness": - node_query = node_query.order_by(models.networkAnalysisTranscript.betweenness.desc()) - elif nodeSorting == "degree": - node_query = node_query.order_by(models.networkAnalysisTranscript.node_degree.desc()) - elif nodeSorting == "eigenvector": - node_query = node_query.order_by(models.networkAnalysisTranscript.eigenvector.desc()) - else: - raise ValueError("Invalid node sorting key. Choose one of 'betweenness', 'degree', 'eigenvector'") + # Sorting nodes: if more than one sorting key, rank by each key individually and sort by the mean of the ranks + if nodeSorting: + if any([key not in ['betweenness', 'node_degree', 'eigenvector'] for key in nodeSorting]): + raise ValueError("Invalid node sorting key. Choose from 'betweenness', 'node_degree', 'eigenvector'") + rank_columns = [db.func.rank().over(order_by=getattr(models.networkAnalysisTranscript, col).desc()).label(f"{col}_rank") for col in nodeSorting] + mean_rank = sum(rank_columns) / len(rank_columns) + node_query = node_query.order_by(mean_rank) # node pagination node_query = node_query.offset(offsetNodes).limit(maxNodes) diff --git a/swagger.yml b/swagger.yml index 9f0cb37..20709be 100644 --- a/swagger.yml +++ b/swagger.yml @@ -1432,11 +1432,13 @@ paths: required: false description: Possibilities for sorting of the nodes. schema: - type: string - enum: - - betweenness - - degree - - eigenvector + type: array + items: + type: string + # enum: + # - betweenness + # - degree + # - eigenvector - name: maxNodes in: query description: Number of nodes that should be shown. Default value is 100 and can be up to 1000. For more results please use batches, the provided offset parameter or download the whole dataset. @@ -1552,11 +1554,13 @@ paths: required: false description: Possibilities for sorting of the nodes. schema: - type: string - enum: - - betweenness - - degree - - eigenvector + type: array + items: + type: string + # enum: + # - betweenness + # - degree + # - eigenvector - name: maxNodes in: query description: Number of nodes that should be shown. Default value is 100 and can be up to 1000. For more results please use batches, the provided offset parameter or download the whole dataset. @@ -1714,7 +1718,7 @@ paths: type: string enum: - betweenness - - degree + - node_degree - eigenvector - name: descending in: query @@ -1895,7 +1899,7 @@ paths: type: string enum: - betweenness - - degree + - node_degree - eigenvector - name: descending in: query