Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.EvolutionaryTracking/HeuristicLab.EvolutionaryTracking.Views/3.4/GenealogyGraphChart.cs @ 8037

Last change on this file since 8037 was 7817, checked in by bburlacu, 12 years ago

#1772: Fixed a small bug in the TracingSymbolicExpressionTreeCrossover. Fixed bug in fragment matching code.

File size: 11.3 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2010 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.Drawing.Drawing2D;
26using System.Linq;
27using System.Windows.Forms;
28using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
29using HeuristicLab.Visualization;
30
31namespace HeuristicLab.EvolutionaryTracking.Views {
32  public partial class GenealogyGraphChart : ChartControl {
33    private Dictionary<GenealogyGraphNode, List<VisualGenealogyGraphNode>> _visualNodeMap;
34    private Dictionary<Tuple<VisualGenealogyGraphNode, VisualGenealogyGraphNode>, VisualGenealogyGraphArc> _visualArcMap;
35    private const int Diameter = 20;
36    private int x, y;
37    private const int Cx = 30, Cy = 30;
38
39    private VisualGenealogyGraphNode _selectedGenealogyGraphNode;
40    public VisualGenealogyGraphNode SelectedGenealogyGraphNode { get { return _selectedGenealogyGraphNode; } }
41    private Visualization.Rectangle _targetRectangle; // provides a  rectangle mark of the currently selected genealogy graph node
42
43    private SymbolicExpressionTreeGenealogyGraph _graph;
44    public SymbolicExpressionTreeGenealogyGraph Graph {
45      get { return _graph; }
46      internal set {
47        _graph = value;
48        _visualNodeMap = new Dictionary<GenealogyGraphNode, List<VisualGenealogyGraphNode>>();
49        _visualArcMap = new Dictionary<Tuple<VisualGenealogyGraphNode, VisualGenealogyGraphNode>, VisualGenealogyGraphArc>();
50        DrawGraph();
51      }
52    }
53
54    public event MouseEventHandler GenealogyGraphNodeClicked;
55    private void OnGenealogyGraphNodeClicked(object sender, MouseEventArgs e) {
56      var clicked = GenealogyGraphNodeClicked;
57      if (clicked != null) clicked(sender, e);
58    }
59
60    public GenealogyGraphChart() {
61      Chart = new Chart(0, 0, PreferredSize.Width, PreferredSize.Height);
62      x = 0;
63      y = PreferredSize.Height + Cx + 2 * Diameter;
64    }
65
66    public void DrawGraph() {
67      if (_graph == null) return;
68      Chart.UpdateEnabled = false;
69      var layers = Graph.Values.GroupBy(node => node.Rank).OrderBy(g => g.Key);
70      // show elites in every graph level
71      List<GenealogyGraphNode> currLayer = null, prevLayer = null;
72      double currRank = 0.0;
73      int count = layers.Count();
74      for (int i = 0; i != count; ++i) {
75        // propagate elites from successive layers
76        if (currRank == (int)currRank) prevLayer = currLayer;
77        currRank = layers.ElementAt(i).Key;
78        currLayer = layers.ElementAt(i).ToList();
79        if (i > 0 && currRank == (int)currRank) {
80          // this code injects elites that propagate from the previous generation into the current graph layer, so that they can be represented as visual nodes
81          int prevCount = prevLayer.Count(node => node.IsElite);
82          int currCount = currLayer.Count(node => node.IsElite);
83          for (int j = currCount; j < prevCount; ++j) currLayer.Add(prevLayer.ElementAt(j));
84        }
85        currLayer.Sort(); // uses the CompareTo() method inside the GenealogyGraphNode class
86
87        foreach (var node in currLayer) {
88          var pen = new Pen(Color.LightGray);
89          var nl = Environment.NewLine;
90          var visualNode = new VisualGenealogyGraphNode(Chart, x, y, x + Diameter, y + Diameter, pen, null) {
91            Data = node, ToolTipText = "Id: " + node.Label + nl + "Rank: " + node.Rank + nl + "Quality: " + String.Format("{0:0.0000}", node.Quality) + nl + "IsElite: " + node.IsElite
92          };
93          Chart.Group.Add(visualNode);
94          if (!_visualNodeMap.ContainsKey(node)) _visualNodeMap[node] = new List<VisualGenealogyGraphNode>();
95          _visualNodeMap[node].Add(visualNode);
96          // connect visual nodes that actually represent the same individual in the genealogy graph (this applies for elites) with a dashed line
97          if (_visualNodeMap[node].Count > 1) {
98            for (int c = _visualNodeMap[node].Count; c >= 2; --c) {
99              var n1 = _visualNodeMap[node][c - 1];
100              var n2 = _visualNodeMap[node][c - 2];
101              var visualArc = AddArc(Chart, n1, n2, new Pen(Color.LightGray) { DashStyle = DashStyle.Dash });
102              _visualArcMap[Tuple.Create(n1, n2)] = visualArc;
103            }
104          }
105          x += Cx; // increment horizontal coordinate
106          if (node.InEdges == null) continue;
107          // add visual edges
108          foreach (var arc in node.InEdges) {
109            var parent = arc.Target;
110            // find the visual parent node that is closest to the current node in terms of vertical distance
111            var visualParent = _visualNodeMap[parent].Where(p => p.Center.Y > visualNode.Center.Y).OrderByDescending(p => p.Center.Y).Last();
112            DashStyle style;
113            if (visualParent.Data == visualNode.Data) {
114              style = DashStyle.Dash;
115            } else {
116              style = node.InEdges.Count == 2 ? DashStyle.Solid : DashStyle.Dash;
117            }
118            var arcPen = new Pen(Color.Transparent) { DashStyle = style };
119            _visualArcMap[Tuple.Create(visualParent, visualNode)] = AddArc(Chart, visualParent, visualNode, arcPen);
120          }
121        }
122        y -= Cy; // decrement vertical coordinate (because the origin is upside down)
123        x = 0; // reset horizontal coordinate
124      }
125
126      Chart.UpdateEnabled = true;
127      Chart.EnforceUpdate();
128    }
129
130    // add an arc between the source and the target nodes, using the specified pen color
131    // adds the arc to the arc lists of both nodes and to the primitive group of the chart
132    private static VisualGenealogyGraphArc AddArc(IChart chart, VisualGenealogyGraphNode source, VisualGenealogyGraphNode target, Pen pen, Brush brush = null) {
133      var arc = new VisualGenealogyGraphArc(chart, source, target, pen) { Brush = brush };
134      arc.UpdatePosition();
135      source.OutgoingArcs.Add(arc);
136      target.IncomingArcs.Add(arc);
137      chart.Group.Add(arc);
138      return arc;
139    }
140
141    protected override void pictureBox_MouseUp(object sender, MouseEventArgs e) {
142      if (Chart.Mode != ChartMode.Select)
143        base.pictureBox_MouseUp(sender, e);
144      else { // select mode
145        Chart.UpdateEnabled = false;
146        // clear colors
147        foreach (var primitive in Chart.Group.Primitives) {
148          if (primitive is VisualGenealogyGraphNode) {
149            var visualNode = primitive as VisualGenealogyGraphNode;
150            visualNode.Brush = null;
151          } else if (primitive is VisualGenealogyGraphArc) {
152            var visualArc = primitive as VisualGenealogyGraphArc;
153            if (visualArc.Source.Data != visualArc.Target.Data) visualArc.Pen.Brush = new SolidBrush(Color.Transparent);
154          }
155        }
156        // get selected node
157        var visualNodes = Chart.GetAllPrimitives(e.Location).Where(p => p is VisualGenealogyGraphNode).ToList();
158        if (visualNodes.Count > 0) {
159          _selectedGenealogyGraphNode = visualNodes[0] as VisualGenealogyGraphNode;
160          // color selected node and its genealogy
161          if (_selectedGenealogyGraphNode == null) return;
162          // use special highlighting for the currently selected genealogy graph node
163          var center = _selectedGenealogyGraphNode.Center;
164          var size = _selectedGenealogyGraphNode.Size;
165          double x1 = center.X - size.Width / 2, x2 = x1 + size.Width;
166          double y1 = center.Y - size.Height / 2, y2 = y1 + size.Height;
167          if (_targetRectangle != null) _targetRectangle.SetPosition(x1, y1, x2, y2);
168          else {
169            _targetRectangle = new Visualization.Rectangle(Chart, x1, y1, x2, y2, new Pen(Color.Black), null);
170            Chart.Group.Add(_targetRectangle);
171          }
172          var gNode = _selectedGenealogyGraphNode.Data; // genealogy graph node (representing an individual in the population)
173          double rank = gNode.Rank;
174          var ancestors = gNode.Ancestors().Where(a => a.Rank < rank).ToList();
175          ancestors.Add(gNode);
176          // highlight selected node and its ancestry
177          foreach (var node in ancestors.SelectMany(n => _visualNodeMap[n])) {
178            node.Brush = new SolidBrush(node.ToColor());
179            if (node.IncomingArcs != null && node == _visualNodeMap[node.Data].First()) {
180              foreach (var arc in node.IncomingArcs) {
181                if (arc.Source.Data == node.Data) continue;
182                var start = new Point((int)arc.Start.X, (int)arc.Start.Y);
183                var end = new Point((int)arc.End.X, (int)arc.End.Y);
184                arc.Pen.Brush = new LinearGradientBrush(start, end, arc.Source.ToColor(), arc.Target.ToColor());
185              }
186            }
187          }
188          // highlight the descendants
189          var descendants = gNode.Descendants().Where(a => a.Rank > rank).ToList();
190          descendants.Add(gNode);
191          foreach (var node in descendants.SelectMany(n => _visualNodeMap[n])) {
192            node.Brush = new SolidBrush(node.ToColor());
193            foreach (var arc in node.IncomingArcs.Where(a => descendants.Contains(a.Source.Data))) {
194              if (arc.Source.Data == node.Data) continue;
195              var start = new Point((int)arc.Start.X, (int)arc.Start.Y);
196              var end = new Point((int)arc.End.X, (int)arc.End.Y);
197              arc.Pen.Brush = new LinearGradientBrush(start, end, arc.Source.ToColor(), arc.Target.ToColor());
198            }
199          }
200        } else {
201          _selectedGenealogyGraphNode = null;
202        }
203        // update
204        Chart.UpdateEnabled = true;
205        Chart.EnforceUpdate();
206        if (_selectedGenealogyGraphNode != null)
207          /* emit clicked event */
208          GenealogyGraphNodeClicked(_selectedGenealogyGraphNode, e);
209      }
210    }
211
212    public void ClearAllNodes() {
213      Chart.UpdateEnabled = false;
214      foreach (var node in Chart.Group.Primitives.Where(p => p is VisualGenealogyGraphNode).Cast<VisualGenealogyGraphNode>()) {
215        node.Brush = null;
216        if (node.IncomingArcs != null)
217          foreach (var arc in node.IncomingArcs)
218            if (arc.Source.Data != node.Data) arc.Pen = new Pen(Color.Transparent);
219      }
220      Chart.UpdateEnabled = true;
221      Chart.EnforceUpdate();
222    }
223
224    public void HighlightNodes(IEnumerable<ISymbolicExpressionTree> trees, Color color) {
225      Chart.UpdateEnabled = false;
226      foreach (var visualNode in trees.Select(tree => _visualNodeMap[Graph.GetNode(tree)]).SelectMany(vList => vList))
227        visualNode.Brush = new SolidBrush(color);
228
229      Chart.UpdateEnabled = true;
230      Chart.EnforceUpdate();
231    }
232  }
233}
Note: See TracBrowser for help on using the repository browser.