def __init__(self, **kwargs): self.output_file = 'pycallgraph.dot' self.font_name = 'Verdana' self.font_size = 7 self.group_font_size = 10 self.group_border_color = Color(0, 0, 0, 0.8) Output.__init__(self, **kwargs) self.prepare_graph_attributes()
def edge_color(self, edge): value = float(edge.time.fraction) return Color.hsv(value / 2 + .5, value, 0.7)
def node_color(self, node): value = float(node.time.fraction) return Color.hsv(value / 2 + .5, value, 0.9)
class DotGraphvizOutput(Output): """ Generates """ def __init__(self, **kwargs): self.output_file = 'pycallgraph.dot' self.font_name = 'Verdana' self.font_size = 7 self.group_font_size = 10 self.group_border_color = Color(0, 0, 0, 0.8) Output.__init__(self, **kwargs) self.prepare_graph_attributes() def prepare_graph_attributes(self): generated_message = '\\n'.join([ r'Generated by Python Call Graph v%s' % __version__, r'http://pycallgraph.slowchop.com', ]) self.graph_attributes = { 'graph': { 'overlap': 'scalexy', 'fontname': self.font_name, 'fontsize': self.font_size, 'fontcolor': Color(0, 0, 0, 0.5).rgba_web(), 'label': generated_message, }, 'node': { 'fontname': self.font_name, 'fontsize': self.font_size, 'fontcolor': Color(0, 0, 0).rgba_web(), 'style': 'filled', 'shape': 'rect', }, 'edge': { 'fontname': self.font_name, 'fontsize': self.font_size, 'fontcolor': Color(0, 0, 0).rgba_web(), } } def done(self): source = self.generate() self.debug(source) with open(self.output_file, 'w') as f: f.write(source) def generate(self): '''Returns a string with the contents of a DOT file for Graphviz to parse. ''' indent_join = '\n' + ' ' * 12 return textwrap.dedent('''\ digraph G {{ // Attributes {} // Groups {} // Nodes {} // Edges {} }} '''.format( indent_join.join(self.generate_attributes()), indent_join.join(self.generate_groups()), indent_join.join(self.generate_nodes()), indent_join.join(self.generate_edges()), )) def attrs_from_dict(self, d): output = [] for attr, val in d.iteritems(): output.append('%s = "%s"' % (attr, val)) return ', '.join(output) def node(self, key, attr): return '"{}" [{}];'.format( key, self.attrs_from_dict(attr), ) def edge(self, edge, attr): return '"{0.src_func}" -> "{0.dst_func}" [{1}];'.format( edge, self.attrs_from_dict(attr), ) def generate_attributes(self): output = [] for section, attrs in self.graph_attributes.iteritems(): output.append('{} [ {} ];'.format( section, self.attrs_from_dict(attrs), )) return output def generate_groups(self): if not self.processor.config.groups: return '' output = [] for group, nodes in self.processor.groups(): funcs = [node.name for node in nodes] funcs = '" "'.join(funcs) group_color = self.group_border_color.rgba_web() group_font_size = self.group_font_size output.append( 'subgraph "cluster_{group}" {{ ' '"{funcs}"; ' 'label = "{group}"; ' 'fontsize = "{group_font_size}"; ' 'fontcolor = "black"; ' 'style = "bold"; ' 'color="{group_color}"; }}'.format(**locals())) return output def generate_nodes(self): output = [] for node in self.processor.nodes(): attr = { 'color': self.node_color_func(node).rgba_web(), 'label': self.node_label_func(node), } output.append(self.node(node.name, attr)) return output def generate_edges(self): output = [] for edge in self.processor.edges(): attr = { 'color': self.edge_color_func(edge).rgba_web(), 'label': self.edge_label_func(edge), } output.append(self.edge(edge, attr)) return output