Changeset 8556 for branches/HeuristicLab.EvolutionaryTracking/HeuristicLab.EvolutionaryTracking.Views/3.4/GenealogyGraphChart.cs
- Timestamp:
- 09/03/12 15:09:52 (12 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/HeuristicLab.EvolutionaryTracking/HeuristicLab.EvolutionaryTracking.Views/3.4/GenealogyGraphChart.cs
r8249 r8556 32 32 namespace HeuristicLab.EvolutionaryTracking.Views { 33 33 public partial class GenealogyGraphChart : ChartControl { 34 private Dictionary< GenealogyGraphNode, List<VisualGenealogyGraphNode>> _visualNodeMap;35 private Dictionary<Tuple<VisualGenealogyGraphNode, VisualGenealogyGraphNode>, VisualGenealogyGraphArc> _visualArcMap;34 private Dictionary<IGenealogyGraphNode, VisualGenealogyGraphNode> visualNodeMap; 35 private Dictionary<Tuple<VisualGenealogyGraphNode, VisualGenealogyGraphNode>, VisualGenealogyGraphArc> visualArcMap; 36 36 private const int Diameter = 20; // node diameter 37 37 private int x, y; // coordinates for positioning each node 38 38 private const int Cx = 30, Cy = 30; // position increments 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 node42 43 private SymbolicExpressionTreeGenealogyGraph _graph;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 44 public SymbolicExpressionTreeGenealogyGraph Graph { 45 get { return _graph; }45 get { return graph; } 46 46 internal set { 47 _graph = value;48 _visualNodeMap = new Dictionary<GenealogyGraphNode, List<VisualGenealogyGraphNode>>();49 _visualArcMap = new Dictionary<Tuple<VisualGenealogyGraphNode, VisualGenealogyGraphNode>, VisualGenealogyGraphArc>();47 graph = value; 48 visualNodeMap = new Dictionary<IGenealogyGraphNode, VisualGenealogyGraphNode>(); 49 visualArcMap = new Dictionary<Tuple<VisualGenealogyGraphNode, VisualGenealogyGraphNode>, VisualGenealogyGraphArc>(); 50 50 DrawGraph(); 51 51 } … … 65 65 66 66 public void DrawGraph() { 67 if ( _graph == null) return;67 if (graph == null) return; 68 68 Chart.UpdateEnabled = false; 69 69 70 var genealogyGraphNodes = Graph.Values.ToList(); 71 var layers = genealogyGraphNodes.GroupBy(n => Graph[n].Ranks[0]).OrderBy(g => g.Key).Select(g => new { Rank = g.Key, Nodes = g.ToList() }).ToList(); 72 List<GenealogyGraphNode> currentLayer = null; 73 List<GenealogyGraphNode> previousLayer = null; 74 75 for (int i = 0; i != layers.Count(); ++i) { 76 var layer = layers[i]; 77 double currentRank = layer.Rank; 78 if (i > 0 && currentRank % 1 == 0) { 79 previousLayer = currentLayer; 80 currentLayer = layer.Nodes; 81 int d = previousLayer.Count - currentLayer.Count; 82 if (d > 0) 83 currentLayer.AddRange(previousLayer.Take(d)); 84 } else { 85 currentLayer = layer.Nodes; 86 } 87 currentLayer.Sort((b, a) => { 88 if (Graph[a].Quality.Equals(Graph[b].Quality)) { 89 if (Graph[a].IsElite) return 1; 90 if (Graph[b].IsElite) return -1; 91 } 92 return Graph[a].Quality.CompareTo(Graph[b].Quality); 93 }); // sort descending by quality (using comparison defined in GenealogyGraphNode class) 94 70 var layers = Graph.Nodes.GroupBy(n => n.Ranks[0]).OrderBy(g => g.Key).Select(g => new { Rank = g.Key, Nodes = g.ToList() }).ToList(); 71 for (int i = 0; i != layers.Count; ++i) { 72 // sort descending by quality (using comparison defined in GenealogyGraphNode class) 73 layers[i].Nodes.Sort((b, a) => Graph.Compare(a, b)); 95 74 x = 0; // reset horizontal coordinate 96 75 // start laying out visual nodes 97 foreach (var node in currentLayer) {76 foreach (var node in layers[i].Nodes) { 98 77 var pen = new Pen(Color.LightGray); 99 78 var nl = Environment.NewLine; … … 101 80 Data = node, 102 81 ToolTipText = "Id: " + node.Label + nl + 103 "Ranks: " + string.Join(",", Graph[node].Ranks.Select(r => r.ToString())) + nl +104 "Quality: " + String.Format("{0:0.0000}", Graph[node].Quality) + nl +105 "IsElite: " + Graph[node].IsElite82 "Ranks: " + string.Join(",", node.Ranks) + nl + 83 "Quality: " + String.Format("{0:0.0000}", node.Quality) + nl + 84 "IsElite: " + node.IsElite 106 85 }; 107 86 Chart.Group.Add(visualNode); 108 if (!_visualNodeMap.ContainsKey(node)) 109 _visualNodeMap[node] = new List<VisualGenealogyGraphNode>(); 110 _visualNodeMap[node].Add(visualNode); 87 if (!visualNodeMap.ContainsKey(node)) 88 visualNodeMap[node] = visualNode; 111 89 112 90 x += Cx; // increment horizontal coordinate … … 114 92 115 93 y -= Cy; // decrement vertical coordinate (because the origin is upside down) 94 95 // connect elites from successive layers with visual arcs 96 if (i > 0) { 97 for (int m = 0; m != layers[i].Nodes.Count; ++m) 98 for (int n = 0; n != layers[i - 1].Nodes.Count; ++n) { 99 if (layers[i].Nodes[m].SymbolicExpressionTree == layers[i - 1].Nodes[n].SymbolicExpressionTree) { 100 var v1 = visualNodeMap[layers[i].Nodes[m]]; 101 var v2 = visualNodeMap[layers[i - 1].Nodes[n]]; 102 var pen = new Pen(Color.LightGray); 103 visualArcMap[Tuple.Create(v2, v1)] = AddArc(Chart, v2, v1, pen); 104 } 105 } 106 } 116 107 } 117 108 // add arcs separately (to avoid some ordering problems) 118 foreach (var node in _visualNodeMap.Keys) {119 var visualNode = _visualNodeMap[node][0];109 foreach (var node in visualNodeMap.Keys) { 110 var visualNode = visualNodeMap[node]; 120 111 if (node.InEdges == null) continue; 121 112 122 113 foreach (var arc in node.InEdges) { 123 var visualParent = _visualNodeMap[arc.Target][0];114 var visualParent = visualNodeMap[arc.Target]; 124 115 var pen = new Pen(Color.Transparent); 125 _visualArcMap[Tuple.Create(visualParent, visualNode)] = AddArc(Chart, visualParent, visualNode, pen); 126 } 127 } 128 // connect visual nodes representing the same elite individual with a line 129 foreach (var list in _visualNodeMap.Values.Where(l => l.Count > 1)) { 130 for (int i = 1; i != list.Count; ++i) { 131 var pen = new Pen(Color.LightGray); 132 _visualArcMap[Tuple.Create(list[i - 1], list[i])] = AddArc(Chart, list[i - 1], list[i], pen); 116 visualArcMap[Tuple.Create(visualParent, visualNode)] = AddArc(Chart, visualParent, visualNode, pen); 133 117 } 134 118 } … … 156 140 var visualNodes = Chart.GetAllPrimitives(e.Location).Where(p => p is VisualGenealogyGraphNode).ToList(); 157 141 if (visualNodes.Count > 0) { 158 if ( _selectedGenealogyGraphNode == visualNodes[0]) return;159 _selectedGenealogyGraphNode = visualNodes[0] as VisualGenealogyGraphNode;160 if ( _selectedGenealogyGraphNode == null) return;142 if (selectedGenealogyGraphNode == visualNodes[0]) return; 143 selectedGenealogyGraphNode = visualNodes[0] as VisualGenealogyGraphNode; 144 if (selectedGenealogyGraphNode == null) return; 161 145 // new node has been selected, clean up 162 146 Chart.UpdateEnabled = false; … … 164 148 ClearAllNodes(); 165 149 // use a rectangle to highlight the currently selected genealogy graph node 166 var center = _selectedGenealogyGraphNode.Center;167 var size = _selectedGenealogyGraphNode.Size;150 var center = selectedGenealogyGraphNode.Center; 151 var size = selectedGenealogyGraphNode.Size; 168 152 double x1 = center.X - size.Width / 2; 169 153 double x2 = x1 + size.Width; 170 154 double y1 = center.Y - size.Height / 2; 171 155 double y2 = y1 + size.Height; 172 if ( _targetRectangle == null) {173 _targetRectangle = new Visualization.Rectangle(Chart, x1, y1, x2, y2, new Pen(Color.Black), null);174 Chart.Group.Add( _targetRectangle);156 if (targetRectangle == null) { 157 targetRectangle = new Visualization.Rectangle(Chart, x1, y1, x2, y2, new Pen(Color.Black), null); 158 Chart.Group.Add(targetRectangle); 175 159 } else { 176 _targetRectangle.SetPosition(x1, y1, x2, y2); 177 } 178 var gNode = _selectedGenealogyGraphNode.Data; // genealogy graph node (representing an individual in the population) 179 double rank = Graph[gNode].Ranks[0]; 160 targetRectangle.SetPosition(x1, y1, x2, y2); 161 } 162 var gNode = selectedGenealogyGraphNode.Data; // genealogy graph node (representing an individual in the population) 163 // double rank = Graph[gNode].Ranks[0]; 164 double rank = ((SymbolicExpressionGenealogyGraphNode)gNode).Ranks[0]; 180 165 // ancestors 181 var ancestors = gNode.Ancestors().Where(n => Graph[n].Ranks.Last() < rank).ToList();166 var ancestors = gNode.Ancestors().Where(n => ((SymbolicExpressionGenealogyGraphNode)n).Ranks.Last() < rank).ToList(); 182 167 ancestors.Add(gNode); 183 168 // descendants 184 var descendants = gNode.Descendants().Where(n => Graph[n].Ranks.Last() > rank).ToList();169 var descendants = gNode.Descendants().Where(n => ((SymbolicExpressionGenealogyGraphNode)n).Ranks.Last() > rank).ToList(); 185 170 descendants.Add(gNode); 186 171 // highlight ancestors 187 foreach (var node in ancestors.Select(n => _visualNodeMap[n][0])) {188 node.Brush = new SolidBrush( Graph[node.Data].GetColor());172 foreach (var node in ancestors.Select(n => visualNodeMap[n])) { 173 node.Brush = new SolidBrush(((SymbolicExpressionGenealogyGraphNode)node.Data).GetColor()); 189 174 if (node.IncomingArcs != null) 190 175 foreach (var arc in node.IncomingArcs) { 191 // check if, in case of elites, the target node is the first visual representation of the elite192 // (for purposes of display consistency)193 bool isFirst = arc.Source == _visualNodeMap[arc.Source.Data][0];194 if (arc.Source.Data == arc.Target.Data || !isFirst) continue;195 176 var start = new Point((int)arc.Start.X, (int)arc.Start.Y); 196 177 var end = new Point((int)arc.End.X, (int)arc.End.Y); 197 arc.Pen.Brush = new LinearGradientBrush(start, end, Graph[arc.Source.Data].GetColor(), Graph[arc.Target.Data].GetColor()); 178 var srcNode = arc.Source.Data as SymbolicExpressionGenealogyGraphNode; 179 var destNode = arc.Target.Data as SymbolicExpressionGenealogyGraphNode; 180 arc.Pen.Brush = new LinearGradientBrush(start, end, srcNode.GetColor(), destNode.GetColor()); 198 181 } 199 182 } 200 183 // highlight descendants 201 foreach (var node in descendants.Select(n => _visualNodeMap[n][0])) {202 node.Brush = new SolidBrush( Graph[node.Data].GetColor());184 foreach (var node in descendants.Select(n => visualNodeMap[n])) { 185 node.Brush = new SolidBrush((node.Data as SymbolicExpressionGenealogyGraphNode).GetColor()); 203 186 if (node.OutgoingArcs != null) 204 187 foreach (var arc in node.OutgoingArcs) { 205 // check if, in case of elites, the target node is the first visual representation of the elite206 // (for purposes of display consistency)207 bool isFirst = arc.Target == _visualNodeMap[arc.Target.Data][0];208 if (arc.Source.Data == arc.Target.Data || !isFirst) continue;209 188 var start = new Point((int)arc.Start.X, (int)arc.Start.Y); 210 189 var end = new Point((int)arc.End.X, (int)arc.End.Y); 211 arc.Pen.Brush = new LinearGradientBrush(start, end, Graph[arc.Source.Data].GetColor(), Graph[arc.Target.Data].GetColor()); 190 var srcNode = arc.Source.Data as SymbolicExpressionGenealogyGraphNode; 191 var destNode = arc.Target.Data as SymbolicExpressionGenealogyGraphNode; 192 arc.Pen.Brush = new LinearGradientBrush(start, end, srcNode.GetColor(), destNode.GetColor()); 212 193 } 213 194 } 214 195 } else { 215 _selectedGenealogyGraphNode = null;196 selectedGenealogyGraphNode = null; 216 197 } 217 198 // update 218 199 Chart.UpdateEnabled = true; 219 200 Chart.EnforceUpdate(); 220 if ( _selectedGenealogyGraphNode != null)201 if (selectedGenealogyGraphNode != null) 221 202 /* emit clicked event */ 222 OnGenealogyGraphNodeClicked( _selectedGenealogyGraphNode, e);203 OnGenealogyGraphNodeClicked(selectedGenealogyGraphNode, e); 223 204 } 224 205 } … … 226 207 public void ClearAllNodes() { 227 208 foreach (var primitive in Chart.Group.Primitives) { 228 primitive.Brush = null;229 209 if (primitive is VisualGenealogyGraphArc) { 230 210 var arc = primitive as VisualGenealogyGraphArc; 231 if (arc.Source.Data != arc.Target.Data && primitive.Pen.Brush != null) 211 var sourceData = (arc.Source.Data as SymbolicExpressionGenealogyGraphNode).SymbolicExpressionTree; 212 var targetData = (arc.Target.Data as SymbolicExpressionGenealogyGraphNode).SymbolicExpressionTree; 213 if (sourceData != targetData) { 232 214 primitive.Pen.Brush = new SolidBrush(Color.Transparent); 215 } else { 216 primitive.Pen.Brush = new SolidBrush(Color.LightGray); 217 } 218 } else { 219 primitive.Brush = null; 233 220 } 234 221 } … … 236 223 237 224 public void HighlightLineage(IEnumerable<GenealogyGraphNode> nodes) { 238 foreach (var node in nodes.Select Many(n => _visualNodeMap[n])) {239 node.Brush = new SolidBrush( Graph[node.Data].GetColor());240 if (node.IncomingArcs == null || node != _visualNodeMap[node.Data][0]) continue;225 foreach (var node in nodes.Select(n => visualNodeMap[n])) { 226 node.Brush = new SolidBrush((node.Data as SymbolicExpressionGenealogyGraphNode).GetColor()); 227 if (node.IncomingArcs == null || node != visualNodeMap[node.Data]) continue; 241 228 foreach (var arc in node.IncomingArcs) { 242 229 if (arc.Source.Data == node.Data) continue; 243 230 var start = new Point((int)arc.Start.X, (int)arc.Start.Y); 244 231 var end = new Point((int)arc.End.X, (int)arc.End.Y); 245 arc.Pen.Brush = new LinearGradientBrush(start, end, Graph[arc.Source.Data].GetColor(), Graph[arc.Target.Data].GetColor()); 246 } 247 } 248 } 249 232 var srcNode = arc.Source.Data as SymbolicExpressionGenealogyGraphNode; 233 var destNode = arc.Target.Data as SymbolicExpressionGenealogyGraphNode; 234 arc.Pen.Brush = new LinearGradientBrush(start, end, srcNode.GetColor(), destNode.GetColor()); 235 } 236 } 237 } 238 239 // TODO: optimize and reduce complexity of this method 250 240 public void HighlightNodes(IEnumerable<ISymbolicExpressionTree> trees, Color color) { 251 foreach (var visualNode in trees.Select(tree => _visualNodeMap[Graph.GetNode(tree)]).SelectMany(vList => vList)) 252 visualNode.Brush = new SolidBrush(color); 241 foreach (var tree in trees) 242 foreach (var graphNode in Graph.Nodes) { 243 if (graphNode.SymbolicExpressionTree == tree) { 244 var visualNode = visualNodeMap[graphNode]; 245 visualNode.Brush = new SolidBrush(color); 246 } 247 } 248 } 249 250 public void HighlightNode(SymbolicExpressionGenealogyGraphNode graphNode, Color color) { 251 visualNodeMap[graphNode].Brush = new SolidBrush(color); 253 252 } 254 253 … … 256 255 Chart.UpdateEnabled = false; 257 256 ClearAllNodes(); 258 var graphNodes = Graph.Values.ToList(); 259 double min = graphNodes.Min(x => x.InEdges == null ? 0 : x.InEdges.Count); 260 double max = graphNodes.Max(x => x.InEdges == null ? 0 : x.InEdges.Count); 261 foreach (var graphNode in graphNodes) { 262 var visualNode = _visualNodeMap[graphNode][0]; 257 double max = Graph.Nodes.Max(x => x.InEdges == null ? 0 : x.InEdges.Count); 258 foreach (var graphNode in Graph.Nodes) { 259 var visualNode = visualNodeMap[graphNode]; 263 260 double deg = graphNode.InEdges == null ? 0 : graphNode.InEdges.Count; 264 var color = Color.FromArgb((int)(1 - deg / max) * 255, (int)(deg / max * 255), 100); 261 int index = (int)(deg / max * ColorGradient.Colors.Count); 262 if (index == ColorGradient.Colors.Count) --index; 263 var color = ColorGradient.Colors[index]; 265 264 visualNode.Brush = new SolidBrush(color); 266 265 } … … 272 271 Chart.UpdateEnabled = false; 273 272 ClearAllNodes(); 274 var graphNodes = Graph.Values.ToList(); 275 double min = graphNodes.Min(x => x.OutEdges == null ? 0 : x.OutEdges.Count); 273 var graphNodes = Graph.Nodes; 276 274 double max = graphNodes.Max(x => x.OutEdges == null ? 0 : x.OutEdges.Count); 277 275 foreach (var graphNode in graphNodes) { 278 var visualNode = _visualNodeMap[graphNode][0];276 var visualNode = visualNodeMap[graphNode]; 279 277 double deg = graphNode.OutEdges == null ? 0 : graphNode.OutEdges.Count; 280 int index = (int)(deg / max * ColorGradient.Colors.Count) - 1; 281 if (index < 0) index = 0; 282 visualNode.Brush = new SolidBrush(ColorGradient.Colors[index]); 278 int index = (int)(deg / max * ColorGradient.Colors.Count); 279 if (index == ColorGradient.Colors.Count) --index; 280 var color = ColorGradient.Colors[index]; 281 visualNode.Brush = new SolidBrush(color); 283 282 } 284 283 Chart.UpdateEnabled = true; … … 288 287 289 288 internal static class Util { 290 public static Color GetColor(this NodeMetadata nm) {291 var colorIndex = (int)(n m.Quality * ColorGradient.Colors.Count);289 public static Color GetColor(this SymbolicExpressionGenealogyGraphNode node) { 290 var colorIndex = (int)(node.Quality * ColorGradient.Colors.Count); 292 291 if (colorIndex >= ColorGradient.Colors.Count) --colorIndex; 293 292 return ColorGradient.Colors[colorIndex];
Note: See TracChangeset
for help on using the changeset viewer.