public override IOperation Apply() { ItemArray <StringValue> exceptions = ExceptionTreeParameter.ActualValue; double count = exceptions.Count(); ResultCollection results = ResultsParameter.ActualValue; DataTable exceptionFrequencies = ExceptionFrequenciesParameter.ActualValue; if (exceptionFrequencies == null) { exceptionFrequencies = new DataTable("Exception frequencies", "Relative frequency of exception aggregated over the whole population."); exceptionFrequencies.VisualProperties.YAxisTitle = "Relative Exception Frequency"; ExceptionFrequenciesParameter.ActualValue = exceptionFrequencies; results.Add(new Result("Exception frequencies", exceptionFrequencies)); } // all rows must have the same number of values so we can just take the first int numberOfValues = exceptionFrequencies.Rows.Select(r => r.Values.Count).DefaultIfEmpty().First(); foreach (var pair in exceptions.GroupBy(x => x.Value).ToDictionary(g => g.Key, g => (double)g.Count() / count)) { string key = String.IsNullOrEmpty(pair.Key) ? "No Exception" : pair.Key; if (!exceptionFrequencies.Rows.ContainsKey(key)) { // initialize a new row for the symbol and pad with zeros DataRow row = new DataRow(key, "", Enumerable.Repeat(0.0, numberOfValues)); row.VisualProperties.StartIndexZero = true; exceptionFrequencies.Rows.Add(row); } exceptionFrequencies.Rows[key].Values.Add(Math.Round(pair.Value, 3)); } // add a zero for each data row that was not modified in the previous loop foreach (var row in exceptionFrequencies.Rows.Where(r => r.Values.Count != numberOfValues + 1)) { row.Values.Add(0.0); } return(base.Apply()); }