Interface Documentation
Version: invalid
graphviz.hh
1 /*
2  @@@@@@@@ @@ @@@@@@ @@@@@@@@ @@
3  /@@///// /@@ @@////@@ @@////// /@@
4  /@@ /@@ @@@@@ @@ // /@@ /@@
5  /@@@@@@@ /@@ @@///@@/@@ /@@@@@@@@@/@@
6  /@@//// /@@/@@@@@@@/@@ ////////@@/@@
7  /@@ /@@/@@//// //@@ @@ /@@/@@
8  /@@ @@@//@@@@@@ //@@@@@@ @@@@@@@@ /@@
9  // /// ////// ////// //////// //
10 
11  Copyright (c) 2016, Triad National Security, LLC
12  All rights reserved.
13  */
14 #pragma once
15 
16 #include <flecsi-config.h>
17 
18 #include "flecsi/flog.hh"
19 
20 #if !defined(FLECSI_ENABLE_GRAPHVIZ)
21 #error FLECSI_ENABLE_GRAPHVIZ not defined! This file depends on Graphviz!
22 #endif
23 
24 #include <graphviz/gvc.h>
25 
26 namespace flecsi {
27 namespace util {
28 
29 // attribute strings
30 static constexpr const char * gv_graph = "graph";
31 static constexpr const char * gv_label_default = "";
32 static constexpr const char * gv_label = "label";
33 static constexpr const char * gv_color = "color";
34 static constexpr const char * gv_color_black = "black";
35 static constexpr const char * gv_penwidth = "penwidth";
36 static constexpr const char * gv_penwidth_default = "";
37 static constexpr const char * gv_shape = "shape";
38 static constexpr const char * gv_shape_default = "ellipse";
39 static constexpr const char * gv_style = "style";
40 static constexpr const char * gv_style_default = "";
41 static constexpr const char * gv_fill_color = "fillcolor";
42 static constexpr const char * gv_color_lightgrey = "lightgrey";
43 static constexpr const char * gv_font_color = "fontcolor";
44 static constexpr const char * gv_dir = "dir";
45 static constexpr const char * gv_dir_default = "forward";
46 static constexpr const char * gv_headport = "headport";
47 static constexpr const char * gv_headport_default = "c";
48 static constexpr const char * gv_tailport = "tailport";
49 static constexpr const char * gv_tailport_default = "c";
50 static constexpr const char * gv_arrowsize = "arrowsize";
51 static constexpr const char * gv_arrowsize_default = "0.75";
52 static constexpr const char * gv_arrowhead = "arrowhead";
53 static constexpr const char * gv_arrowhead_default = "normal";
54 static constexpr const char * gv_arrowtail = "arrowtail";
55 static constexpr const char * gv_arrowtail_default = "normal";
56 
57 #define GV_GRAPH const_cast<char *>(gv_graph)
58 #define GV_LABEL const_cast<char *>(gv_label)
59 #define GV_LABEL_DEFAULT const_cast<char *>(gv_label_default)
60 #define GV_PENWIDTH const_cast<char *>(gv_penwidth)
61 #define GV_PENWIDTH_DEFAULT const_cast<char *>(gv_penwidth_default)
62 #define GV_COLOR const_cast<char *>(gv_color)
63 #define GV_COLOR_BLACK const_cast<char *>(gv_color_black)
64 #define GV_SHAPE const_cast<char *>(gv_shape)
65 #define GV_SHAPE_DEFAULT const_cast<char *>(gv_shape_default)
66 #define GV_STYLE const_cast<char *>(gv_style)
67 #define GV_STYLE_DEFAULT const_cast<char *>(gv_style_default)
68 #define GV_FILL_COLOR const_cast<char *>(gv_fill_color)
69 #define GV_COLOR_LIGHTGREY const_cast<char *>(gv_color_lightgrey)
70 #define GV_FONT_COLOR const_cast<char *>(gv_font_color)
71 #define GV_DIR const_cast<char *>(gv_dir)
72 #define GV_DIR_DEFAULT const_cast<char *>(gv_dir_default)
73 #define GV_HEADPORT const_cast<char *>(gv_headport)
74 #define GV_HEADPORT_DEFAULT const_cast<char *>(gv_headport_default)
75 #define GV_TAILPORT const_cast<char *>(gv_tailport)
76 #define GV_TAILPORT_DEFAULT const_cast<char *>(gv_tailport_default)
77 #define GV_ARROWSIZE const_cast<char *>(gv_arrowsize)
78 #define GV_ARROWSIZE_DEFAULT const_cast<char *>(gv_arrowsize_default)
79 #define GV_ARROWHEAD const_cast<char *>(gv_arrowhead)
80 #define GV_ARROWHEAD_DEFAULT const_cast<char *>(gv_arrowhead_default)
81 #define GV_ARROWTAIL const_cast<char *>(gv_arrowtail)
82 #define GV_ARROWTAIL_DEFAULT const_cast<char *>(gv_arrowtail_default)
83 
84 const int ag_create(1);
85 const int ag_access(0);
86 
87 /*----------------------------------------------------------------------------*
88  * Class for creating Graphviz trees.
89  *----------------------------------------------------------------------------*/
90 
91 class graphviz
92 {
93 public:
94  graphviz() : gvc_(nullptr), graph_(nullptr) {
95  gvc_ = gvContext();
96  clear();
97  } // graphviz
98 
99  ~graphviz() {
100  if(graph_ != nullptr) {
101  gvFreeLayout(gvc_, graph_);
102  agclose(graph_);
103  } // if
104 
105  gvFreeContext(gvc_);
106  } // ~graphviz
107 
108  /*-------------------------------------------------------------------------*
109  * Clear the graph. This call is a little counter-intuitive. It frees
110  * the currently allocated graph and creates a new empty one in its place.
111  * Therefore, there is always a graph instance available.
112  *-------------------------------------------------------------------------*/
113 
114  void clear() {
115  if(graph_ != nullptr) {
116  gvFreeLayout(gvc_, graph_);
117  agclose(graph_);
118  } // if
119 
120  graph_ = agopen(GV_GRAPH, Agdirected, nullptr);
121  agattr(
122  graph_, AGRAPH, const_cast<char *>("nodesep"), const_cast<char *>(".5"));
123 
124  // set default node attributes
125  agattr(graph_, AGNODE, GV_LABEL, GV_LABEL_DEFAULT);
126  agattr(graph_, AGNODE, GV_PENWIDTH, GV_PENWIDTH_DEFAULT);
127  agattr(graph_, AGNODE, GV_COLOR, GV_COLOR_BLACK);
128  agattr(graph_, AGNODE, GV_SHAPE, GV_SHAPE_DEFAULT);
129  agattr(graph_, AGNODE, GV_STYLE, GV_STYLE_DEFAULT);
130  agattr(graph_, AGNODE, GV_FILL_COLOR, GV_COLOR_LIGHTGREY);
131  agattr(graph_, AGNODE, GV_FONT_COLOR, GV_COLOR_BLACK);
132 
133  // set default edge attributes
134  agattr(graph_, AGEDGE, GV_DIR, GV_DIR_DEFAULT);
135  agattr(graph_, AGEDGE, GV_LABEL, GV_LABEL_DEFAULT);
136  agattr(graph_, AGEDGE, GV_PENWIDTH, GV_PENWIDTH_DEFAULT);
137  agattr(graph_, AGEDGE, GV_COLOR, GV_COLOR_BLACK);
138  agattr(graph_, AGEDGE, GV_STYLE, GV_STYLE_DEFAULT);
139  agattr(graph_, AGEDGE, GV_FILL_COLOR, GV_COLOR_BLACK);
140  agattr(graph_, AGEDGE, GV_FONT_COLOR, GV_COLOR_BLACK);
141  agattr(graph_, AGEDGE, GV_HEADPORT, GV_HEADPORT_DEFAULT);
142  agattr(graph_, AGEDGE, GV_TAILPORT, GV_TAILPORT_DEFAULT);
143  agattr(graph_, AGEDGE, GV_ARROWSIZE, GV_ARROWSIZE_DEFAULT);
144  agattr(graph_, AGEDGE, GV_ARROWHEAD, GV_ARROWHEAD_DEFAULT);
145  agattr(graph_, AGEDGE, GV_ARROWTAIL, GV_ARROWTAIL_DEFAULT);
146  } // clear
147 
148  /*-------------------------------------------------------------------------*
149  * Add a node to the graph.
150  *
151  * If 'label' is non-null, it will be used for the display name of the node.
152  *-------------------------------------------------------------------------*/
153 
154  Agnode_t * add_node(const char * name, const char * label = nullptr) {
155  char buffer[1024];
156  sprintf(buffer, "%s", name);
157  Agnode_t * node = agnode(graph_, buffer, ag_create);
158 
159  if(label != nullptr) {
160  char attr[1024];
161  sprintf(attr, "%s", "label");
162  sprintf(buffer, "%s", label);
163  agset(node, attr, buffer);
164  } // if
165 
166  return node;
167  } // add_node
168 
169  Agnode_t * node(const char * name) {
170  char buffer[1024];
171  sprintf(buffer, "%s", name);
172  return agnode(graph_, buffer, ag_access);
173  } // node
174 
175  /*-------------------------------------------------------------------------*
176  * Remove a node from the graph.
177  *-------------------------------------------------------------------------*/
178 
179  void remove_node(const char * name) {
180  char buffer[1024];
181  sprintf(buffer, "%s", name);
182  Agnode_t * node = agfindnode(graph_, buffer);
183 
184  if(node != nullptr) {
185  agdelete(graph_, node);
186  } // if
187  } // remove_node
188 
189  /*-------------------------------------------------------------------------*
190  * Set a node attribute.
191  *-------------------------------------------------------------------------*/
192 
193  void
194  set_node_attribute(const char * name, const char * attr, const char * value) {
195  char buffer[1024];
196  sprintf(buffer, "%s", name);
197  Agnode_t * node = agnode(graph_, buffer, ag_access);
198 
199  if(node == nullptr) {
200  flog(warn) << "node " << name << " does not exist";
201  return;
202  } // if
203 
204  char _attr[1024];
205  char _value[1024];
206  sprintf(_attr, "%s", attr);
207  sprintf(_value, "%s", value);
208  agset(node, _attr, _value);
209  } // set_node_attribute
210 
211  void
212  set_node_attribute(Agnode_t * node, const char * attr, const char * value) {
213  char _attr[1024];
214  char _value[1024];
215  sprintf(_attr, "%s", attr);
216  sprintf(_value, "%s", value);
217  agset(node, _attr, _value);
218  } // set_node_attribute
219 
220  /*-------------------------------------------------------------------------*
221  * Append to node label.
222  *-------------------------------------------------------------------------*/
223 
224  void set_label(const char * name, const char * label) {
225  char buffer[1024];
226  sprintf(buffer, "%s", name);
227  Agnode_t * node = agnode(graph_, buffer, ag_access);
228 
229  if(node == nullptr) {
230  flog(warn) << "node " << name << " does not exist";
231  return;
232  } // if
233 
234  set_node_attribute(name, "label", label);
235  } // append_node_label
236 
237  /*-------------------------------------------------------------------------*
238  * Get a node attribute.
239  *-------------------------------------------------------------------------*/
240 
241  char * get_node_attribute(const char * name, const char * attr) {
242  char buffer[1024];
243  sprintf(buffer, "%s", name);
244  Agnode_t * node = agnode(graph_, buffer, ag_access);
245 
246  if(node == nullptr) {
247  flog(warn) << "node " << name << " does not exist";
248  return nullptr;
249  } // if
250 
251  char _attr[1024];
252  sprintf(_attr, "%s", attr);
253  return agget(node, _attr);
254  } // set_node_attribute
255 
256  int inedge_count(const char * name) {
257  char buffer[1024];
258  sprintf(buffer, "%s", name);
259  Agnode_t * node = agnode(graph_, buffer, ag_access);
260 
261  if(node == nullptr) {
262  flog(warn) << "node " << name << " does not exist";
263  return -1;
264  } // if
265 
266  return agdegree(graph_, node, true, false);
267  } // edge_count
268 
269  /*-------------------------------------------------------------------------*
270  * Add an edge to the graph.
271  *-------------------------------------------------------------------------*/
272 
273  Agedge_t * add_edge(Agnode_t * parent, Agnode_t * child) {
274  return agedge(graph_, parent, child, nullptr, ag_create);
275  } // add_edge
276 
277  void
278  set_edge_attribute(Agedge_t * edge, const char * attr, const char * value) {
279  char _attr[1024];
280  char _value[1024];
281  sprintf(_attr, "%s", attr);
282  sprintf(_value, "%s", value);
283  agset(edge, _attr, _value);
284  } // set_edge_attribute
285 
286  /*-------------------------------------------------------------------------*
287  * Compute a layout using the specified engine.
288  *-------------------------------------------------------------------------*/
289 
290  void layout(const char * engine) {
291  char _engine[1024];
292  sprintf(_engine, "%s", engine);
293  // FIXME: Error handling
294  gvLayout(gvc_, graph_, _engine);
295  } // layout
296 
297  /*-------------------------------------------------------------------------*
298  * Write the current layout to file.
299  *-------------------------------------------------------------------------*/
300 
301  // FIXME: May need to check that a valid layout exists.
302  void write(const std::string & name) {
303  write(name.c_str());
304  } // write
305 
306  void write(const char * name) {
307  FILE * file = fopen(name, "w");
308 
309  if(name == nullptr) {
310  flog_fatal("failed opening " << name);
311  } // if
312 
313  agwrite(graph_, file);
314  fclose(file);
315  } // write
316 
317 private:
318  // private data members
319  GVC_t * gvc_;
320  Agraph_t * graph_;
321 
322 }; // class graphviz
323 
324 } // namespace util
325 } // namespace flecsi
Definition: graphviz.hh:91
#define flog(severity)
Definition: flog.hh:136
#define flog_fatal(message)
Definition: flog.hh:358
Definition: control.hh:31