Skip to content

Instantly share code, notes, and snippets.

@gpduck
Created November 26, 2015 04:22
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gpduck/3367596eb7f1518dbae7 to your computer and use it in GitHub Desktop.
Save gpduck/3367596eb7f1518dbae7 to your computer and use it in GitHub Desktop.
function New-Node {
[OutputType("Whatsupduck.Powershell.GraphViz.Node")]
param(
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[String]$Name,
[Parameter(Mandatory=$false)]
[ValidateNotNullOrEmpty()]
[String]$Label,
[Parameter(Mandatory=$false)]
[Whatsupduck.Powershell.GraphViz.Shapes]$Shape,
[Parameter(Mandatory=$false)]
[ValidateRange(0,[Double]::MaxValue)]
[Double]$Height,
[Parameter(Mandatory=$false)]
[ValidateRange(0,[Double]::MaxValue)]
[Double]$Width
)
$node = New-Object -TypeName Whatsupduck.Powershell.GraphViz.Node
$node.Name = $Name
$node | Get-Member -MemberType Property | Select-Object -ExpandProperty Name | %{
if($PSBoundParameters.ContainsKey($_)) {
$node."$_" = $PSBoundParameters[$_]
}
}
Write-Output $node
}
function New-Graph {
[OutputType("Whatsupduck.Powershell.GraphViz.Graph")]
param(
[Parameter(Mandatory=$false)]
[ValidateNotNullOrEmpty()]
[String]$Name,
[Parameter(Mandatory=$false)]
[switch]$Directed,
[String]$Label,
[String]$Color,
[Whatsupduck.Powershell.GraphViz.RankDir]$RankDir,
[String]$Style,
[Switch]$Concentrate
)
if($Directed) {
$Graph = New-Object -TypeName Whatsupduck.Powershell.GraphViz.DirectedGraph
} else {
$Graph = New-Object -TypeName Whatsupduck.Powershell.GraphViz.UndirectedGraph
}
$PSBoundParameters.Keys | ?{$_ -ne "Directed"} | %{
$KeyName = $_
$KeyValue = $PSBoundParameters[$KeyName]
$Graph."$KeyName" = $KeyValue
}
Write-Output $Graph
}
<#
.PARAMETER Shape
The shape for the node. The default is ellipse.
See http://www.graphviz.org/doc/info/shapes.html for a visual depiction of all shapes.
#>
function Add-Node {
[OutputType("Whatsupduck.Powershell.GraphViz.Graph")]
param(
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[String]$Name,
[Parameter(Mandatory=$false)]
[ValidateNotNullOrEmpty()]
[String]$Label,
[Parameter(Mandatory=$false)]
[Whatsupduck.Powershell.GraphViz.Shapes]$Shape,
[Parameter(Mandatory=$false)]
[ValidateRange(0,[Double]::MaxValue)]
[Double]$Height,
[Parameter(Mandatory=$false)]
[ValidateRange(0,[Double]::MaxValue)]
[Double]$Width,
[Parameter(Mandatory=$true,ValueFromPipeline=$true)]
[Whatsupduck.Powershell.GraphViz.Graph]$Graph
)
begin {
$NewNodeParams = @{}
$PSBoundParameters.Keys | ?{$_ -ne "Graph" } | %{
$NewNodeParams.Add($_, $PSBoundParameters[$_])
}
}
process {
$Graph.AddNode( (New-Node @NewNodeParams))
Write-Output $Graph
}
}
function New-Edge {
[OutputType("Whatsupduck.Powershell.GraphViz.Edge")]
param(
[Parameter(Mandatory=$true,ParameterSetName="DirectedEdge")]
[ValidateNotNullOrEmpty()]
[String]$SourceName,
[Parameter(Mandatory=$true,ParameterSetName="DirectedEdge")]
[ValidateNotNullOrEmpty()]
[String]$TargetName,
[Parameter(Mandatory=$true,ParameterSetName="UndirectedEdge")]
[ValidateCount(2,[Int32]::MaxValue)]
[String[]]$Names,
[Parameter(Mandatory=$false,ParameterSetName="DirectedEdge")]
[Parameter(Mandatory=$false,ParameterSetName="UnirectedEdge")]
[ValidateNotNullOrEmpty()]
[String]$Label
)
switch ($PSCmdlet.ParameterSetName) {
"DirectedEdge" {
$Edge = New-Object -TypeName Whatsupduck.Powershell.GraphViz.DirectedEdge
$Edge.SourceName = $SourceName
$Edge.TargetName = $TargetName
if($Label) {
$Edge.Label = $Label
}
Write-Output $Edge
}
"UndirectedEdge" {
$PreviousName = $null
$Names | %{
if($PreviousName) {
$Edge = New-Object -TypeName Whatsupduck.Powershell.GraphViz.UndirectedEdge
$Edge.SourceName = $PreviousName
$Edge.TargetName = $_
if($Label) {
$Edge.Label = $Label
}
Write-Output $Edge
}
$PreviousName = $_
}
}
default {
throw "Unknown parameter set name"
}
}
}
function Add-Edge {
[OutputType("Whatsupduck.Powershell.GraphViz.Graph")]
param(
[Parameter(Mandatory=$true,ParameterSetName="DirectedEdge")]
[ValidateNotNullOrEmpty()]
[String]$SourceName,
[Parameter(Mandatory=$true,ParameterSetName="DirectedEdge")]
[ValidateNotNullOrEmpty()]
[String]$TargetName,
[Parameter(Mandatory=$true,ParameterSetName="UndirectedEdge")]
[ValidateCount(2,[Int32]::MaxValue)]
[String[]]$Names,
[Parameter(Mandatory=$false,ParameterSetName="DirectedEdge")]
[Parameter(Mandatory=$false,ParameterSetName="UnirectedEdge")]
[ValidateNotNullOrEmpty()]
[String]$Label,
[Parameter(Mandatory=$true,ValueFromPipeline=$true,ParameterSetName="DirectedEdge")]
[Parameter(Mandatory=$true,ValueFromPipeline=$true,ParameterSetName="UndirectedEdge")]
[ValidateNotNullOrEmpty()]
[Whatsupduck.Powershell.GraphViz.Graph]$Graph
)
begin {
$EdgeParameters = @{}
$PSBoundParameters.Keys | ?{$_ -ne "Graph"} | %{
$EdgeParameters.Add($_, $PSBoundParameters[$_])
}
}
process {
if($Graph -is [Whatsupduck.Powershell.GraphViz.UndirectedGraph] -and $PSCmdlet.ParameterSetName -eq "DirectedEdge") {
Write-Error "Unable to add a directed edge ($SourceName -> $TargetName) to an undirected graph $(Graph.Name)"
} else {
New-Edge @EdgeParameters | %{
$Graph.AddEdge($_)
}
Write-Output $Graph
}
}
}
function ConvertTo-Dot {
[OutputType("System.String")]
param(
[Parameter(Mandatory=$true,ValueFromPipeline=$true)]
[ValidateNotNullOrEmpty()]
[Whatsupduck.Powershell.GraphViz.Graph]$Graph
)
process {
Write-Output $Graph.ToDot();
}
}
function Out-GraphViz {
param(
[Parameter(Mandatory=$true,ParameterSetName="FromDot")]
[Parameter(Mandatory=$true,ParameterSetName="FromGraph")]
[ValidateNotNullOrEmpty()]
[String]$Path,
[Parameter(Mandatory=$true,ParameterSetName="FromDot")]
[ValidateSet("dot","neato","circo","fdp","osage","sfdp","twopi")]
[String]$LayoutEngine,
[Parameter(Mandatory=$true,ValueFromPipeline=$true,ParameterSetName="FromDot")]
[ValidateNotNullOrEmpty()]
[String]$Dot,
[Parameter(Mandatory=$true,ValueFromPipeline=$true,ParameterSetName="FromGraph")]
[ValidateNotNullOrEmpty()]
[Whatsupduck.Powershell.GraphViz.Graph]$Graph,
[Parameter(Mandatory=$false,ParameterSetName="FromDot")]
[Parameter(Mandatory=$false,ParameterSetName="FromGraph")]
[switch]$Show
)
begin {
if($Env:PROCESSOR_ARCHITECTURE -eq "amd64") {
$GraphVizRegistryPath = "HKLM:\Software\Wow6432Node\AT&T Research Labs\Graphviz*"
} else {
$GraphVizRegistryPath = "HKLM:\Software\AT&T Research Labs\Graphviz*"
}
$GraphVizRegistry = Get-Item $GraphVizRegistryPath -ErrorAction SilentlyContinue
if($GraphVizRegistry) {
$GraphVizInstallPath = $GraphVizRegistry.GetValue("InstallPath")
}
if( !(Test-Path (Join-Path $GraphVizInstallPath "bin\dot.exe")) ) {
throw "Unable to locate GraphViz installation folder"
}
}
process {
switch ($PSCmdlet.ParameterSetName) {
"FromDot" {
#do nothing special
}
"FromGraph" {
$Dot = $Graph.ToDot()
$LayoutEngine = $Graph.LayoutEngine
}
default {
throw "Unknown Parameter Set Name"
}
}
$Exe = Join-Path $GraphVizInstallPath ("bin\{0}.exe" -f $LayoutEngine)
if( !(Test-Path $Exe)) {
throw "Layout engine $LayoutEngine not found at $Exe"
}
$Dot | &$EXE -Tpng -o $Path
if($Show) {
Invoke-Item $Path
}
}
}
$ObjectsSource = @"
using System.Collections.Generic;
using System.Text;
using System;
namespace Whatsupduck.Powershell.GraphViz {
public enum RankDir {
LR,
RT,
TB,
BT
}
public abstract class Graph {
protected LinkedList<Node> nodeList;
protected LinkedList<Edge> edgeList;
protected LinkedList<Graph> graphList;
protected Dictionary<string, string> properties;
public String Name { get; set; }
public String Label {
get {
return properties["label"];
}
set {
properties["label"] = value;
}
}
public String Color {
get {
return properties["color"];
}
set {
properties["color"] = value;
}
}
public bool Concentrate {
get {
if(properties.ContainsKey("concentrate")) {
return bool.Parse(properties["concentrate"]);
} else {
return false;
}
}
set {
properties["concentrate"] = value.ToString();
}
}
public RankDir RankDir {
get {
return (RankDir)Enum.Parse(typeof(RankDir), properties["rankdir"]);
}
set {
properties["rankdir"] = Enum.GetName(typeof(RankDir), value);
}
}
public String Style {
get { return properties["style"]; }
set { properties["style"] = value; }
}
public abstract String LayoutEngine { get; }
public bool IsSubGraph { get; set; }
public bool IsCompound { get; set; }
public ICollection<Node> Nodes {
get {
return nodeList;
}
}
public ICollection<Edge> Edges {
get {
return edgeList;
}
}
public ICollection<Graph> Subgraphs {
get {
return graphList;
}
}
public Graph() {
this.Name = "";
this.nodeList = new LinkedList<Node>();
this.edgeList = new LinkedList<Edge>();
this.graphList = new LinkedList<Graph>();
this.properties = new Dictionary<string,string>();
this.IsSubGraph = false;
this.IsCompound = false;
this.RankDir = RankDir.LR;
}
public void AddNode(Node newNode) {
nodeList.AddLast(newNode);
}
public void AddEdge(Edge newEdge) {
edgeList.AddLast(newEdge);
}
public void AddGraph(Graph newGraph) {
if(!newGraph.IsSubGraph) {
newGraph.IsSubGraph = true;
}
graphList.AddLast(newGraph);
this.IsCompound = true;
}
public abstract String ToDot();
public String ToDot(string GraphType) {
StringBuilder sb = new StringBuilder();
if(this.IsSubGraph) {
sb.Append("subgraph ");
} else {
sb.Append(GraphType + " ");
}
sb.Append("\"" + this.Name + "\"");
sb.AppendLine(" {");
foreach(string name in this.properties.Keys) {
string value = this.properties[name];
sb.AppendLine(name + "=\"" + value + "\"");
}
if(this.IsCompound) {
sb.AppendLine("compound=true;");
}
foreach(Graph g in graphList) {
sb.Append(g.ToDot());
}
foreach(Node n in nodeList) {
sb.Append(n.ToString());
sb.AppendLine(";");
}
foreach(Edge e in edgeList) {
sb.Append(e.ToString());
sb.AppendLine(";");
}
sb.AppendLine("}");
return sb.ToString();
}
}
public class DirectedGraph : Graph {
public override String ToDot() {
return base.ToDot("digraph");
}
public override String LayoutEngine { get { return "dot"; } }
}
public class UndirectedGraph : Graph {
public override String ToDot() {
return base.ToDot("graph");
}
public override String LayoutEngine { get { return "neato"; } }
}
// Full list http://www.graphviz.org/doc/info/shapes.html
// I left out these redundent shapes: none, rect
public enum Shapes { box, polygon, ellipse, oval, circle, point, egg, triangle, plaintext, diamond, trapezium, parallelogram, house, pentagon, hexagon, septagon, octagon, doublecircle, doubleoctagon, tripleoctagon, invtriangle, invtrapezium, invhouse, Mdiamond, Msquare, Mcircle, rectangle, square, note, tab, folder, box3d, component, promoter, cds, terminator, utr, primersite, restrictionsite, fivepoverhang, threepoverhang, noverhang, assembly, signature, insulator, ribosite, rnastab, proteasesite, proteinstab, rpromoter, rarrow, larrow, lpromoter };
public class Node {
public String Name { get; set; }
private String _label;
public String Label {
get {
if(String.IsNullOrEmpty(_label)) {
return Name;
} else {
return _label;
}
}
set {
_label = value;
}
}
public Double Width { get; set; }
public Double Height { get; set; }
public Shapes Shape { get; set; }
public int Sides { get; set; }
public Node() {
Name = "";
Label = "";
//These are the defaults values for DOT
Width = .75;
Height = .5;
Shape = Shapes.ellipse;
Sides = 4;
}
public override String ToString() {
return String.Format("\"{0}\" [ label=\"{1}\", shape={2}]", Name, Label, Shape);
}
}
public abstract class Edge {
public String SourceName { get; set; }
public String TargetName { get; set; }
public String Label { get; set; }
public Edge() {
SourceName = "";
TargetName = "";
Label = "";
}
public Edge(Node sourceNode, Node targetNode, String label) {
this.SourceName = sourceNode.Name;
this.TargetName = targetNode.Name;
this.Label = label;
}
public abstract override String ToString();
}
public class DirectedEdge : Edge {
public override String ToString() {
return String.Format("\"{0}\" -> \"{1}\" [ label=\"{2}\"]", SourceName, TargetName, Label);
}
}
public class UndirectedEdge : Edge {
public override String ToString() {
return String.Format("\"{0}\" -- \"{1}\" [ label=\"{2}\"]", SourceName, TargetName, Label);
}
}
}
"@
Add-Type -TypeDefinition $ObjectsSource
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment