override public void generate() { //remove any old child graphical elements Children.Clear(); //compute total volume of pairs double totalVolume = innerValues.Sum<double>(x=>x); totalVolume += outerValues.Sum<double>(x => x); //compute pair volumes List<double> pairVolumes = new List<double>(); for (int x = 0; x < innerValues.Count(); x++) { pairVolumes.Add(innerValues[x] + outerValues[x]); } //determine rotational angles per pair List<double> pairRotationalAngles = new List<double>(); pairVolumes.ForEach(x => pairRotationalAngles.Add((x / totalVolume)*360.0)); //in degrees! double h = 0.0; //hue double s = 0.0; //saturation for (int x = 0; x < innerValues.Count(); x++) { //Draw the outer ring Wedge w = new Wedge(); w.center = center; w.sweep = pairRotationalAngles[x]; w.innerRadius = (innerValues[x] / pairVolumes[x]) * 100.0; w.outerRadius = (outerValues[x] / pairVolumes[x]) * 100.0; w.rotationAngle = h; //vary the color by both hue and saturation (for the colorblind) Color c = ColorUtils.computeFromHSV(h, 1.0-s, 0.9); w.Fill = new SolidColorBrush(c); w.Stroke = System.Windows.Media.Brushes.Black; //use a slightly darker version of the color as the stroke on the wedge w.Stroke = new SolidColorBrush(scaled(c, .8)); w.StrokeThickness = 2; //temporary labelling! w.ToolTip = outerValueLabels[x]; this.Children.Add(w); //draw the inner ring w = new Wedge(); w.center = center; w.sweep = pairRotationalAngles[x]; w.innerRadius = 0.0; w.outerRadius = (innerValues[x] / pairVolumes[x]) * 100.0; w.rotationAngle = h; c = ColorUtils.computeFromHSV(h, 1.0-s, 0.75); w.Fill = new SolidColorBrush(c); w.Fill.Opacity = 1.0; w.Stroke = new SolidColorBrush(scaled(c, .8)); w.StrokeThickness = 2; //temporary labelling! w.ToolTip = innerValueLabels[x]; this.Children.Add(w); h += pairRotationalAngles[x]; s += pairVolumes[x] / totalVolume; } }
public override void generate() { //remove any old child graphical elements Children.Clear(); //figure out the number of pie slices we will have int sliceCount = slices.Count(); double angle = 0.0; double sliceIncrement = 360.0 / sliceCount; for (int s = 0; s < sliceCount; s++) { //determine the number of rings that we will have int ringCount = slices[s].rings.Count(); //determine the ring increment double ringIncrement = (maxRadius - minRadius) / ringCount; double innerRadius = minRadius; for (int r = 0; r < ringCount; r++) { //determine the number of wedges per ring int wedgeCount = slices[s].rings[r].values.Count(); //determine the sweep increment double wedgeIncrement = sliceIncrement / wedgeCount; double wedgeAngle = angle; double max = slices[s].rings[r].values.Max(); for (int w = 0; w < wedgeCount; w++) { //create a wedge... Wedge wedge = new Wedge(); wedge.center = center; wedge.innerRadius = innerRadius; wedge.outerRadius = innerRadius + ((slices[s].rings[r].values[w] / max) * ringIncrement); //this needs to be adjusted to compare amongst the multiple data values at this level - max = 100%, then scale down from there... wedge.sweep = wedgeIncrement; wedge.rotationAngle = wedgeAngle; wedge.Fill = new SolidColorBrush(ColorUtils.computeFromHSV(220.0, (double)w / (double)(wedgeCount), 0.85)); wedge.Stroke = System.Windows.Media.Brushes.Black; wedge.StrokeThickness = 0.5; Children.Add(wedge); wedgeAngle += wedgeIncrement; } innerRadius += ringIncrement; } angle += sliceIncrement; } //draw all the circles... //draw outer circle Ellipse e = new Ellipse(); e.Width = maxRadius; e.Height = maxRadius; e.Stroke = System.Windows.Media.Brushes.Black; e.StrokeThickness = 1.0; e.RenderTransform = new TranslateTransform(center.X, center.Y); //Children.Add(e); //draw inner circle e = new Ellipse(); e.Width = minRadius; e.Height = minRadius; e.Stroke = System.Windows.Media.Brushes.Black; e.StrokeThickness = 1.0; e.RenderTransform = new TranslateTransform(center.X, center.Y); //Children.Add(e); for (int x = 0; x < sliceCount; x++) { Line l = new Line(); l.X1 = minRadius * Math.Cos((x * (2 * Math.PI / sliceCount))); l.Y1 = minRadius * Math.Sin(x * (2 * Math.PI / sliceCount)); l.X2 = maxRadius * Math.Cos(x * (2 * Math.PI / sliceCount)); l.Y2 = maxRadius * Math.Sin(x * (2 * Math.PI / sliceCount)); l.Stroke = System.Windows.Media.Brushes.Purple; l.StrokeThickness = 1.0; l.RenderTransform = new TranslateTransform(center.X, center.Y); //Children.Add(l); } }
public override void generate() { //remove any old child graphical elements Children.Clear(); //draw a scale underneath the other images for (double x = 10.0; x < 100.0; x+=10.0) { Ellipse ellipse = new Ellipse(); ellipse.Width = x*2.0; ellipse.Height = x*2.0; ellipse.Stroke = System.Windows.Media.Brushes.LightBlue; ellipse.StrokeThickness = 0.5; ellipse.RenderTransform = new TranslateTransform(center.X - x, center.Y-x); this.Children.Add(ellipse); } int polyCount = data.Count(); //number of stars Star star = new Star(); star.center = center; star.numPoints = polyCount; star.radii = new List<double>(); double maxStarValue = 0.0; for (int x = 0; x < polyCount; x++) { if (data[x][starIndex] > maxStarValue) { maxStarValue = data[x][starIndex]; } } for (int x = 0; x < polyCount; x++) { star.radii.Add((data[x][starIndex]/maxStarValue)*100.0); } star.Fill = System.Windows.Media.Brushes.Khaki; star.Stroke = System.Windows.Media.Brushes.Brown; star.StrokeThickness = 0.5; //generate the points used to locate the pie charts, etc. star.generateGeometry(); this.Children.Add(star); //build the wedges at each star tip for (int x = 0; x < polyCount; x++) { //compute information for wedges double sum = data[x].Sum<double>(z => z); sum -= data[x][starIndex]; //remove the value used to calculate the star arms from the pie chart total double angle = 0.0; for (int y = 0; y < data[x].Count(); y++) { if (y != starIndex) //skip this index if it's the one used to calculate the star arms { //Draw the outer ring Wedge w = new Wedge(); w.center = star.tips[x]; w.sweep = data[x][y] / sum * 90.0; w.innerRadius = 0.0; w.outerRadius = 50.0; w.rotationAngle = angle; //running total of value to aid with the colorblind! Color c = ColorUtils.computeFromHSV(angle * 4.0, 1.0, 0.9); w.Fill = new SolidColorBrush(c); w.Stroke = System.Windows.Media.Brushes.Black; w.Stroke = new SolidColorBrush(scaled(c, .8)); w.StrokeThickness = 0.5; RotateTransform rotation = new RotateTransform(180 - 45 - (360.0 / polyCount) * x); rotation.CenterX = star.tips[x].X; rotation.CenterY = star.tips[x].Y; w.RenderTransform = rotation; this.Children.Add(w); angle += w.sweep; } } } }
/// <summary> /// Recursively generates the wedges for each node in the hierarchical value tree. /// </summary> /// <param name="node">The node from which to create a wedge.</param> /// <param name="innerRadius">The inner radius of the wedge.</param> /// <param name="radius">The radius length (poor naming!).</param> /// <param name="arc">The arc of the wedge.</param> /// <param name="rotationalAngle">The rotational angle of the wedge (rotational transform, essentially).</param> private void generate(HierarchicalValue node, double innerRadius, double radius, double arc, double rotationalAngle) { Wedge wedge = new Wedge(); wedge.center = center; wedge.innerRadius = innerRadius; wedge.outerRadius = innerRadius + radius; wedge.sweep = arc; wedge.rotationAngle = rotationalAngle; //use a default black stroke around each wedge wedge.Stroke = System.Windows.Media.Brushes.Black; wedge.StrokeThickness = 0.5; wedge.Fill = brushes[node.tag]; //lookup the unique color based on the tag for this node wedge.ToolTip = node.name; wedges.Add(wedge); //arc percentage for children... var h = rotationalAngle; if (rotationalAngle < 180.0) { //create wedges for all of the children of this node foreach (HierarchicalValue child in node.children) { //sweep is related to the value the child contributes to the parent value var angle = arc * (child.totalValues() / (node.totalValues() - node.value)); generate(child, wedge.outerRadius, radius, angle, h); h += angle; //advance around the parent's arc } } else { // Process in reverse order //create wedges for all of the children of this node for(int i = node.children.Count - 1;i >= 0;i--) { HierarchicalValue child = node.children[i]; //sweep is related to the value the child contributes to the parent value var angle = arc * (child.totalValues() / (node.totalValues() - node.value)); generate(child, wedge.outerRadius, radius, angle, h); h += angle; //advance around the parent's arc } } }