Connections provides the search-and-connect algorithms that underlie Network expansion methods. It is initialised with an interaction database DataFrame and pre-processes lookup tables for fast neighbour queries.
You rarely need to instantiate Connections directly — it is used internally by Network. The documentation here is aimed at developers who want to extend NeKo with custom connection strategies.
importpandasaspdfromneko._methods.enrichment_methodsimportConnectionsdb=pd.read_csv("my_interactions.csv")# source, target, effect, ...conn=Connections(db)# Check if a direct path exists between two proteinspaths=conn.find_paths("EGFR","AKT1",maxlen=3)
The public Network.complete_connection API describes results through
path_policy rather than exposing traversal details:
one_shortest uses BFS and selects one stable minimum-edge path.
all_shortest uses a BFS predecessor DAG and selects the edge union of all
minimum-edge paths.
all_bounded uses bounded DFS and selects all simple paths through the
cutoff.
All public completion policies require a finite positive cutoff. Low-level
Connections.bfs retains its legacy force behavior for specialized internal
use, but unbounded traversal is not an implicit network-construction policy.
Connections also stores indexed resource rows and signed adjacency maps.
Connection strategies should use those indexes and bulk network mutation rather
than scanning a DataFrame or calling Network.add_edge for every interaction.
Class that stores many utility functions to enrich an object Network.
Each utility functions should take as input the nodes dataframe, which is used as base for each algorithm, and a
database from the inputs modules, which will be used to extend the initial network.
Source code in neko/_methods/enrichment_methods.py
deffind_target_neighbours(self,node:str)->List[str]:""" Optimized helper function that finds the neighbors of the target node. """returnsorted(self.target_neighbours_map.get(node,[]),key=str)
deffind_source_neighbours(self,node:str)->List[str]:""" Optimized helper function that finds the neighbors of the target node. """returnsorted(self.source_neighbours_map.get(node,[]),key=str)
deffind_all_neighbours(self,node:str)->List[str]:""" Optimized helper function that finds all neighbors (both source and target) of the target node. """target_neighs=self.find_target_neighbours(node)source_neighs=self.find_source_neighbours(node)returnsorted(set(target_neighs+source_neighs),key=str)
deffind_interactions(self,source:str,target:str)->pd.DataFrame:"""Return resource rows for one directed edge without scanning the table."""positions=self._edge_positions.get((source,target),())ifnotpositions:returnself.resources.iloc[0:0]returnself.resources.iloc[positions]
defis_signed_edge(self,source,target,consensus=False):""" Returns True if the edge from source to target is signed (not undefined), False otherwise. Uses precomputed cache for speed. """key=(source,target)ifconsensus:result=self.signed_edges_consensus.get(key,False)else:result=self.signed_edges.get(key,False)returnresult
Returns the shortest path between two nodes (as a list of nodes) using BFS,
but stops searching if the path length exceeds maxlen edges (if provided).
If only_signed is True, only considers signed edges (not undefined).
If force is False and maxlen is None, uses a default upper bound of 10.
Source code in neko/_methods/enrichment_methods.py
defbfs(self,start:str,end:str,maxlen:Optional[int],only_signed:bool=False,consensus:bool=False,force:bool=False)->List[List[str]]:""" Returns the shortest path between two nodes (as a list of nodes) using BFS, but stops searching if the path length exceeds `maxlen` edges (if provided). If only_signed is True, only considers signed edges (not undefined). If force is False and maxlen is None, uses a default upper bound of 10. """ifstart==end:return[[start]]# trivial pathvisited=set()# Set a default upper bound if maxlen is None and not forceeffective_maxlen=maxlenifmaxlenisNoneandnotforce:effective_maxlen=10queue=deque([(start,[start],0)])# (node, path_so_far, depth)whilequeue:node,path,depth=queue.popleft()ifnode==end:return[path]ifeffective_maxlenisnotNoneanddepth>=effective_maxlen:continueifnodenotinvisited:visited.add(node)forneighborinself.find_target_neighbours(node):ifneighbornotinvisited:ifnotonly_signedorself.is_signed_edge(node,neighbor,consensus):queue.append((neighbor,path+[neighbor],depth+1))return[]
defbfs_all_shortest_edges(self,start:str,end:str,maxlen:int,only_signed:bool=False,consensus:bool=False,)->List[Tuple[str,str]]:"""Return the edge union of all minimum-length paths within a cutoff."""ifstart==end:return[]distances={start:0}predecessors=defaultdict(set)queue=deque([start])shortest_distance=Nonewhilequeue:node=queue.popleft()depth=distances[node]ifdepth>=maxlen:continueifshortest_distanceisnotNoneanddepth>=shortest_distance:continueforneighborinself.find_target_neighbours(node):ifonly_signedandnotself.is_signed_edge(node,neighbor,consensus,):continuenext_depth=depth+1known_depth=distances.get(neighbor)ifknown_depthisNone:distances[neighbor]=next_depthpredecessors[neighbor].add(node)queue.append(neighbor)elifknown_depth==next_depth:predecessors[neighbor].add(node)ifneighbor==end:shortest_distance=next_depthifendnotindistances:return[]shortest_edges=set()pending=[end]expanded=set()whilepending:node=pending.pop()ifnodeinexpanded:continueexpanded.add(node)forpredecessorinpredecessors[node]:shortest_edges.add((predecessor,node))pending.append(predecessor)returnsorted(shortest_edges,key=lambdaedge:(str(edge[0]),str(edge[1])))
Find all paths or motifs in a network, with optional sign/consensus filtering.
Uses an iterative DFS with an explicit stack for better performance and memory efficiency.
Args:
start: Node(s) to start from (str, list of str, or DataFrame with 'name_of_node').
end: Node(s) to end at (str, list of str, DataFrame, or None for motif search).
maxlen: Maximum path length (number of edges).
minlen: Minimum path length (number of edges).
loops: Allow cycles/loops if True.
only_signed: If True, only consider signed edges (not undefined).
consensus: If True, use consensus sign filtering.
Returns:
List of paths (each path is a list of node names).
Source code in neko/_methods/enrichment_methods.py
deffind_paths(self,start:Union[str,pd.DataFrame,List[str]],end:Union[str,pd.DataFrame,List[str],None]=None,maxlen:int=2,minlen:int=1,loops:bool=False,only_signed:bool=False,consensus:bool=False)->List[List[str]]:""" Find all paths or motifs in a network, with optional sign/consensus filtering. Uses an iterative DFS with an explicit stack for better performance and memory efficiency. Args: start: Node(s) to start from (str, list of str, or DataFrame with 'name_of_node'). end: Node(s) to end at (str, list of str, DataFrame, or None for motif search). maxlen: Maximum path length (number of edges). minlen: Minimum path length (number of edges). loops: Allow cycles/loops if True. only_signed: If True, only consider signed edges (not undefined). consensus: If True, use consensus sign filtering. Returns: List of paths (each path is a list of node names). """defconvert_to_string_list(start):ifisinstance(start,str):return[start]elifisinstance(start,pd.DataFrame):returnstart['name_of_node'].tolist()elifisinstance(start,list)andall(isinstance(item,str)foriteminstart):returnstartelse:raiseValueError("Invalid type for 'start' variable")defpath_generator(start_nodes,end_nodes,maxlen,minlen,loops,only_signed,consensus):forsinstart_nodes:foreinend_nodes:stack=[(s,[s])]whilestack:current,path=stack.pop()# Prune if path too longiflen(path)>maxlen+1:continue# Check for valid pathiflen(path)>=minlen+1and((eisnotNoneandcurrent==e)or(eisNoneandnotloopsandlen(path)==maxlen+1)or(loopsandpath[0]==path[-1]andlen(path)>1)):yieldpath# Continue DFSiflen(path)<=maxlen:next_steps=self.find_target_neighbours(current)ifonly_signed:next_steps=[nforninnext_stepsifself.is_signed_edge(current,n,consensus)]ifnotloops:next_steps=list(set(next_steps)-set(path))forneighborinnext_steps:stack.append((neighbor,path+[neighbor]))start_nodes=convert_to_string_list(start)end_nodes=convert_to_string_list(end)ifendelse[None]minlen=max(1,minlen)# Collect all paths in a list for backward compatibilityreturnlist(path_generator(start_nodes,end_nodes,maxlen,minlen,loops,only_signed,consensus))
Find cascades of interactions in the network.
Parameters:
- target_genes: List of target genes to start the cascade.
- max_depth: Maximum depth of the cascade.
- selected_rank: Number of top regulators to select for each iteration.
Returns:
- interactions: List of interactions in the cascade.
Source code in neko/_methods/enrichment_methods.py
deffind_upstream_cascades(self,target_genes:List[str],max_depth:int=1,selected_rank:int=1)->List[Tuple[str,str]]:""" Find cascades of interactions in the network. Parameters: - target_genes: List of target genes to start the cascade. - max_depth: Maximum depth of the cascade. - selected_rank: Number of top regulators to select for each iteration. Returns: - interactions: List of interactions in the cascade. """defcollect_for_depth(current_targets,current_depth):ifcurrent_depth>max_depth:return[]mcs_regulators=find_minimal_covering_regulators(self.resources,current_targets,selected_rank)interactions=[(reg,target)forreginmcs_regulatorsfortargetinself.target_neighbours_map.get(reg,[])iftargetincurrent_targets]# this is not workingifcurrent_depth<max_depth:next_targets=list(mcs_regulators)interactions+=collect_for_depth(next_targets,current_depth+1)returninteractionsreturncollect_for_depth(target_genes,1)# it returns nothing