def gen_add_input2( dfg: AGraph, fu: AGraph, input_map: Dict[str, int]) -> Tuple[List[Input], List[Output]]: outputs: List[Output] = [] inputs: List[Input] = [] nodes: List[Instruction] = [] for node in fu.nodes(): nodes.append(parse_instruction(node)) nodes.sort() prev_o = 0 for node in nodes: preds = dfg.predecessors(node.name) parent0 = parse_instruction(preds[0]) parent1 = parse_instruction(preds[1]) if parent0.name in input_map: label = dfg.get_node(parent0.name).attr['label'] if 'mul' in label: latency = 2 else: latency = 1 i0 = prev_o + 1 inputs.append( Input(i0, input_map[parent0.name], parent0.cycle + latency)) else: for output in outputs: if output.cycle == parent0.cycle + 1: i0 = output.val break if parent1.name in input_map: label = dfg.get_node(parent1.name).attr['label'] if 'mul' in label: latency = 2 else: latency = 1 i1 = prev_o + 1 inputs.append( Input(i1, input_map[parent1.name], parent1.cycle + latency)) else: for output in outputs: if output.cycle == parent1.cycle + 1: i1 = output.val break expected = i0 + i1 prev_o = expected outputs.append(Output(expected, node.cycle + 1)) inputs.sort() return inputs, outputs
def trace(graph: pgv.AGraph, start: str, end: str) -> pgv.AGraph: nxgraph = nx.nx_agraph.from_agraph(graph) assert(start in nxgraph and end in nxgraph) shortest = nx.shortest_path(nxgraph, start, end) shgraph = pgv.AGraph(directed=True,overlap=False,rankdir='LR') for e in range(len(shortest)-1): label = graph.get_edge(shortest[e], shortest[e+1]).attr['label'] shgraph.add_edge(shortest[e], shortest[e+1], label=label) for n in shgraph.nodes_iter(): n.attr['label'] = graph.get_node(n).attr['label'] n.attr['style'] = graph.get_node(n).attr['style'] n.attr['fillcolor'] = graph.get_node(n).attr['fillcolor'] return shgraph
def draw_finite_state_machine(finite_state_machine: FiniteStateMachine, path: str): """Creates a directed non-strict multi graph image representation of the FSM.""" from pygraphviz import AGraph graph = AGraph(strict=False, directed=True) graph.add_nodes_from(finite_state_machine.state_set) for initial_state in finite_state_machine.initial_states: graph.get_node(initial_state).attr["color"] = "green" for element, transitions in finite_state_machine.transitions.items(): for from_state, to_states in transitions.items(): for to_state in to_states: graph.add_edge(from_state, to_state, label=element) for final_state in finite_state_machine.final_states: graph.get_node(final_state).attr["color"] = "red" graph.draw(path, prog="dot")
def gen_alloc_insts(rf_allocs: List[RFallocation], dfg: AGraph, fu: AGraph, input_map: Dict[str, int]) -> List[ATAI]: rf_insts = [] for rf_alloc in rf_allocs: inst = parse_instruction(dfg.get_node(rf_alloc.name)) if rf_alloc.type == RFallocation.FUTypes.MUL: latency = Config.MUL_LATENCY elif rf_alloc.type == RFallocation.FUTypes.ADD: latency = Config.ADD_LATENCY else: # TODO: load inst latency? latency = 1 if rf_alloc.name in fu: input_type = OpInput() else: # TODO: map fu input input_type = FUinput(input_map[rf_alloc.name]) if input_type is None: raise AllocException('alloc not found in input map') cycle = inst.cycle + latency rf_insts.append(ATAStore(input_type, rf_alloc.address, cycle)) return rf_insts
def gen_op_insts(rf_allocs: List[RFallocation], dfg: AGraph, fu: AGraph, input_map: Dict[str, int]) -> List[ATAI]: assembly = [] instructions: List[Instruction] = [] for instruction in fu.nodes(): instructions.append(parse_instruction(instruction)) for instruction in instructions: n = dfg.get_node(instruction.name) nodes = dfg.predecessors(n) input_type0 = inst_input_type(rf_allocs, fu, nodes[0]) if len(nodes) > 1: input_type1 = inst_input_type(rf_allocs, fu, nodes[1]) else: input_type1 = input_type0 # This should never occur but we check for it anyways if input_type0 == OpInput and input_type1 == OpInput: if nodes[0] != nodes[1]: raise DoubleUnidenticalOPInputException # TODO: find scheduling for fetch ops might need to be swapped to fit? if input_type0 == RFInput: # If the data is in the RF we need to generate fetch instructions assembly.append( generate_fetch(rf_allocs, instruction, nodes[0], ATAFetch.REG.REG0)) input0 = RFInput() elif input_type0 == OpInput: input0 = OpInput() else: n = input_map[nodes[0].get_name()] if n is None: raise FUinputException( 'Cannot find FU from which predecessing node originates in map' ) input0 = FUinput(n) if input_type1 == RFInput: assembly.append( generate_fetch(rf_allocs, instruction, nodes[1], ATAFetch.REG.REG1)) input1 = RFInput() elif input_type1 == OpInput: input1 = OpInput() else: n = input_map[nodes[1].get_name()] if n is None: raise FUinputException( 'Cannot find FU from which predecessing node originates in map' ) input1 = FUinput(n) assembly.append(ATAOp(input0, input1, instruction.cycle)) return assembly
def to_dot(self, filename, edges): from pygraphviz import AGraph dot = AGraph(directed=True) for n in edges.keys(): dot.add_node(str(n)) if lib.qcgc_arena_get_blocktype(ffi.cast( "cell_t *", n)) not in [lib.BLOCK_BLACK, lib.BLOCK_WHITE]: node = dot.get_node(str(n)) node.attr['color'] = 'red' for n in edges.keys(): if edges[n] is not None: dot.add_edge(str(n), str(edges[n])) dot.layout(prog='dot') dot.draw(filename)
def to_dot(self, filename, edges): from pygraphviz import AGraph dot = AGraph(directed=True) for n in edges.keys(): dot.add_node(str(n)) if lib.qcgc_arena_get_blocktype(ffi.cast("cell_t *", n)) not in [ lib.BLOCK_BLACK, lib.BLOCK_WHITE]: node = dot.get_node(str(n)) node.attr['color'] = 'red' for n in edges.keys(): if edges[n] is not None: dot.add_edge(str(n), str(edges[n])) dot.layout(prog='dot') dot.draw(filename)
def draw_workflow(filename, workflow, paint=None): dot = AGraph(directed=True) # (comment="Computing scheme") dot.node_attr['style'] = 'filled' for i, n in workflow.nodes.items(): dot.add_node(i, label="{0} \n {1}".format( n.foo.__name__, _format_arg_list(n.bound_args.args, None))) x = dot.get_node(i) if paint: paint(x, n.foo.__name__) for i in workflow.links: for j in workflow.links[i]: dot.add_edge(i, j[0]) dot.layout(prog='dot') dot.draw(filename)
def draw_graph(state_manager, filename): graph = AGraph() graph.node_attr["style"] = "filled" graph.node_attr["shape"] = "circle" graph.node_attr["fixedsize"] = "true" graph.node_attr["width"] = 0.5 graph.node_attr["height"] = 0.5 # we add all nodes (keys = ID) graph.add_nodes_from(state_manager.state.keys()) for var_id in state_manager.state: # and for each of these nodes, we change color node = graph.get_node(var_id) node.attr["fillcolor"] = get_color(state_manager.state[var_id]) # finally, we add edges for c in state_manager.constraints: e = c.list_vars graph.add_edge(e[0], e[1]) graph.write(filename)
def dot_layout(cy_elements): """ Get a CyElements object and augment it (in-place) with positions, widths, heights, and spline data from a dot based layout. Returns the object. """ elements = cy_elements.elements g = AGraph(directed=True, strict=False) # make transitive relations appear top to bottom # TODO: make this not specific to leader example elements = list(elements) nodes_by_id = dict( (e["data"]["id"], e) for e in elements if e["group"] == "nodes") order = [(nodes_by_id[e["data"]["source"]], nodes_by_id[e["data"]["target"]]) for e in elements if e["group"] == "edges" and e["data"]["obj"] in ('reach', 'le')] elements = topological_sort(elements, order, lambda e: e["data"]["id"]) # add nodes to the graph for e in elements: if e["group"] == "nodes": g.add_node(e["data"]["id"], label=e["data"]["label"].replace('\n', '\\n')) # TODO: remove this, it's specific to leader_demo weight = { 'reach': 10, 'le': 10, 'id': 1, } constraint = { 'pending': False, } # add edges to the graph for e in elements: if e["group"] == "edges": g.add_edge( e["data"]["source"], e["data"]["target"], e["data"]["id"], weight=weight.get(e["data"]["obj"], 0), #constraint=constraint.get(e["data"]["obj"], True), ) # add clusters clusters = defaultdict(list) for e in elements: if e["group"] == "nodes" and e["data"]["cluster"] is not None: clusters[e["data"]["cluster"]].append(e["data"]["id"]) for i, k in enumerate(sorted(clusters.keys())): g.add_subgraph( name='cluster_{}'.format(i), nbunch=clusters[k], ) # now get positions, heights, widths, and bsplines g.layout(prog='dot') for e in elements: if e["group"] == "nodes": attr = g.get_node(e["data"]["id"]).attr e["position"] = _to_position(attr['pos']) e["data"]["width"] = 72 * float(attr['width']) e["data"]["height"] = 72 * float(attr['height']) elif e["group"] == "edges": attr = g.get_edge(e["data"]["source"], e["data"]["target"], e["data"]["id"]).attr e["data"].update(_to_edge_position(attr['pos'])) g.draw('g.png') return cy_elements
def dot_layout(cy_elements, edge_labels=False, subgraph_boxes=False, node_gt=None): """ Get a CyElements object and augment it (in-place) with positions, widths, heights, and spline data from a dot based layout. edge_labels is true if labels should appear on edges subgraph_boxes is true if boxes should be drawn around subgraphs Returns the object. """ elements = cy_elements.elements # g = AGraph(directed=True, strict=False) g = AGraph(directed=True, strict=False, forcelabels=True) # make transitive relations appear top to bottom elements = list(elements) nodes_by_id = dict( (e["data"]["id"], e) for e in elements if e["group"] == "nodes") order = [(nodes_by_id[e["data"]["source"]], nodes_by_id[e["data"]["target"]]) for e in elements if e["group"] == "edges" and "transitive" in e["data"] and e["data"]["transitive"]] elements = topological_sort(elements, order, lambda e: e["data"]["id"]) # get the node id's and stable sort them by cluster # the idea here is to convert the graph into a dag by sorting # the nodes, then reversing the back edges. In particular, we try to make # all the edges between two clusters go in the same direction so clustering # doesn't result in horizontal edges, which dot renders badly. sorted_nodes = [e["data"]["id"] for e in elements if e["group"] == "nodes"] sorted_nodes = sorted(enumerate(sorted_nodes), key=lambda x: (nodes_by_id[x[1]]["data"]["cluster"], x[0])) sorted_nodes = [y for idx, y in sorted_nodes] node_key = dict((id, idx) for idx, id in enumerate(sorted_nodes)) if node_gt is None: node_gt = lambda X, y: False else: node_gt = lambda x, y: node_key[x] > node_key[y] # add nodes to the graph for e in elements: if e["group"] == "nodes" and e["classes"] != 'non_existing': g.add_node(e["data"]["id"], label=e["data"]["label"].replace('\n', '\\n')) # TODO: remove this, it's specific to leader_demo weight = { 'reach': 10, 'le': 10, 'id': 1, } constraint = { 'pending': False, } # add edges to the graph for e in elements: if e["group"] == "edges": # kwargs = {'weight': weight.get(e["data"]["obj"], 0)}, kwargs = {'label': e["data"]["label"]} if edge_labels else {} if node_gt(e["data"]["source"], e["data"]["target"]): g.add_edge(e["data"]["target"], e["data"]["source"], e["data"]["id"], dir='back', **kwargs #constraint=constraint.get(e["data"]["obj"], True), ) else: g.add_edge(e["data"]["source"], e["data"]["target"], e["data"]["id"], **kwargs #constraint=constraint.get(e["data"]["obj"], True), ) # add clusters clusters = defaultdict(list) for e in elements: if e["group"] == "nodes" and e["data"][ "cluster"] is not None and e["classes"] != 'non_existing': clusters[e["data"]["cluster"]].append(e["data"]["id"]) for i, k in enumerate(sorted(clusters.keys())): g.add_subgraph( name='cluster_{}'.format(i), nbunch=clusters[k], rank='min', ) # now get positions, heights, widths, and bsplines g.layout(prog='dot') # get the y origin. we want the top left of the graph to be a # fixed coordinate (hopefully (0,0)) so the graph doesn't jump when # its height changes. Unfortunately, pygraphviz has a bug a gives # the wrong bbox, so we compute the max y coord. # bbox = pygraphviz.graphviz.agget(g.handle,'bb') global y_origin y_origin = 0.0 for n in g.nodes(): top = float(n.attr['pos'].split(',')[1]) + float(n.attr['height']) / 2 if top > y_origin: y_origin = top if subgraph_boxes: for sg in g.subgraphs(): top = float(sg.graph_attr['bb'].split(',')[3]) if top > y_origin: y_origin = top for e in elements: if e["group"] == "nodes" and e["classes"] != 'non_existing': attr = g.get_node(e["data"]["id"]).attr e["position"] = _to_position(attr['pos']) e["data"]["width"] = 72 * float(attr['width']) e["data"]["height"] = 72 * float(attr['height']) elif e["group"] == "edges": if node_gt(e["data"]["source"], e["data"]["target"]): attr = g.get_edge(e["data"]["target"], e["data"]["source"], e["data"]["id"]).attr pos = attr['pos'] pe = pos.split() ppe = pe[1:] ppe.reverse() pos = ' '.join([pe[0].replace('s', 'e')] + ppe) else: attr = g.get_edge(e["data"]["source"], e["data"]["target"], e["data"]["id"]).attr pos = attr['pos'] e["data"].update(_to_edge_position(pos)) if edge_labels and e["data"]["label"] != '': e["data"]["lp"] = _to_position(attr['lp']) # g.draw('g.png') if subgraph_boxes: for sg in g.subgraphs(): box = cy_elements.add_shape(sg.name, classes='subgraphs') coords = _to_coord_list(sg.graph_attr['bb']) box["data"]["coords"] = coords return cy_elements
def recalculate(user): # remove old ranking RankedTeam.objects.filter(team__user = user).delete() for pic in RankingPicture.objects.all(): pic.image.delete() pic.delete() color_index = 0 team_graph = Graph() gvfull = AGraph(directed = True) for team in user.teams.all(): gvfull.add_node(asciiname(team), label = team.name) team_graph.add_node(team) for game in Game.objects.filter(team_1__user = user, team_2__user = user): team_graph.add_edge(game.winner(), game.loser(), game.jugg_diff()) for source, dest, weight in team_graph.edges(): gvfull.add_edge(asciiname(source), asciiname(dest), label = str(weight)) current_place = 1 gvcircles = AGraph(directed = True) gvtiebreaker = AGraph(directed = True) for place in team_graph.topological_sort(): place_list = [] relevant_teams = set() for circle in place: relevant_teams |= circle if len(circle) == 1: continue color_index, current_color = getcolor(color_index) for team in circle: gvcircles.add_node(asciiname(team), label = team.name, color = current_color, fontcolor = current_color) gvfull.get_node(asciiname(team)).attr['color'] = current_color gvfull.get_node(asciiname(team)).attr['fontcolor'] = current_color for source, dest, weight in team_graph.edges(): if source in circle and dest in circle: gvcircles.add_edge(asciiname(source), asciiname(dest), label = str(weight), color = current_color, fontcolor = current_color) gvfull.get_edge(asciiname(source), asciiname(dest)).attr['color'] = current_color gvfull.get_edge(asciiname(source), asciiname(dest)).attr['fontcolor'] = current_color place = [[(team.normalized_jugg_diff(relevant_teams), team.name, team) for team in circle] for circle in place] for circle in place: circle.sort(reverse = True) while place: place_list.append(set()) i = 0 while i < len(place): circle = place[i] jd = circle[0][0] while circle and circle[0][0] == jd: place_list[-1].add(circle.pop(0)) if not circle: place.remove(circle) else: i += 1 for same_place_set in place_list: # tie breaker if len(same_place_set) > 1: # teams that everyone on this place played against relevant_teams = team_graph.nodes() for circ_jugg_diff, name, team in same_place_set: opponents = set() for game in team.games(): if game.team_1 == team: opponents.add(game.team_2) else: opponents.add(game.team_1) relevant_teams &= opponents if len(relevant_teams) > 0: color_index, current_color_a = getcolor(color_index) color_index, current_color_b = getcolor(color_index) for team in relevant_teams: gvtiebreaker.add_node("b-" + asciiname(team), label = team.name, color = current_color_b, fontcolor = current_color_b) for void, void, team in same_place_set: gvtiebreaker.add_node("a-" + asciiname(team), label = team.name, color = current_color_a, fontcolor = current_color_a) for game in team.games(): if game.team_1 == team and game.team_2 in relevant_teams: if game.winner() == team: gvtiebreaker.add_edge("a-" + asciiname(team), "b-" + asciiname(game.team_2), label = game.jugg_diff(), color = current_color_a, fontcolor = current_color_a) else: gvtiebreaker.add_edge("b-" + asciiname(game.team_2), "a-" + asciiname(team), label = game.jugg_diff(), color = current_color_b, fontcolor = current_color_b) elif game.team_2 == team and game.team_1 in relevant_teams: if game.winner() == team: gvtiebreaker.add_edge("a-" + asciiname(team), "b-" + asciiname(game.team_1), label = game.jugg_diff(), color = current_color_a, fontcolor = current_color_a) else: gvtiebreaker.add_edge("b-" + asciiname(game.team_1), "a-" + asciiname(team), label = game.jugg_diff(), color = current_color_b, fontcolor = current_color_b) # jugg differences against relevant teams rel_jugg_diffs = set() for team_tuple in same_place_set: rel_jugg_diffs.add((team_tuple, team_tuple[2].normalized_jugg_diff(relevant_teams))) # pop all teams, highest relevant jugg difference first while rel_jugg_diffs: # current maximum max_rel_jugg_diff = None # teams with maximum jugg difference to_remove = None for team_tuple, rel_jugg_diff in rel_jugg_diffs: # new maximum if max_rel_jugg_diff is None or rel_jugg_diff > max_rel_jugg_diff[0]: max_rel_jugg_diff = (rel_jugg_diff, {team_tuple}) to_remove = {(team_tuple, rel_jugg_diff)} # same as maximum elif rel_jugg_diff == max_rel_jugg_diff[0]: max_rel_jugg_diff[1].add(team_tuple) to_remove.add((team_tuple, rel_jugg_diff)) # remove teams with maximum jugg difference rel_jugg_diffs -= to_remove # add teams to listing for (circ_jugg_diff, name, team), rel_jugg_diff in to_remove: RankedTeam.objects.create(place = current_place, team = team) current_place += 1 else: circ_jugg_diff, name, team = same_place_set.pop() RankedTeam.objects.create(place = current_place, team = team) current_place += 1 with tempfile.NamedTemporaryFile(suffix = ".png") as tmp: gvfull.draw(tmp, "png", "dot") pic = RankingPicture(user = user, image = File(tmp), title = "Full Team Graph") pic.save() with tempfile.NamedTemporaryFile(suffix = ".png") as tmp: gvcircles.draw(tmp, "png", "dot") pic = RankingPicture(user = user, image = File(tmp), title = "Circles") pic.save() with tempfile.NamedTemporaryFile(suffix = ".png") as tmp: gvtiebreaker.draw(tmp, "png", "dot") pic = RankingPicture(user = user, image = File(tmp), title = "Tie Breaker") pic.save()
class GraphGeneratingReporter(BaseReporter): def __init__(self): self.evolution = [] # List[str] self._evaluating = None # Dict[Candidate, Set[Requirement]] self._dependencies = defaultdict(set) # Dict[Candidate.name, Counter[Requirement]] self._active_requirements = defaultdict(Counter) self._node_names = {} self._counter = count() self.graph = AGraph( directed=True, rankdir="LR", labelloc="top", labeljust="center", nodesep="0", concentrate="true", ) self.graph.add_node("root", label=":root:", shape="Mdiamond") self._node_names[self._key(None)] = "root" del self.graph.node_attr["label"] self.graph.edge_attr.update({ "arrowhead": "empty", "style": "dashed", "color": "#808080" }) # # Internal Graph-handling API # def _prepare_node(self, obj): cls = obj.__class__.__name__ n = next(self._counter) node_name = f"{cls}_{n}" self._node_names[self._key(obj)] = node_name return node_name def _key(self, obj): if obj is None: return None return ( obj.__class__.__name__, repr(obj), ) def _get_subgraph(self, name, *, must_exist_already=True): name = canonicalize_name(name) c_name = f"cluster_{name}" subgraph = self.graph.get_subgraph(c_name) if subgraph is None: if must_exist_already: existing = [s.name for s in self.graph.subgraphs_iter()] raise RuntimeError( f"Graph for {name} not found. Existing: {existing}") else: subgraph = self.graph.add_subgraph(name=c_name, label=name) return subgraph def _add_candidate(self, candidate): if candidate is None: return if self._key(candidate) in self._node_names: return node_name = self._prepare_node(candidate) # A candidate is only seen after a requirement with the same name. subgraph = self._get_subgraph(candidate.name, must_exist_already=True) subgraph.add_node(node_name, label=candidate.version, shape="box") def _add_requirement(self, req): if self._key(req) in self._node_names: return name = self._prepare_node(req) subgraph = self._get_subgraph(req.name, must_exist_already=False) subgraph.add_node(name, label=str(req.specifier) or "*", shape="cds") def _ensure_edge(self, from_, *, to, **attrs): from_node = self._node_names[self._key(from_)] to_node = self._node_names[self._key(to)] try: existing = self.graph.get_edge(from_node, to_node) except KeyError: attrs.update(headport="w", tailport="e") self.graph.add_edge(from_node, to_node, **attrs) else: existing.attr.update(attrs) def _get_node_for(self, obj): node_name = self._node_names[self._key(obj)] node = self.graph.get_node(node_name) assert node is not None return node_name, node def _track_evaluating(self, candidate): if self._evaluating != candidate: if self._evaluating is not None: self.backtracking(self._evaluating, internal=True) self.evolution.append(self.graph.to_string()) self._evaluating = candidate # # Public reporter API # def starting(self): print("starting(self)") def starting_round(self, index): print(f"starting_round(self, {index})") # self.graph.graph_attr["label"] = f"Round {index}" self.evolution.append(self.graph.to_string()) def ending_round(self, index, state): print(f"ending_round(self, {index}, state)") def ending(self, state): print("ending(self, state)") def adding_requirement(self, req, parent): print(f"adding_requirement(self, {req!r}, {parent!r})") self._track_evaluating(parent) self._add_candidate(parent) self._add_requirement(req) self._ensure_edge(parent, to=req) self._active_requirements[canonicalize_name(req.name)][req] += 1 self._dependencies[parent].add(req) if parent is None: return # We're seeing the parent candidate (which is being "evaluated"), so # color all "active" requirements pointing to the it. # TODO: How does this interact with revisited candidates? for parent_req in self._active_requirements[canonicalize_name( parent.name)]: self._ensure_edge(parent_req, to=parent, color="#80CC80") def backtracking(self, candidate, internal=False): print(f"backtracking(self, {candidate!r}, internal={internal})") self._track_evaluating(candidate) self._evaluating = None # Update the graph! node_name, node = self._get_node_for(candidate) node.attr.update(shape="signature", color="red") for edge in self.graph.out_edges_iter([node_name]): edge.attr.update(style="dotted", arrowhead="vee", color="#FF9999") _, to = edge to.attr.update(color="black") for edge in self.graph.in_edges_iter([node_name]): edge.attr.update(style="dotted", color="#808080") # Trim "active" requirements to remove anything not relevant now. for requirement in self._dependencies[candidate]: active = self._active_requirements[canonicalize_name( requirement.name)] active[requirement] -= 1 if not active[requirement]: del active[requirement] def pinning(self, candidate): print(f"pinning(self, {candidate!r})") assert self._evaluating == candidate or self._evaluating is None self._evaluating = None self._add_candidate(candidate) # Update the graph! node_name, node = self._get_node_for(candidate) node.attr.update(color="#80CC80") # Requirement -> Candidate edges, from this candidate. for req in self._active_requirements[canonicalize_name( candidate.name)]: self._ensure_edge(req, to=candidate, arrowhead="vee", color="#80CC80") # Candidate -> Requirement edges, from this candidate. for edge in self.graph.out_edges_iter([node_name]): edge.attr.update(style="solid", arrowhead="vee", color="#80CC80") _, to = edge to.attr.update(color="#80C080")
def get_node(self, graph: AGraph): return graph.get_node(self.name)
class DotGraphSearchProblem(Problem): """ Playground for stuff in the library... eats a .dot graph and allows you to try it with the search methods. """ def __init__(self, filename): self.G = AGraph(filename) xs = [(nodo, nodo.attr.get("initial", None)) for nodo in self.G.iternodes()] xs = [x for x in xs if x[1]] if len(xs) == 0: raise BadInputGraph("Missing 'initial' node") elif len(xs) > 1: raise BadInputGraph("Cannot have two initial nodes") if not any(nodo.attr.get("goal", None) for nodo in self.G.iternodes()): raise BadInputGraph("Missing a goal state '[goal=\"1\"]'") super(DotGraphSearchProblem, self).__init__(xs[0][0]) self.initial_state.attr["shape"] = "doublecircle" for node in self.G.iternodes(): if self.is_goal(node): node.attr["shape"] = "hexagon" node.attr["color"] = "blue" self.seen = set() self.visit(self.initial_state) for edge in self.G.iteredges(): edge.attr["style"] = "dotted" x = edge.attr.get("weight", None) if x: x = int(x) else: x = 1 edge.attr["weight"] = x edge.attr["label"] = x def actions(self, state): assert state in self.G if self.G.is_directed(): return self.G.itersucc(state) else: assert self.G.is_undirected() return self.G.iterneighbors(state) def result(self, state, action): assert state in self.G and action in self.G self.visit(state) return action def cost(self, state1, action, state2): assert state1 in self.G and action in self.G and action == state2 x = self.G.get_edge(state1, state2).attr["weight"] if float(x) == int(x): return int(x) else: return float(x) def visit(self, state): if state in self.seen: return self.seen.add(state) attr = self.G.get_node(state).attr attr["color"] = "firebrick" def is_goal(self, state): return bool(state.attr.get("goal", False)) def value(self, state): assert state in self.G value = self.G.get_node(state).attr.get("value", None) if not value: return 0 return float(value)
__author__ = """Aric Hagberg ([email protected])""" from pygraphviz import AGraph A = AGraph() # set some default node attributes A.node_attr['style'] = 'filled' A.node_attr['shape'] = 'circle' A.node_attr['fixedsize'] = 'true' A.node_attr['fontcolor'] = '#FFFFFF' # make a star in shades of red for i in range( 16 ): A.add_edge( 0, i ) n = A.get_node( i ) n.attr['fillcolor'] = "#%2x0000" % ( i * 16 ) n.attr['height'] = "%s" % ( i / 16.0 + 0.5 ) n.attr['width'] = "%s" % ( i / 16.0 + 0.5 ) print A.string() # print to screen A.write( "star.dot" ) # write to simple.dot print "Wrote star.dot" A.draw( 'star.png', prog="circo" ) # draw to png using circo print "Wrote star.png" import matplotlib.pyplot as plt a = plt.imread( 'star.png' ) plt.imshow( a ) plt.show()
def dot_layout(cy_elements, edge_labels=False, subgraph_boxes=False, node_gt=None): """ Get a CyElements object and augment it (in-place) with positions, widths, heights, and spline data from a dot based layout. edge_labels is true if labels should appear on edges subgraph_boxes is true if boxes should be drawn around subgraphs Returns the object. """ elements = cy_elements.elements # g = AGraph(directed=True, strict=False) g = AGraph(directed=True, strict=False, forcelabels=True) # make transitive relations appear top to bottom elements = list(elements) nodes_by_id = dict((e["data"]["id"], e) for e in elements if e["group"] == "nodes") order = [ (nodes_by_id[e["data"]["source"]], nodes_by_id[e["data"]["target"]]) for e in elements if e["group"] == "edges" and "transitive" in e["data"] and e["data"]["transitive"] ] elements = topological_sort(elements, order, lambda e: e["data"]["id"]) # get the node id's and stable sort them by cluster # the idea here is to convert the graph into a dag by sorting # the nodes, then reversing the back edges. In particular, we try to make # all the edges between two clusters go in the same direction so clustering # doesn't result in horizontal edges, which dot renders badly. sorted_nodes = [e["data"]["id"] for e in elements if e["group"] == "nodes"] sorted_nodes = sorted(enumerate(sorted_nodes), key=lambda x: (nodes_by_id[x[1]]["data"]["cluster"], x[0])) sorted_nodes = [y for idx, y in sorted_nodes] node_key = dict((id, idx) for idx, id in enumerate(sorted_nodes)) if node_gt is None: node_gt = lambda X, y: False else: node_gt = lambda x, y: node_key[x] > node_key[y] # add nodes to the graph for e in elements: if e["group"] == "nodes" and e["classes"] != "non_existing": g.add_node(e["data"]["id"], label=e["data"]["label"].replace("\n", "\\n")) # TODO: remove this, it's specific to leader_demo weight = {"reach": 10, "le": 10, "id": 1} constraint = {"pending": False} # add edges to the graph for e in elements: if e["group"] == "edges": # kwargs = {'weight': weight.get(e["data"]["obj"], 0)}, kwargs = {"label": e["data"]["label"]} if edge_labels else {} if node_gt(e["data"]["source"], e["data"]["target"]): g.add_edge( e["data"]["target"], e["data"]["source"], e["data"]["id"], dir="back", **kwargs # constraint=constraint.get(e["data"]["obj"], True), ) else: g.add_edge( e["data"]["source"], e["data"]["target"], e["data"]["id"], **kwargs # constraint=constraint.get(e["data"]["obj"], True), ) # add clusters clusters = defaultdict(list) for e in elements: if e["group"] == "nodes" and e["data"]["cluster"] is not None and e["classes"] != "non_existing": clusters[e["data"]["cluster"]].append(e["data"]["id"]) for i, k in enumerate(sorted(clusters.keys())): g.add_subgraph(name="cluster_{}".format(i), nbunch=clusters[k], rank="min") # now get positions, heights, widths, and bsplines g.layout(prog="dot") # get the y origin. we want the top left of the graph to be a # fixed coordinate (hopefully (0,0)) so the graph doesn't jump when # its height changes. Unfortunately, pygraphviz has a bug a gives # the wrong bbox, so we compute the max y coord. # bbox = pygraphviz.graphviz.agget(g.handle,'bb') global y_origin y_origin = 0.0 for n in g.nodes(): top = float(n.attr["pos"].split(",")[1]) + float(n.attr["height"]) / 2 if top > y_origin: y_origin = top if subgraph_boxes: for sg in g.subgraphs(): top = float(sg.graph_attr["bb"].split(",")[3]) if top > y_origin: y_origin = top for e in elements: if e["group"] == "nodes" and e["classes"] != "non_existing": attr = g.get_node(e["data"]["id"]).attr e["position"] = _to_position(attr["pos"]) e["data"]["width"] = 72 * float(attr["width"]) e["data"]["height"] = 72 * float(attr["height"]) elif e["group"] == "edges": if node_gt(e["data"]["source"], e["data"]["target"]): attr = g.get_edge(e["data"]["target"], e["data"]["source"], e["data"]["id"]).attr pos = attr["pos"] pe = pos.split() ppe = pe[1:] ppe.reverse() pos = " ".join([pe[0].replace("s", "e")] + ppe) else: attr = g.get_edge(e["data"]["source"], e["data"]["target"], e["data"]["id"]).attr pos = attr["pos"] e["data"].update(_to_edge_position(pos)) if edge_labels and e["data"]["label"] != "": e["data"]["lp"] = _to_position(attr["lp"]) # g.draw('g.png') if subgraph_boxes: for sg in g.subgraphs(): box = cy_elements.add_shape(sg.name, classes="subgraphs") coords = _to_coord_list(sg.graph_attr["bb"]) box["data"]["coords"] = coords return cy_elements
class DotGraphSearchProblem(Problem): def __init__(self, filename): self.G = AGraph(filename) xs = [(nodo, nodo.attr.get("initial", None)) for nodo in self.G.iternodes()] xs = [x for x in xs if x[1]] if len(xs) == 0: raise BadInputGraph("Missing 'initial' node") elif len(xs) > 1: raise BadInputGraph("Cannot have two initial nodes") if not any(nodo.attr.get("goal", None) for nodo in self.G.iternodes()): raise BadInputGraph("Missing a goal state '[goal=\"1\"]'") super(DotGraphSearchProblem, self).__init__(xs[0][0]) self.initial_state.attr["shape"] = "doublecircle" for node in self.G.iternodes(): if self.is_goal(node): node.attr["shape"] = "hexagon" node.attr["color"] = "blue" self.seen = set() self.visit(self.initial_state) for edge in self.G.iteredges(): edge.attr["style"] = "dotted" x = edge.attr.get("weight", None) if x: x = int(x) else: x = 1 edge.attr["weight"] = x edge.attr["label"] = x def actions(self, state): assert state in self.G if self.G.is_directed(): return self.G.itersucc(state) else: assert self.G.is_undirected() return self.G.iterneighbors(state) def result(self, state, action): assert state in self.G and action in self.G self.visit(state) return action def cost(self, state1, action, state2): assert state1 in self.G and action in self.G and action == state2 x = self.G.get_edge(state1, state2).attr["weight"] if float(x) == int(x): return int(x) else: return float(x) def visit(self, state): if state in self.seen: return self.seen.add(state) attr = self.G.get_node(state).attr attr["color"] = "firebrick" def is_goal(self, state): return bool(state.attr.get("goal", False)) def value(self, state): assert state in self.G value = self.G.get_node(state).attr.get("value", None) if not value: return 0 return float(value)
def convert(graph, desired_ns=[], exclude_ns=[]): # graph.parse('rdf-schema.ttl', format='turtle') # network.feedFactsToAdd(generateTokenSet(graph)) # for n in network.inferredFacts.triples((None, None, None)): # graph.add(n) agraph = AGraph(directed=True, clusterrank="global", rankdir="LR") namespaces = {} nsm = graph.namespace_manager deferred_resources = set() included_resources = set() def prefix(ressource): return nsm.qname(ressource).split(':')[0] def add_ressource(ressource): if ressource not in included_resources: qname = nsm.qname(ressource) prefix = qname.split(':')[0] shape = 'rect' if (ressource, RDF.type, OWL.Class) in graph else 'oval' color = 'black' if prefix in desired_ns else 'grey' if prefix in namespaces: namespaces[prefix].add_node(qname, shape=shape, color=color) else: agraph.add_node(qname, shape=shape, color=color) included_resources.add(ressource) if ressource in deferred_resources: deferred_resources.remove(ressource) def add_edge(r1, r2, **kwargs): pr1, pr2 = prefix(r1), prefix(r2) if pr1 in exclude_ns or pr2 in exclude_ns: return if pr1 in desired_ns or pr2 in desired_ns: add_ressource(r1) add_ressource(r2) agraph.add_edge(nsm.qname(r1), nsm.qname(r2), **kwargs) for kprefix, namespace in graph.namespaces(): namespaces[kprefix] = agraph.add_subgraph(name="cluster_" + kprefix, color="grey") for k in graph.subjects(RDF.type, OWL.Class): if isinstance(k, BNode): continue qname = nsm.qname(k) kprefix = prefix(k) if kprefix in exclude_ns: continue elif kprefix in desired_ns: add_ressource(k) else: deferred_resources.add(k) for (s, p, o) in chain(graph.triples((None, RDFS.subClassOf, None)), graph.triples((None, OWL.subClassOf, None))): if isinstance(s, BNode) or isinstance(o, BNode): continue add_edge(s, o, arrowhead='empty', color="blue") prop_types = [ OWL.Property, OWL.AnnotationProperty, OWL.DatatypeProperty, OWL.AsymmetricProperty, OWL.ObjectProperty, OWL.FunctionalProperty, OWL.InverseFunctionalProperty ] properties = set() for prop in prop_types: properties.update(graph.subjects(RDF.type, prop)) for k in properties: if isinstance(k, BNode): continue qname = nsm.qname(k) kprefix = prefix(k) if kprefix in exclude_ns: continue elif kprefix in desired_ns: add_ressource(k) else: deferred_resources.add(k) for (s, p, o) in chain(graph.triples((None, RDFS.subPropertyOf, None)), graph.triples((None, OWL.subPropertyOf, None))): if isinstance(s, BNode) or isinstance(o, BNode): continue add_edge(s, o, arrowhead='empty', color="blue") for (s, p, o) in graph.triples((None, OWL.equivalentClass, None)): if isinstance(s, BNode) or isinstance(o, BNode): continue add_edge(s, o, arrowhead="odot", arrowtail="odot", color="blue") for (s, p, o) in graph.triples((None, RDFS.domain, None)): if isinstance(s, BNode): continue if isinstance(o, BNode): for o2 in graph.objects(o, OWL.unionOf): for o3 in list_content(o2, graph): add_edge(o3, s, arrowhead="open") for o2 in graph.objects(o, OWL.intersectionOf): for o3 in list_content(o2, graph): add_edge(o3, s, arrowhead="open") continue add_edge(o, s, arrowhead="open") for (s, p, o) in graph.triples((None, RDFS.range, None)): if isinstance(s, BNode): continue if isinstance(o, BNode): for o2 in graph.objects(o, OWL.unionOf): for o3 in list_content(o2, graph): add_edge(s, o3, arrowhead="open") for o2 in graph.objects(o, OWL.intersectionOf): for o3 in list_content(o2, graph): add_edge(s, o3, arrowhead="open") continue add_edge(s, o, arrowhead="open") for (s, p, o) in graph.triples((None, OWL.inverseOf, None)): if isinstance(s, BNode) or isinstance(o, BNode): continue if str(o) < str(s): s, o = o, s add_edge(o, s, arrowhead="crow", arrowtail="crow", dir="both") for ressource in included_resources: labels = graph.objects(ressource, RDFS.label) en_labels = [l for l in labels if l.language == 'eng'] if en_labels: label = en_labels[0] qname = nsm.qname(ressource) prefix, name = qname.split(':', 1) if normalize_label(name) != normalize_label(label): node = agraph.get_node(qname) node.attr['label'] = "%s\n(%s)" % (qname, label) return agraph
def convert_to_a_graph(rdf_graph): multi_di_graph = rdflib_to_networkx_multidigraph(rdf_graph) directed = multi_di_graph.is_directed() strict = nx.number_of_selfloops( multi_di_graph) == 0 and not multi_di_graph.is_multigraph() a_graph = AGraph(name=multi_di_graph.name, strict=strict, directed=directed) a_graph.graph_attr.update( multi_di_graph.graph.get( "graph", { 'label': 'Network Map', 'fontsize': '16', 'fontcolor': 'white', 'bgcolor': '#333333', 'rankdir': 'BT', 'overlap': 'prism', 'splines': 'true' })) a_graph.node_attr.update( multi_di_graph.graph.get( "node", { 'fontname': 'Helvetica', 'fontcolor': 'white', 'color': '#006699', 'style': 'filled', 'fillcolor': '#006699', })) a_graph.edge_attr.update( multi_di_graph.graph.get( "edge", { 'style': 'dashed', 'color': 'green', 'arrowhead': 'open', 'fontname': 'Courier', 'fontsize': '14', 'fontcolor': 'white', })) a_graph.graph_attr.update((k, v) for k, v in multi_di_graph.graph.items() if k not in ("graph", "node", "edge")) for n, node_data in multi_di_graph.nodes(data=True): a_graph.add_node(n) a = a_graph.get_node(n) a.attr.update({k: str(v) for k, v in node_data.items()}) if multi_di_graph.is_multigraph(): for u, v, key, edge_data in multi_di_graph.edges(data=True, keys=True): str_edge_data = { k: str(v) for k, v in edge_data.items() if k != "key" } a_graph.add_edge(u, v, headlabel=str(key)) a = a_graph.get_edge(u, v) a.attr.update(str_edge_data) a_graph.layout() return a_graph
def gen_mul_inputs( dfg: AGraph, fu: AGraph, input_map: Dict[str, int]) -> Tuple[List[Input], List[Output]]: outputs: List[Output] = [] inputs: List[Input] = [] nodes: List[Instruction] = [] for node in fu.nodes(): nodes.append(parse_instruction(node)) nodes.sort() prime_idx = 0 for node in nodes: preds = dfg.predecessors(node.name) parent0 = parse_instruction(preds[0]) parent1 = parse_instruction(preds[1]) label0 = dfg.get_node(parent0.name).attr['label'] label1 = dfg.get_node(parent1.name).attr['label'] i0, edge_case0, prime_idx = gen_mul_input(node, parent0, input_map, inputs, outputs, prime_idx, label0) i1, edge_case1, prime_idx = gen_mul_input(node, parent1, input_map, inputs, outputs, prime_idx, label1) if edge_case0 or edge_case1: expected = None else: expected = i0 * i1 # if parent0.name in input_map: # label = dfg.get_node(parent0.name).attr['label'] # if 'mul' in label: # latency = 2 # else: # latency = 1 # # i0 = PRIMES[prime_idx] # prime_idx += 1 # inputs.append(Input(i0, input_map[parent0.name], parent0.cycle + latency)) # else: # for output in outputs: # if output.cycle == parent0.cycle + 2: # i0 = output.val # break # # if parent1.name in input_map: # label = dfg.get_node(parent1.name).attr['label'] # if 'mul' in label: # latency = 2 # else: # latency = 1 # # i1 = PRIMES[prime_idx] # prime_idx += 1 # inputs.append(Input(i1, input_map[parent1.name], parent1.cycle + latency)) # else: # for output in outputs: # if output.cycle == parent1.cycle + 2: # i1 = output.val # break # expected = i0 * i1 outputs.append(Output(expected, node.cycle + 1)) inputs.sort() return inputs, outputs
def dot_layout(cy_elements): """ Get a CyElements object and augment it (in-place) with positions, widths, heights, and spline data from a dot based layout. Returns the object. """ elements = cy_elements.elements g = AGraph(directed=True, strict=False) # make transitive relations appear top to bottom # TODO: make this not specific to leader example elements = list(elements) nodes_by_id = dict( (e["data"]["id"], e) for e in elements if e["group"] == "nodes" ) order = [ (nodes_by_id[e["data"]["source"]], nodes_by_id[e["data"]["target"]]) for e in elements if e["group"] == "edges" and e["data"]["obj"] in ('reach', 'le') ] elements = topological_sort(elements, order, lambda e: e["data"]["id"]) # add nodes to the graph for e in elements: if e["group"] == "nodes": g.add_node(e["data"]["id"], label=e["data"]["label"].replace('\n', '\\n')) # TODO: remove this, it's specific to leader_demo weight = { 'reach': 10, 'le': 10, 'id': 1, } constraint = { 'pending': False, } # add edges to the graph for e in elements: if e["group"] == "edges": g.add_edge( e["data"]["source"], e["data"]["target"], e["data"]["id"], weight=weight.get(e["data"]["obj"], 0), #constraint=constraint.get(e["data"]["obj"], True), ) # add clusters clusters = defaultdict(list) for e in elements: if e["group"] == "nodes" and e["data"]["cluster"] is not None: clusters[e["data"]["cluster"]].append(e["data"]["id"]) for i, k in enumerate(sorted(clusters.keys())): g.add_subgraph( name='cluster_{}'.format(i), nbunch=clusters[k], ) # now get positions, heights, widths, and bsplines g.layout(prog='dot') for e in elements: if e["group"] == "nodes": attr = g.get_node(e["data"]["id"]).attr e["position"] = _to_position(attr['pos']) e["data"]["width"] = 72 * float(attr['width']) e["data"]["height"] = 72 * float(attr['height']) elif e["group"] == "edges": attr = g.get_edge(e["data"]["source"], e["data"]["target"], e["data"]["id"]).attr e["data"].update(_to_edge_position(attr['pos'])) g.draw('g.png') return cy_elements
def convert(graph, desired_ns=[], exclude_ns=[]): # graph.parse('rdf-schema.ttl', format='turtle') # network.feedFactsToAdd(generateTokenSet(graph)) # for n in network.inferredFacts.triples((None, None, None)): # graph.add(n) agraph = AGraph(directed=True, clusterrank="global", rankdir="LR") namespaces = {} nsm = graph.namespace_manager deferred_resources = set() included_resources = set() def prefix(ressource): return nsm.qname(ressource).split(':')[0] def add_ressource(ressource): if ressource not in included_resources: qname = nsm.qname(ressource) prefix = qname.split(':')[0] shape = 'rect' if ( ressource, RDF.type, OWL.Class) in graph else 'oval' color = 'black' if prefix in desired_ns else 'grey' if prefix in namespaces: namespaces[prefix].add_node(qname, shape=shape, color=color) else: agraph.add_node(qname, shape=shape, color=color) included_resources.add(ressource) if ressource in deferred_resources: deferred_resources.remove(ressource) def add_edge(r1, r2, **kwargs): pr1, pr2 = prefix(r1), prefix(r2) if pr1 in exclude_ns or pr2 in exclude_ns: return if pr1 in desired_ns or pr2 in desired_ns: add_ressource(r1) add_ressource(r2) agraph.add_edge(nsm.qname(r1), nsm.qname(r2), **kwargs) for kprefix, namespace in graph.namespaces(): namespaces[kprefix] = agraph.add_subgraph( name="cluster_"+kprefix, color="grey") for k in graph.subjects(RDF.type, OWL.Class): if isinstance(k, BNode): continue qname = nsm.qname(k) kprefix = prefix(k) if kprefix in exclude_ns: continue elif kprefix in desired_ns: add_ressource(k) else: deferred_resources.add(k) for (s, p, o) in chain(graph.triples((None, RDFS.subClassOf, None)), graph.triples((None, OWL.subClassOf, None))): if isinstance(s, BNode) or isinstance(o, BNode): continue add_edge(s, o, arrowhead='empty', color="blue") prop_types = [OWL.Property, OWL.AnnotationProperty, OWL.DatatypeProperty, OWL.AsymmetricProperty, OWL.ObjectProperty, OWL.FunctionalProperty, OWL.InverseFunctionalProperty] properties = set() for prop in prop_types: properties.update(graph.subjects(RDF.type, prop)) for k in properties: if isinstance(k, BNode): continue qname = nsm.qname(k) kprefix = prefix(k) if kprefix in exclude_ns: continue elif kprefix in desired_ns: add_ressource(k) else: deferred_resources.add(k) for (s, p, o) in chain(graph.triples((None, RDFS.subPropertyOf, None)), graph.triples((None, OWL.subPropertyOf, None))): if isinstance(s, BNode) or isinstance(o, BNode): continue add_edge(s, o, arrowhead='empty', color="blue") for (s, p, o) in graph.triples((None, OWL.equivalentClass, None)): if isinstance(s, BNode) or isinstance(o, BNode): continue add_edge(s, o, arrowhead="odot", arrowtail="odot", color="blue") for (s, p, o) in graph.triples((None, RDFS.domain, None)): if isinstance(s, BNode): continue if isinstance(o, BNode): for o2 in graph.objects(o, OWL.unionOf): for o3 in list_content(o2, graph): add_edge(o3, s, arrowhead="open") for o2 in graph.objects(o, OWL.intersectionOf): for o3 in list_content(o2, graph): add_edge(o3, s, arrowhead="open") continue add_edge(o, s, arrowhead="open") for (s, p, o) in graph.triples((None, RDFS.range, None)): if isinstance(s, BNode): continue if isinstance(o, BNode): for o2 in graph.objects(o, OWL.unionOf): for o3 in list_content(o2, graph): add_edge(s, o3, arrowhead="open") for o2 in graph.objects(o, OWL.intersectionOf): for o3 in list_content(o2, graph): add_edge(s, o3, arrowhead="open") continue add_edge(s, o, arrowhead="open") for (s, p, o) in graph.triples((None, OWL.inverseOf, None)): if isinstance(s, BNode) or isinstance(o, BNode): continue if str(o) < str(s): s, o = o, s add_edge(o, s, arrowhead="crow", arrowtail="crow", dir="both") for ressource in included_resources: labels = graph.objects(ressource, RDFS.label) en_labels = [l for l in labels if l.language == 'eng'] if en_labels: label = en_labels[0] qname = nsm.qname(ressource) prefix, name = qname.split(':', 1) if normalize_label(name) != normalize_label(label): node = agraph.get_node(qname) node.attr['label'] = "%s\n(%s)" % (qname, label) return agraph
def create_graph(filename, layout="dot", use_singularity=False, color_for_disabled_converter='red'): """ :param filename: should end in .png or .svg or .dot If extension is .dot, only the dot file is created. This is useful if you have issues installing graphviz. If so, under Linux you could use our singularity container see github.com/cokelaer/graphviz4all """ from bioconvert.core.registry import Registry rr = Registry() try: if filename.endswith(".dot") or use_singularity is True: raise Exception() from pygraphviz import AGraph dg = AGraph(directed=True) url = "https://bioconvert.readthedocs.io/en/master/formats.html#{}" for a, b, s in rr.get_all_conversions(): if len(a) == 1 and len(b) == 1: dg.add_node(a[0], shape="rectangle", style="filled", url=url.format(a[0].upper())) dg.add_node(b[0], shape="rectangle", style="filled", url=url.format(b[0].upper())) dg.add_edge( a[0], b[0], color='black' if s else color_for_disabled_converter) else: and_node = "_".join(a) + "_and_" + "_".join(b) dg.add_node(and_node, label="", fillcolor="black", width=.1, height=.1, styled="filled", fixedsize=True, shape="circle") for this in a: dg.add_edge( this, and_node, color="black" if s else color_for_disabled_converter) for this in b: dg.add_edge( and_node, this, color="black" if s else color_for_disabled_converter) for name in dg.nodes(): if dg.degree(name) < 5: dg.get_node(name).attr["fillcolor"] = "white" elif dg.degree(name) < 10: # yellow dg.get_node(name).attr["fillcolor"] = "yellow" elif dg.degree(name) < 20: # orange dg.get_node(name).attr["fillcolor"] = "orange" else: # red dg.get_node(name).attr["fillcolor"] = "red" dg.layout(layout) dg.draw(filename) dg.write("conversion.dot") print(list(dg.get_node("FASTQ").attr.values())) except Exception as e: _log.error(e) dot = """ strict digraph{ node [label="\\N"]; """ nodes = set([ item for items in rr.get_all_conversions() for item in items[0:1] ]) for node in nodes: dot += "\"{}\";\n".format(node) for a, b, s in rr.get_all_conversions(): dot += "\"{}\" -> \"{}\";\n".format(a, b) dot += "}\n" from easydev import TempFile from bioconvert import shell dotfile = TempFile(suffix=".dot") with open(dotfile.name, "w") as fout: fout.write(dot) dotpath = "" if use_singularity: from bioconvert.core.downloader import download_singularity_image singfile = download_singularity_image( "graphviz.simg", "shub://cokelaer/graphviz4all:v1", "4288088d91c848e5e3a327282a1ab3d1") dotpath = "singularity run {} ".format(singfile) on_rtd = environ.get('READTHEDOCS', None) == 'True' if on_rtd: dotpath = "" ext = filename.rsplit(".", 1)[1] cmd = "{}dot -T{} {} -o {}".format(dotpath, ext, dotfile.name, filename) print(dotfile.name) try: shell(cmd) except: import os os.system(cmd)