diff --git a/src/graph.py b/src/graph.py index b9157e7844f30462f34b73e9e0053e32c8bd0cb2..6c4badc39094cf7142a4eaf69eb571f3eb5db0c7 100644 --- a/src/graph.py +++ b/src/graph.py @@ -27,55 +27,55 @@ class Graph(): def initialise(self, processes_2_remove = []): + if(not self.is_initialised()): + def get_node_id(dico, process): + for node in dico["nodes"]: + if(node['name']==process): + return node['id'] + for sub in dico['subworkflows']: + res = get_node_id(dico['subworkflows'][sub], process) + if(res!=-1): + return res + return -1 + + #This function removes the process -> by the simpliest way -> it doesn't create new links + def remove_node(dico, node_id): + #Remove nodes + nodes_to_remove = [] + for node in dico["nodes"]: + if(node['id']==node_id): + nodes_to_remove.append(node) + for node in nodes_to_remove: + dico["nodes"].remove(node) + + #Remove edges + edges_to_remove = [] + for edge in dico["edges"]: + if(edge['A']==node_id): + edges_to_remove.append(edge) + if(edge['B']==node_id): + edges_to_remove.append(edge) + for edge in edges_to_remove: + dico["edges"].remove(edge) + + for sub in dico['subworkflows']: + remove_node(dico['subworkflows'][sub], node_id) + + for process in processes_2_remove: + node_id = get_node_id(self.full_dico, process) + remove_node(self.full_dico, node_id) + + + self.get_dependency_graph() + self.get_process_dependency_graph() - def get_node_id(dico, process): - for node in dico["nodes"]: - if(node['name']==process): - return node['id'] - for sub in dico['subworkflows']: - res = get_node_id(dico['subworkflows'][sub], process) - if(res!=-1): - return res - return -1 - - #This function removes the process -> by the simpliest way -> it doesn't create new links - def remove_node(dico, node_id): - #Remove nodes - nodes_to_remove = [] - for node in dico["nodes"]: - if(node['id']==node_id): - nodes_to_remove.append(node) - for node in nodes_to_remove: - dico["nodes"].remove(node) - - #Remove edges - edges_to_remove = [] - for edge in dico["edges"]: - if(edge['A']==node_id): - edges_to_remove.append(edge) - if(edge['B']==node_id): - edges_to_remove.append(edge) - for edge in edges_to_remove: - dico["edges"].remove(edge) - - for sub in dico['subworkflows']: - remove_node(dico['subworkflows'][sub], node_id) - - for process in processes_2_remove: - node_id = get_node_id(self.full_dico, process) - remove_node(self.full_dico, node_id) - - - self.get_dependency_graph() - self.get_process_dependency_graph() - - - #self.networkX_wo_operations = self.get_networkx_graph(self.dico_process_dependency_graph, self.networkX_wo_operations) - self.dico_flattened["nodes"] = [] - self.dico_flattened["edges"] = [] - #This will stay empty -> it's just so we can use the same function - self.dico_flattened["subworkflows"] = [] - self.initialised = True + + #self.networkX_wo_operations = self.get_networkx_graph(self.dico_process_dependency_graph, self.networkX_wo_operations) + self.dico_flattened["nodes"] = [] + self.dico_flattened["edges"] = [] + #This will stay empty -> it's just so we can use the same function + self.dico_flattened["subworkflows"] = [] + self.initialised = True def is_initialised(self): return self.initialised @@ -286,12 +286,31 @@ class Graph(): generate_graph(self.get_output_dir()/'graphs'/filename, graph_dico_wo_orphan_operations(self.dico_wo_branch_operation), label_edge=False, label_node=False, render_graphs = render_graphs) + #============================ + #GENERATE USER VIEW + #============================ + def generate_user_view(self, relevant_processes = [], render_graphs = True): + #For now i'm only gonna work from the flattened dico + self.initialise_flattened_dico(self.dico_process_dependency_graph) + dico = self.dico_flattened + + relev_user_view_builder(dico, relevant_modules=relevant_processes) + + generate_graph(self.get_output_dir()/'graphs'/"temp", dico, label_edge=True, label_node=True, render_graphs = render_graphs) + + + + #============================ #METADATA FROM GRAPH #============================ def initialise_flattened_dico(self, dico): - + self.dico_flattened = {} + self.dico_flattened["nodes"] = [] + self.dico_flattened["edges"] = [] + #This will stay empty -> it's just so we can use the same function + self.dico_flattened["subworkflows"] = [] flatten_dico(dico, self.dico_flattened) #for node in dico["nodes"]: # self.dico_flattened["nodes"].append(node) diff --git a/src/nextflow_file.py b/src/nextflow_file.py index c6588d693861d7f5c1a66dfbd136419b95a9e909..87dd9c2d5c46b95df3499124aca244241612de21 100644 --- a/src/nextflow_file.py +++ b/src/nextflow_file.py @@ -693,13 +693,16 @@ class Nextflow_File(Nextflow_Building_Blocks): self.graph.get_dependency_graph_wo_labels(render_graphs = render_graphs) self.graph.get_dependency_graph_wo_orphan_operations(render_graphs = render_graphs) self.graph.get_dependency_graph_wo_orphan_operations_wo_labels(render_graphs = render_graphs) - #Generate the different metadata associated with the graphs self.graph.get_metadata_specification_graph() self.graph.get_metadata_dependency_graph() self.graph.get_metadata_process_dependency_graph() + def generate_user_view(self, relevant_processes = [], render_graphs = True, processes_2_remove = []): + self.graph.initialise(processes_2_remove = processes_2_remove) + self.graph.generate_user_view(relevant_processes = relevant_processes, render_graphs = render_graphs) + def get_graph(self): return self.graph #def get_metadata_graph_wo_operations(self): diff --git a/src/outils_graph.py b/src/outils_graph.py index 4f18d9abc6c840bbab06476172bdb989e8614f15..8f9c20b9d2470da653d9c4671615eb56aaa437c7 100644 --- a/src/outils_graph.py +++ b/src/outils_graph.py @@ -343,4 +343,112 @@ def flatten_dico(dico, dico_flattened): dico_flattened["edges"].append(edge) for subworkflow in dico["subworkflows"]: flatten_dico(dico["subworkflows"][subworkflow], dico_flattened) - return dico_flattened \ No newline at end of file + return dico_flattened + +#================================================== +#Get user view +#Je suppose que c'est un dico flatten (avec que des processes) -> process dependency graph + +def get_id_from_name(dico, name): + ids = [] + for n in dico["nodes"]: + if(n['name']==name): + ids.append(n['id']) + return ids + +def get_name_from_id(dico, ID): + names = [] + for n in dico["nodes"]: + if(n['id']==ID): + names.append(n['name']) + return names + +def get_output_nodes(dico): + N = [] + for n in dico["nodes"]: + N.append(n['id']) + none_outputs = [] + for e in dico["edges"]: + none_outputs.append(e['A']) + outputs = list(set(N) - set(none_outputs)) + outputs_names = [] + for o in outputs: + outputs_names+=get_name_from_id(dico=dico, ID=o) + return outputs_names + +def remove_edges_with_node(edges, nodes): + edges_without_node = [] + for e in edges: + if(e['A'] not in nodes and e['B'] not in nodes): + edges_without_node.append(e) + return edges_without_node + +def get_nodes_from_edges(edges): + N = [] + for e in edges: + N.append(e['A']) + N.append(e['B']) + return list(set(N)) + +def get_neighbors(edges, A): + Bs = [] + for e in edges: + if(e['A']==A): + Bs.append(e['B']) + return Bs + +def exist_path(A, B, edges): + N = get_nodes_from_edges(edges=edges) + visited = {} + for n in N: + visited[n] = False + visited[A] = True + if(A==B): + return True + for neigh in get_neighbors(edges, A): + if(exist_path(neigh, B, edges)): + return True + return False + + +def nr_path(n, r, dico, R, outputs): + + rest_of_R = set(R)-set([r]) + rest_of_R_ids = [] + for r_p in rest_of_R: + rest_of_R_ids+=get_id_from_name(dico, r_p) + edges = remove_edges_with_node(dico["edges"], rest_of_R_ids) + + for n_ids in get_id_from_name(dico, n): + for r_ids in get_id_from_name(dico, r): + if(exist_path(n_ids, r_ids, edges)): + return True + return False + + +def rSucc(n, dico, R, outputs): + tab = [] + for r in set(R).union(set(outputs)): + if(nr_path(n, r, dico, R, outputs)): + tab.append(r) + return tab + +def relev_user_view_builder(dico, relevant_modules): + R = relevant_modules + outputs = get_output_nodes(dico) + U = [] + markes_statues = {} + N = [] + for n in dico["nodes"]: + # markes_statues[n['name']] = "marked" + N.append(n['name']) + N_minus_R = set(N) - set(R) + for n in N_minus_R: + markes_statues[n] = "unmarked" + #print(N_minus_R) + for r in R: + in_r = [] + for n in set(N) - set(R): + if(rSucc(n, dico, R, outputs)==[r]): + in_r.append(n) + print(r, in_r) \ No newline at end of file diff --git a/src/workflow.py b/src/workflow.py index 96b6b5e5a1b0751c66097a92345c8f0b62ab795f..77ccd87a1b807159df1b7ad9003095625aed40c9 100644 --- a/src/workflow.py +++ b/src/workflow.py @@ -525,3 +525,11 @@ George Marchment, Bryan Brancotte, Marie Schmit, Frédéric Lemoine, Sarah Cohen for t in temp: tab_processes_2_remove.append(t.strip()) self.nextflow_file.generate_all_graphs(render_graphs = render_graphs, processes_2_remove = tab_processes_2_remove) + + def generate_user_view(self, relevant_processes = [], render_graphs = True): + tab_processes_2_remove = [] + if(self.processes_2_remove!=None): + temp = self.processes_2_remove.split(",") + for t in temp: + tab_processes_2_remove.append(t.strip()) + self.nextflow_file.generate_user_view(relevant_processes = relevant_processes, render_graphs = render_graphs, processes_2_remove = tab_processes_2_remove) \ No newline at end of file