Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/Tracking/SymbolicDataAnalysisGenealogyGraphView.cs @ 13061

Last change on this file since 13061 was 13061, checked in by bburlacu, 9 years ago

#1772: Adapted visualization code according to the changes in the HeuristicLab.Visualization branch.

File size: 15.3 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.Drawing;
25using System.Linq;
26using System.Windows.Forms;
27using HeuristicLab.Common;
28using HeuristicLab.Core;
29using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
30using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views;
31using HeuristicLab.EvolutionTracking;
32using HeuristicLab.EvolutionTracking.Views;
33using HeuristicLab.MainForm;
34
35namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Views {
36  [View("SymbolicDataAnalysisGenealogyGraphView")]
37  [Content(typeof(IGenealogyGraph<ISymbolicExpressionTree>), IsDefaultView = true)]
38  public partial class SymbolicDataAnalysisGenealogyGraphView : SymbolicDataAnalysisGenealogyGraphViewDesignable {
39    private readonly ISymbolicExpressionTreeNodeEqualityComparer comparer;
40
41    private ISymbolicExpressionTreeNode selectedSubtree;
42    private ISymbolicExpressionTreeNode SelectedSubtree {
43      get { return selectedSubtree; }
44      set {
45        if (value == null || selectedSubtree == value) return;
46        selectedSubtree = value;
47        ClonedSubtree = (ISymbolicExpressionTreeNode)selectedSubtree.Clone();
48      }
49    }
50    // the clone is necessary in order to deselect parts of a tree (by removing subtrees)
51    // and do "high level" matching of the remaining part
52    private ISymbolicExpressionTreeNode ClonedSubtree { get; set; }
53
54    // we use the symbolic expression tree chart to call the drawing routines
55    // and highlight relevant tree parts
56    public SymbolicExpressionTreeChart SymbolicExpressionTreeChart {
57      get {
58        var view = (GraphicalSymbolicExpressionTreeView)base.viewHost.ActiveView;
59        return view == null ? null : view.SymbolicExpressionTreeChart;
60      }
61    }
62
63    public SymbolicDataAnalysisGenealogyGraphView() {
64      InitializeComponent();
65      comparer = new SymbolicExpressionTreeNodeEqualityComparer();
66      viewHost.ViewType = typeof(GraphicalSymbolicExpressionTreeView);
67    }
68    #region event handlers
69    protected override void OnContentChanged() {
70      base.OnContentChanged();
71      if (Content != null && Content != genealogyGraphChart.GenealogyGraph) {
72        genealogyGraphChart.GenealogyGraph = Content;
73      }
74    }
75
76    public override void graphChart_GenealogyGraphNodeClicked(object sender, MouseEventArgs args) {
77      base.graphChart_GenealogyGraphNodeClicked(sender, args);
78      var visualNode = (VisualGenealogyGraphNode)sender;
79      var graphNode = (IGenealogyGraphNode<ISymbolicExpressionTree>)visualNode.Data;
80
81      nodeQualityLabel.Text = String.Format("{0:0.000}", graphNode.Quality);
82      nodeRankLabel.Text = String.Format("{0:0.0}", graphNode.Rank);
83      nodeDegreeLabel.Text = String.Format("{0} / {1}", graphNode.InDegree, graphNode.OutDegree);
84      nodeWeightLabel.Text = String.Format("{0:0.00}", graphNode.Weight);
85
86      int colorCount = ColorGradient.Colors.Count - 1;
87      const int alpha = 100;
88      // calculate max only in the current generation
89      var nodes = graphNode.Data.IterateNodesPrefix().Skip(1).ToList();
90      var max = Content.GetByRank(graphNode.Rank).Max(x => ((IGenealogyGraphNode<ISymbolicExpressionTree>)x).Data.IterateNodesPrefix().Max(n => n.NodeWeight));
91      if (max.IsAlmost(0)) max = 1;
92      foreach (var n in nodes) {
93        var visualSymbolicExpressionTreeNode = SymbolicExpressionTreeChart.GetVisualSymbolicExpressionTreeNode(n);
94        visualSymbolicExpressionTreeNode.ToolTip += Environment.NewLine + String.Format("Weight: {0:0}", n.NodeWeight);
95        var i = (int)Math.Round(n.NodeWeight / max * colorCount);
96        var fillColor = Color.FromArgb(alpha, ColorGradient.Colors[i]);
97        treeChart_HighlightSubtree(n, null, fillColor);
98      }
99
100      if (!graphNode.InArcs.Any()) return;
101
102      if (openNew_CheckBox.Checked) {
103        // get the ancestors into a new view
104        var cloner = new Cloner();
105        // clone arcs and vertices and use them to create a new graph
106        // that will include just the individual and its ancestors
107        var graph = new GenealogyGraph<ISymbolicExpressionTree>();
108        var ancestors = new[] { graphNode }.Concat(graphNode.Ancestors).ToList();
109        graph.AddVertices(ancestors.Select(cloner.Clone));
110        graph.AddArcs(ancestors.SelectMany(x => x.InArcs).Select(cloner.Clone));
111        MainFormManager.MainForm.ShowContent(graph);
112      }
113
114      var data = graphNode.InArcs.Last().Data;
115      var fragment = data as IFragment<ISymbolicExpressionTreeNode>;
116      var td = data as TraceData;
117
118      if (fragment != null) {
119        // highlight the fragment with a blue line color
120        foreach (var n in graphNode.Data.NodeAt(fragment.Index1).IterateNodesPrefix()) {
121          treeChart_HighlightSubtree(n, Color.CornflowerBlue);
122        }
123      } else if (td != null) {
124        // highlight traced subtree and fragment
125        treeChart_HighlightSubtree(nodes[td.LastSubtreeIndex], Color.Orange);
126        treeChart_HighlightSubtree(nodes[td.LastFragmentIndex], Color.CornflowerBlue);
127      }
128    }
129
130    #region specific symbolic expression tree node click actions
131    private void OnTreeNodeLeftClicked(ISymbolicExpressionTreeNode node) {
132      SelectedSubtree = node;
133      bool trace = genealogyGraphChart.TraceFragments;
134
135      // check whether we are in 'trace' or 'match' mode
136      if (trace) {
137        // perform fragment tracing
138        var graphNode = (IGenealogyGraphNode<ISymbolicExpressionTree>)genealogyGraphChart.SelectedGraphNode;
139        var subtreeIndex = graphNode.Data.IterateNodesPrefix().ToList().IndexOf(node);
140        var traceGraph = TraceCalculator.TraceSubtree(graphNode, subtreeIndex, updateVertexWeights: false, updateSubtreeWeights: false, cacheTraceNodes: true);
141        genealogyGraphChart.SuspendRendering();
142        genealogyGraphChart.ClearPrimitives(); // clear everything
143        var rankMaximums = new Dictionary<double, double>();
144        // fill each vertex in the graph with a grayscale color according to average subtree weight
145        foreach (var r in Content.Ranks) {
146          var vertices = r.Value.Cast<IGenealogyGraphNode<ISymbolicExpressionTree>>().ToList();
147          var averages = vertices.Select(x => x.Data.IterateNodesPrefix().Average(n => n.NodeWeight)).ToList();
148          var max = averages.Max();
149          rankMaximums.Add(r.Key, max);
150          if (max.IsAlmost(0.0)) continue;
151          int colorCount = ColorGradient.GrayscaledColors.Count - 1;
152          for (int i = 0; i < vertices.Count; ++i) {
153            var color = ColorGradient.GrayscaledColors[(int)Math.Round(averages[i] / max * colorCount)];
154            var vNode = genealogyGraphChart.GetMappedNode(vertices[i]);
155            vNode.Brush = new SolidBrush(color);
156          }
157        }
158        // fill vertices that are part of the trace with a rgb color according to average subtree weight
159        if (traceGraph.Vertices.Any()) {
160          var ranks = traceGraph.Vertices.Select(x => Content.GetByContent(x.Data)).GroupBy(x => x.Rank);
161          int colorCount = ColorGradient.Colors.Count - 1;
162          foreach (var g in ranks) {
163            var vertices = g.ToList();
164            var averages = vertices.Select(x => x.Data.IterateNodesPrefix().Average(n => n.NodeWeight)).ToList();
165            double max = rankMaximums[g.Key];
166            if (max.IsAlmost(0.0)) continue;
167            for (int i = 0; i < vertices.Count; ++i) {
168              var vNode = genealogyGraphChart.GetMappedNode(vertices[i]);
169              // use a grayscale gradient
170              var color = ColorGradient.Colors[(int)Math.Round(averages[i] / max * colorCount)];
171              vNode.Brush = new SolidBrush(color);
172            }
173          }
174
175          if (openNew_CheckBox.Checked) {
176            MainFormManager.MainForm.ShowContent(traceGraph); // display the fragment graph on the screen
177          }
178        }
179        genealogyGraphChart.ResumeRendering();
180      } else {
181        // perform matching like it was done before
182        // currently there is no possibility to specify the subtree matching criteria
183        var trees = Content.Vertices.Select(x => x.Data);
184        comparer.MatchVariableWeights = matchingModeButton.Checked;
185        comparer.MatchConstantValues = matchingModeButton.Checked;
186        var matchingTrees = trees.Where(x => x.Root.ContainsSubtree(node, comparer));
187
188        var matchingVertices = matchingTrees.Select(x => Content.GetByContent(x));
189        graphChart_HighlightMatchingVertices(matchingVertices);
190      }
191    }
192
193    private void OnTreeNodeMiddleClicked(ISymbolicExpressionTreeNode node) {
194      var index = SelectedSubtree.IterateNodesPrefix().ToList().IndexOf(node);
195      if (index > 0) {
196        var s = ClonedSubtree.NodeAt(index);
197        s.Parent.RemoveSubtree(s.Parent.IndexOfSubtree(s));
198
199        var trees = Content.Vertices.Select(x => x.Data);
200        comparer.MatchVariableWeights = matchingModeButton.Checked;
201        comparer.MatchConstantValues = matchingModeButton.Checked;
202        var matchingTrees = trees.Where(x => x.Root.ContainsSubtree(ClonedSubtree, comparer));
203
204        var matchingVertices = matchingTrees.Select(x => Content.GetByContent(x));
205        treeChart_HighlightSubtree(node, Color.Black, Color.White);
206        graphChart_HighlightMatchingVertices(matchingVertices);
207      }
208    }
209    #endregion
210
211    public void treeChart_SymbolicExpressionTreeNodeClicked(object sender, MouseEventArgs args) {
212      var visualNode = (VisualTreeNode<ISymbolicExpressionTreeNode>)sender;
213      var subtree = visualNode.Content;
214      // highlight the selected subtree inside the displayed tree on the right hand side
215      treeChart_ClearColors();
216      treeChart_HighlightSubtree(subtree, Color.Black, Color.RoyalBlue);
217
218      switch (args.Button) {
219        case MouseButtons.Left:
220          {
221            OnTreeNodeLeftClicked(subtree);
222            break;
223          }
224        case MouseButtons.Middle:
225          {
226            OnTreeNodeMiddleClicked(subtree);
227            break;
228          }
229      }
230    }
231    #endregion
232
233    protected override void RegisterContentEvents() {
234      base.RegisterContentEvents();
235      if (SymbolicExpressionTreeChart != null)
236        SymbolicExpressionTreeChart.SymbolicExpressionTreeNodeClicked += treeChart_SymbolicExpressionTreeNodeClicked;
237    }
238
239    protected override void DeregisterContentEvents() {
240      if (SymbolicExpressionTreeChart != null)
241        SymbolicExpressionTreeChart.SymbolicExpressionTreeNodeClicked -= treeChart_SymbolicExpressionTreeNodeClicked;
242      base.DeregisterContentEvents();
243    }
244
245    private void graphChart_HighlightMatchingVertices(IEnumerable<IGenealogyGraphNode> vertices) {
246      genealogyGraphChart.SuspendRendering();
247      genealogyGraphChart.ClearPrimitives();
248      genealogyGraphChart.HighlightNodes(vertices);
249      genealogyGraphChart.ResumeRendering();
250    }
251
252    private void treeChart_ClearColors() {
253      foreach (var node in SymbolicExpressionTreeChart.Tree.IterateNodesPrefix()) {
254        var visualNode = SymbolicExpressionTreeChart.GetVisualSymbolicExpressionTreeNode(node);
255        if (visualNode != null) {
256          visualNode.LineColor = Color.Black;
257          visualNode.FillColor = Color.Transparent;
258        }
259      }
260      SymbolicExpressionTreeChart.RepaintNodes();
261    }
262
263    private void treeChart_HighlightSubtree(ISymbolicExpressionTreeNode subtree, Color? lineColor = null, Color? fillColor = null) {
264      if (lineColor == null && fillColor == null)
265        return;
266
267      foreach (var s in subtree.IterateNodesPrefix()) {
268        var visualNode = SymbolicExpressionTreeChart.GetVisualSymbolicExpressionTreeNode(s);
269        if (lineColor != null) {
270          visualNode.LineColor = (Color)lineColor;
271          foreach (var c in s.Subtrees) {
272            var visualArc = SymbolicExpressionTreeChart.GetVisualSymbolicExpressionTreeNodeConnection(s, c);
273            visualArc.LineColor = (Color)lineColor;
274          }
275        }
276        if (fillColor != null)
277          visualNode.FillColor = (Color)fillColor;
278      }
279      SymbolicExpressionTreeChart.RepaintNodes();
280    }
281
282    #region navigate the genealogy / trace graph
283    private void navigateLeftButton_Click(object sender, EventArgs e) {
284      var graphNode = (IGenealogyGraphNode<ISymbolicExpressionTree>)genealogyGraphChart.SelectedGraphNode;
285      var inArcs = (List<IArc>)((IVertex)graphNode).InArcs;
286      if (inArcs.Count > 0) {
287        genealogyGraphChart.SelectedGraphNode = (IGenealogyGraphNode<ISymbolicExpressionTree>)inArcs[0].Source;
288      }
289    }
290
291    private void navigateRightButton_Click(object sender, EventArgs e) {
292      var graphNode = (IGenealogyGraphNode<ISymbolicExpressionTree>)genealogyGraphChart.SelectedGraphNode;
293      var inArcs = (List<IArc>)((IVertex)graphNode).InArcs;
294      if (inArcs.Count > 0) {
295        if (inArcs.Count == 1) {
296          genealogyGraphChart.SelectedGraphNode = (IGenealogyGraphNode<ISymbolicExpressionTree>)inArcs[0].Source;
297          return;
298        }
299        IGenealogyGraphNode<ISymbolicExpressionTree> source = null;
300        var fragment = ((IArc<IDeepCloneable>)inArcs.Last()).Data as IFragment<ISymbolicExpressionTreeNode>;
301        var traceData = ((IArc<IDeepCloneable>)inArcs[0]).Data as TraceData;
302        if (fragment != null) {
303          source = (IGenealogyGraphNode<ISymbolicExpressionTree>)inArcs.Last().Source;
304        }
305        if (traceData != null) {
306          var f = graphNode.Data.NodeAt(traceData.LastFragmentIndex);
307          var selected = inArcs.Skip(1).First(x => {
308            var td = (TraceData)((IArc<IDeepCloneable>)x).Data;
309            var s = (IGenealogyGraphNode<ISymbolicExpressionTree>)x.Source;
310            return f.Difference(s.Data.NodeAt(td.SubtreeIndex)) == null;
311          });
312          source = (IGenealogyGraphNode<ISymbolicExpressionTree>)selected.Source;
313        }
314        if (source != null)
315          genealogyGraphChart.SelectedGraphNode = source;
316      }
317    }
318    #endregion
319  }
320
321  // bogus class needed in order to be able to "design" the view
322  public class SymbolicDataAnalysisGenealogyGraphViewDesignable : GenealogyGraphView<ISymbolicExpressionTree> { }
323
324  #region helper methods
325  internal static class Util {
326    internal static ISymbolicExpressionTreeNode NodeAt(this ISymbolicExpressionTree tree, int position) {
327      return NodeAt(tree.Root, position);
328    }
329    internal static ISymbolicExpressionTreeNode NodeAt(this ISymbolicExpressionTreeNode root, int position) {
330      return root.IterateNodesPrefix().ElementAt(position);
331    }
332  }
333  #endregion
334}
Note: See TracBrowser for help on using the repository browser.