-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'develop' into issue883/add-check-for-different-front-end
- Loading branch information
Showing
17 changed files
with
2,099 additions
and
1,991 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
"""Module to make a png of a graph from a graphml file.""" | ||
|
||
import os | ||
import networkx as nx | ||
import graphviz | ||
|
||
from beeflow.common import paths | ||
|
||
bee_workdir = paths.workdir() | ||
dags_dir = os.path.join(bee_workdir, 'dags') | ||
graphmls_dir = dags_dir + "/graphmls" | ||
|
||
|
||
def generate_viz(wf_id): | ||
"""Generate a PNG of a workflow graph from a GraphML file.""" | ||
short_id = wf_id[:6] | ||
graphml_path = graphmls_dir + "/" + short_id + ".graphml" | ||
output_path = dags_dir + "/" + short_id | ||
|
||
# Load the GraphML file using NetworkX | ||
graph = nx.read_graphml(graphml_path) | ||
|
||
# Initialize Graphviz graph | ||
dot = graphviz.Digraph(comment='Hierarchical Graph') | ||
|
||
# Add nodes and edges using helper functions | ||
add_nodes_to_dot(graph, dot) | ||
add_edges_to_dot(graph, dot) | ||
|
||
# Render the graph and save as PNG | ||
png_data = dot.pipe(format='png') | ||
with open(output_path + ".png", "wb") as png_file: | ||
png_file.write(png_data) | ||
|
||
|
||
def add_nodes_to_dot(graph, dot): | ||
"""Add nodes from the graph to the Graphviz object with labels and colors.""" | ||
label_to_color = { | ||
":Workflow": 'steelblue', | ||
":Output": 'mediumseagreen', | ||
":Metadata": 'skyblue', | ||
":Task": 'lightcoral', | ||
":Input": 'sandybrown', | ||
":Hint": 'plum', | ||
":Requirement": 'lightpink1' | ||
} | ||
|
||
for node_id, attributes in graph.nodes(data=True): | ||
label = attributes.get('labels', node_id) | ||
node_label, color = get_node_label_and_color(label, attributes, label_to_color) | ||
dot.node(node_id, label=node_label, style='filled', fillcolor=color) | ||
|
||
|
||
def get_node_label_and_color(label, attributes, label_to_color): | ||
"""Return the appropriate node label and color based on node type.""" | ||
label_to_attribute = { | ||
":Workflow": "Workflow", | ||
":Output": attributes.get('glob', label), | ||
":Metadata": attributes.get('state', label), | ||
":Task": attributes.get('name', label), | ||
":Input": attributes.get('source', label), | ||
":Hint": attributes.get('class', label), | ||
":Requirement": attributes.get('class', label) | ||
} | ||
|
||
# Check if the label is in the predefined labels | ||
if label in label_to_attribute: | ||
return label_to_attribute[label], label_to_color.get(label, 'gray') | ||
|
||
# Default case if no match | ||
return label, 'gray' | ||
|
||
|
||
def add_edges_to_dot(graph, dot): | ||
"""Add edges from the graph to the Graphviz object with appropriate labels.""" | ||
for source, target, attributes in graph.edges(data=True): | ||
edge_label = attributes.get('label', '') | ||
if edge_label in ('INPUT_OF', 'DESCRIBES', 'HINT_OF', 'REQUIREMENT_OF'): | ||
dot.edge(source, target, label=edge_label, fontsize="10") | ||
elif edge_label in ('DEPENDS_ON', 'RESTARTED_FROM'): | ||
dot.edge(target, source, label=edge_label, penwidth="3", | ||
fontsize="10", fontname="times-bold") | ||
else: | ||
dot.edge(target, source, label=edge_label, fontsize="10") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
"""Module to make sure all required keys are present.""" | ||
|
||
import xml.etree.ElementTree as ET | ||
import os | ||
|
||
from beeflow.common import paths | ||
|
||
bee_workdir = paths.workdir() | ||
dags_dir = os.path.join(bee_workdir, 'dags') | ||
graphmls_dir = dags_dir + "/graphmls" | ||
|
||
expected_keys = {"id", "name", "state", "class", "type", "value", "source", | ||
"workflow_id", "base_command", "stdout", "stderr", "default", | ||
"prefix", "position", "value_from", "glob"} | ||
|
||
default_key_definitions = { | ||
"id": {"for": "node", "attr.name": "id", "attr.type": "string"}, | ||
"name": {"for": "node", "attr.name": "name", "attr.type": "string"}, | ||
"state": {"for": "node", "attr.name": "state", "attr.type": "string"}, | ||
"class": {"for": "node", "attr.name": "class", "attr.type": "string"}, | ||
"type": {"for": "node", "attr.name": "type", "attr.type": "string"}, | ||
"value": {"for": "node", "attr.name": "value", "attr.type": "string"}, | ||
"source": {"for": "node", "attr.name": "source", "attr.type": "string"}, | ||
"workflow_id": {"for": "node", "attr.name": "workflow_id", "attr.type": "string"}, | ||
"base_command": {"for": "node", "attr.name": "base_command", "attr.type": "string"}, | ||
"stdout": {"for": "node", "attr.name": "stdout", "attr.type": "string"}, | ||
"stderr": {"for": "node", "attr.name": "stderr", "attr.type": "string"}, | ||
"default": {"for": "node", "attr.name": "default", "attr.type": "string"}, | ||
"prefix": {"for": "node", "attr.name": "prefix", "attr.type": "string"}, | ||
"position": {"for": "node", "attr.name": "position", "attr.type": "long"}, | ||
"value_from": {"for": "node", "attr.name": "value_from", "attr.type": "string"}, | ||
"glob": {"for": "node", "attr.name": "glob", "attr.type": "string"}, | ||
} | ||
|
||
|
||
def update_graphml(wf_id): | ||
"""Update GraphML file by ensuring required keys are present and updating its structure.""" | ||
short_id = wf_id[:6] | ||
graphml_path = graphmls_dir + "/" + short_id + ".graphml" | ||
# Parse the GraphML file and preserve namespaces | ||
tree = ET.parse(graphml_path) | ||
root = tree.getroot() | ||
|
||
name_space = {'graphml': 'http://graphml.graphdrawing.org/xmlns'} | ||
defined_keys = {key.attrib['id'] for key in root.findall('graphml:key', name_space)} | ||
used_keys = {data.attrib['key'] for data in root.findall('.//graphml:data', name_space)} | ||
|
||
missing_keys = used_keys - defined_keys | ||
|
||
# Insert default key definitions for missing keys | ||
for missing_key in missing_keys: | ||
if missing_key in expected_keys: | ||
default_def = default_key_definitions[missing_key] | ||
key_element = ET.Element(f'{{{name_space["graphml"]}}}key', | ||
id=missing_key, | ||
**default_def) | ||
root.insert(0, key_element) | ||
|
||
# Save the updated GraphML file by overwriting the original one | ||
tree.write(graphml_path, encoding='UTF-8', xml_declaration=True) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.