GraphViz is a cool & powerful open source graphics library. In my case it might have just saved a large amount of effort, if we were to build it from scratch. So, I thought I will share the approach we followed in our project, so that it can help others..,
Installing GraphViz:
- Download the Windows MSI file for windows from http://www.graphviz.org/Download.php
- Backup the Path variable contents (Note: As a rule of thumb you should be doing this each time when you install a new software and the install could mess up your system variables)
- After installing the tool, you might have to log-off and log in for the path variable change to kick in (or reboot)
Add the GraphViz interface class to your solution:
I found this class somewhere in the internet, (I forgot where I got from), and I have added few methods to make it work for my requirement.
Class:
public static class Graphviz {
public const string LIB_GVC = "gvc.dll";
public const string LIB_GRAPH = "graph.dll";
public const int SUCCESS = 0;
///
/// Creates a new Graphviz context.
///
[DllImport(LIB_GVC)]
public static extern IntPtr gvContext();
///
/// Releases a context's resources.
///
[DllImport(LIB_GVC)]
public static extern int gvFreeContext(IntPtr gvc);
///
/// Reads a graph from a string.
///
[DllImport(LIB_GRAPH)]
public static extern IntPtr agmemread(string data);
///
/// Releases the resources used by a graph.
///
[DllImport(LIB_GRAPH)]
public static extern void agclose(IntPtr g);
///
/// Applies a layout to a graph using the given engine.
///
[DllImport(LIB_GVC)]
public static extern int gvLayout(IntPtr gvc, IntPtr g, string engine);
///
/// Releases the resources used by a layout.
///
[DllImport(LIB_GVC)]
public static extern int gvFreeLayout(IntPtr gvc, IntPtr g);
///
/// Renders a graph to a file.
///
[DllImport(LIB_GVC)]
public static extern int gvRenderFilename(IntPtr gvc, IntPtr g,
string format, string fileName);
///
/// Renders a graph in memory.
///
[DllImport(LIB_GVC)]
public static extern int gvRenderData(IntPtr gvc, IntPtr g,
string format, out IntPtr result, out int length);
public static Image RenderImage(string source, string layout, string format) {
// Create a Graphviz context
IntPtr gvc = gvContext();
if (gvc == IntPtr.Zero)
throw new Exception("Failed to create Graphviz context.");
// Load the DOT data into a graph
IntPtr g = agmemread(source);
if (g == IntPtr.Zero)
throw new Exception("Failed to create graph from source. Check for syntax errors.");
// Apply a layout
if (gvLayout(gvc, g, layout) != SUCCESS)
throw new Exception("Layout failed.");
IntPtr result;
int length;
// Render the graph
if (gvRenderData(gvc, g, format, out result, out length) != SUCCESS)
throw new Exception("Render failed.");
// Create an array to hold the rendered graph
byte[] bytes = new byte[length];
// Copy the image from the IntPtr
Marshal.Copy(result, bytes, 0, length);
// Free up the resources
gvFreeLayout(gvc, g);
agclose(g);
gvFreeContext(gvc);
using (MemoryStream stream = new MemoryStream(bytes)) {
return Image.FromStream(stream);
}
}
}
Code to write to file:
try
{
//Convert to byte stream
Byte[] image = Graphviz.RenderImage(graphVizString, "dot", "png");
currentGUIDo = Guid.NewGuid().ToString();
strCurrentFileName = ConfigurationManager.AppSettings["ImagePath"].ToString() + currentGUIDo +".png";
FileStream file = new FileStream(strCurrentFileName, FileMode.Create);
//Write the image to the file
file.Write(image, 0, image.Length);
//close the file
file.Close();
}
catch (Exception ex)
{
//TODO:Impelement exception handling
}
Finally, I had a button where this will be called , and just transmit the file:
if (File.Exists(strCurrentFileName))
{
Response.TransmitFile(strCurrentFileName);
}
Sample values you could use for graphVizString:
Sample 1:
digraph {
Entity1 -> Entity2, Entity1 -> Entity3
Entity1 [shape="circle"] , Entity2 [shape="rectangle"]
}
Sample 2:
digraph {
a -> b [label=relation1],b->c[label=relation2],c->d[label=relation3],e->c [label=relation4]
a [shape=box,color=red,label="Box-A"], b[shape=triangle,color=yellow],e [shape=invtriangle],c [shape=square],d[shape=rectangle]
}
Produces an output:
Sample 3:
digraph {
a -> b [label=relation1],b->c[label=relation2],c->d[label=relation3],e->c [label=relation4], e->d [label=relation5]
a [shape=box,color=red,label="Box-A"],
b [shape=triangle,color=yellow, label="Triangle-B"],
e [shape=invtriangle, label="Inverse Triangle-C"],
c [shape=square,label="Square - C"],
d [shape=rectangle,label="Rectangle - D"]
}
2 comments:
it looks helpful but i couldnt get the Code to write to file: section which file it is and how to set the paths
https://www.codeproject.com/Articles/1164156/%2FArticles%2F1164156%2FUsing-Graphviz-in-your-project-to-create-graphs-fr
https://github.com/JamieDixon/GraphViz-C-Sharp-Wrapper
http://www.fssnip.net/7Rf/title/Generating-GraphViz-images-using-C-wrapper
https://codefreezr.github.io/awesome-graphviz/
Post a Comment