- Timestamp:
- 11/20/18 14:53:51 (6 years ago)
- Location:
- branches/2943_MOBasicProblem_MOCMAES/HeuristicLab.Analysis
- Files:
-
- 1 edited
- 7 copied
Legend:
- Unmodified
- Added
- Removed
-
branches/2943_MOBasicProblem_MOCMAES/HeuristicLab.Analysis
- Property svn:mergeinfo changed
/branches/2916_IndexedDataTableSerialization/HeuristicLab.Analysis (added) merged: 15918 /trunk/HeuristicLab.Analysis (added) merged: 16177
- Property svn:mergeinfo changed
-
branches/2943_MOBasicProblem_MOCMAES/HeuristicLab.Analysis/3.3/MultiObjective/CrowdingAnalyzer.cs
r16303 r16310 20 20 #endregion 21 21 22 using System.Linq;23 22 using HeuristicLab.Common; 24 23 using HeuristicLab.Core; 25 24 using HeuristicLab.Data; 26 25 using HeuristicLab.Optimization; 27 using HeuristicLab.Parameters;28 26 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; 29 27 30 namespace HeuristicLab. Problems.TestFunctions.MultiObjective{28 namespace HeuristicLab.Analysis { 31 29 [StorableClass] 32 30 [Item("CrowdingAnalyzer", "The mean crowding distance for each point of the Front (see Multi-Objective Performance Metrics - Shodhganga for more information)")] 33 public class CrowdingAnalyzer : MOTFAnalyzer { 34 35 public IResultParameter<DoubleValue> CrowdingResultParameter { 36 get { return (IResultParameter<DoubleValue>)Parameters["Crowding"]; } 37 } 31 public class CrowdingAnalyzer : MultiObjectiveSuccessAnalyzer { 32 public override string ResultName => "Crowding"; 38 33 39 34 [StorableConstructor] … … 47 42 48 43 public CrowdingAnalyzer() { 49 Parameters.Add(new ResultParameter<DoubleValue>("Crowding", "The average corwding distance of all points (excluding infinities)")); 50 CrowdingResultParameter.DefaultValue = new DoubleValue(double.NaN); 44 Parameters.Add(new ResultParameter<DoubleValue>("Crowding", "The average corwding distance of all points (excluding infinities)", "Results", new DoubleValue(double.NaN))); 51 45 } 52 46 … … 54 48 var qualities = QualitiesParameter.ActualValue; 55 49 var crowdingDistance = CrowdingCalculator.CalculateCrowding(qualities); 56 CrowdingResultParameter.ActualValue.Value = crowdingDistance;50 ResultParameter.ActualValue.Value = crowdingDistance; 57 51 return base.Apply(); 58 52 } -
branches/2943_MOBasicProblem_MOCMAES/HeuristicLab.Analysis/3.3/MultiObjective/GenerationalDistanceAnalyzer.cs
r16303 r16310 20 20 #endregion 21 21 22 using System ;22 using System.Collections.Generic; 23 23 using System.Linq; 24 24 using HeuristicLab.Common; … … 29 29 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; 30 30 31 namespace HeuristicLab. Problems.TestFunctions.MultiObjective{31 namespace HeuristicLab.Analysis { 32 32 [StorableClass] 33 [Item("GenerationalDistanceAnalyzer", "The generational distance between the current and the best known front (see Multi-Objective Performance Metrics - Shodhganga for more information)")] 34 public class GenerationalDistanceAnalyzer : MOTFAnalyzer { 33 [Item("GenerationalDistanceAnalyzer", "The generational distance between the current and the optimal front (if known)(see Multi-Objective Performance Metrics - Shodhganga for more information). The calculation of generational distance requires a known optimal pareto front")] 34 public class GenerationalDistanceAnalyzer : MultiObjectiveSuccessAnalyzer { 35 public override string ResultName => "Generational Distance"; 35 36 36 private IFixedValueParameter<DoubleValue> DampeningParameter { 37 get { return (IFixedValueParameter<DoubleValue>)Parameters["Dampening"]; } 38 set { Parameters["Dampening"].ActualValue = value; } 37 public IFixedValueParameter<DoubleValue> DampeningParameter => (IFixedValueParameter<DoubleValue>)Parameters["Dampening"]; 38 39 public double Dampening { 40 get => DampeningParameter.Value.Value; 41 set => DampeningParameter.Value.Value = value; 39 42 } 40 43 41 public double Dampening { 42 get { return DampeningParameter.Value.Value; } 43 set { DampeningParameter.Value.Value = value; } 44 } 44 public ILookupParameter<DoubleMatrix> OptimalParetoFrontParameter => (ILookupParameter<DoubleMatrix>)Parameters["BestKnownFront"]; 45 45 46 public IResultParameter<DoubleValue> GenerationalDistanceResultParameter {47 get { return (IResultParameter<DoubleValue>)Parameters["Generational Distance"]; }48 }49 46 50 47 [StorableConstructor] … … 57 54 public GenerationalDistanceAnalyzer() { 58 55 Parameters.Add(new FixedValueParameter<DoubleValue>("Dampening", "", new DoubleValue(1))); 59 Parameters.Add(new ResultParameter<DoubleValue>("Generational Distance", "The genrational distance between the current front and the optimal front")); 60 GenerationalDistanceResultParameter.DefaultValue = new DoubleValue(double.NaN); 61 56 Parameters.Add(new LookupParameter<ItemArray<DoubleArray>>("OptimalParetoFront", "The analytically best known Pareto front")); 57 Parameters.Add(new ResultParameter<DoubleValue>(ResultName, "The generational distance between the current front and the optimal front", "Results", new DoubleValue(double.NaN))); 62 58 } 63 59 64 60 public override IOperation Apply() { 65 61 var qualities = QualitiesParameter.ActualValue; 66 var optimalfront = TestFunctionParameter.ActualValue.OptimalParetoFront(qualities[0].Length); 67 if (optimalfront == null) return base.Apply(); 68 GenerationalDistanceResultParameter.ActualValue.Value = GenerationalDistanceCalculator.CalculateGenerationalDistance(qualities, optimalfront, Dampening); 62 var optimalFront = OptimalParetoFrontParameter.ActualValue; 63 if (optimalFront == null) return base.Apply(); 64 var front = Enumerable.Range(0, optimalFront.Rows).Select(r => Enumerable.Range(0, optimalFront.Columns).Select(c => optimalFront[r, c]).ToList()).ToList(); 65 ResultParameter.ActualValue.Value = CalculateDistance(qualities,front); 69 66 return base.Apply(); 67 } 68 69 protected virtual double CalculateDistance(ItemArray<DoubleArray> qualities, IList<List<double>> optimalFront) { 70 return GenerationalDistanceCalculator.CalculateGenerationalDistance(qualities, optimalFront, Dampening); 70 71 } 71 72 } -
branches/2943_MOBasicProblem_MOCMAES/HeuristicLab.Analysis/3.3/MultiObjective/HypervolumeAnalyzer.cs
r16303 r16310 30 30 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; 31 31 32 namespace HeuristicLab. Problems.TestFunctions.MultiObjective{32 namespace HeuristicLab.Analysis { 33 33 [StorableClass] 34 34 [Item("HypervolumeAnalyzer", "Computes the enclosed Hypervolume between the current front and a given reference Point")] 35 public class HypervolumeAnalyzer : MOTFAnalyzer { 35 public class HypervolumeAnalyzer : MultiObjectiveSuccessAnalyzer { 36 public override string ResultName => "Hypervolume"; 36 37 37 public ILookupParameter<DoubleArray> ReferencePointParameter { 38 get { return (ILookupParameter<DoubleArray>)Parameters["ReferencePoint"]; } 39 } 40 public IResultParameter<DoubleValue> HypervolumeResultParameter { 41 get { return (IResultParameter<DoubleValue>)Parameters["Hypervolume"]; } 42 } 43 public IResultParameter<DoubleValue> BestKnownHypervolumeResultParameter { 44 get { return (IResultParameter<DoubleValue>)Parameters["Best known hypervolume"]; } 45 } 46 public IResultParameter<DoubleValue> HypervolumeDistanceResultParameter { 47 get { return (IResultParameter<DoubleValue>)Parameters["Absolute Distance to BestKnownHypervolume"]; } 48 } 38 public ILookupParameter<DoubleArray> ReferencePointParameter => (ILookupParameter<DoubleArray>)Parameters["ReferencePoint"]; 39 40 public IResultParameter<DoubleValue> BestKnownHypervolumeResultParameter => (IResultParameter<DoubleValue>)Parameters["Best known hypervolume"]; 41 42 public IResultParameter<DoubleValue> HypervolumeDistanceResultParameter => (IResultParameter<DoubleValue>)Parameters["Absolute Distance to BestKnownHypervolume"]; 49 43 50 44 51 45 [StorableConstructor] 52 protected HypervolumeAnalyzer(bool deserializing) 53 : base(deserializing) { 54 } 46 protected HypervolumeAnalyzer(bool deserializing) : base(deserializing) {} 55 47 56 protected HypervolumeAnalyzer(HypervolumeAnalyzer original, Cloner cloner) 57 : base(original, cloner) { 58 } 48 protected HypervolumeAnalyzer(HypervolumeAnalyzer original, Cloner cloner) : base(original, cloner) {} 49 59 50 public override IDeepCloneable Clone(Cloner cloner) { 60 51 return new HypervolumeAnalyzer(this, cloner); … … 63 54 public HypervolumeAnalyzer() { 64 55 Parameters.Add(new LookupParameter<DoubleArray>("ReferencePoint", "The reference point for hypervolume calculation")); 65 Parameters.Add(new ResultParameter<DoubleValue>("Hypervolume", "The hypervolume of the current generation" ));56 Parameters.Add(new ResultParameter<DoubleValue>("Hypervolume", "The hypervolume of the current generation", "Results", new DoubleValue(double.NaN))); 66 57 Parameters.Add(new ResultParameter<DoubleValue>("Best known hypervolume", "The optimal hypervolume")); 67 58 Parameters.Add(new ResultParameter<DoubleValue>("Absolute Distance to BestKnownHypervolume", "The difference between the best known and the current hypervolume")); 68 HypervolumeResultParameter.DefaultValue = new DoubleValue(0); 69 BestKnownHypervolumeResultParameter.DefaultValue = new DoubleValue(0); 70 HypervolumeDistanceResultParameter.DefaultValue = new DoubleValue(0); 71 72 59 BestKnownHypervolumeResultParameter.DefaultValue = new DoubleValue(double.NaN); 60 HypervolumeDistanceResultParameter.DefaultValue = new DoubleValue(double.NaN); 73 61 } 74 62 75 63 public override IOperation Apply() { 76 var qualities = QualitiesParameter.ActualValue ;77 var testFunction = TestFunctionParameter.ActualValue;78 var objectives = qualities[0].Length;79 var referencePoint = ReferencePointParameter.ActualValue;64 var qualities = QualitiesParameter.ActualValue.Select(x => x.CloneAsArray()).ToArray(); 65 var referencePoint = ReferencePointParameter.ActualValue.ToArray(); 66 var best = BestKnownHypervolumeResultParameter.ActualValue.Value; 67 var maximization = MaximizationParameter.ActualValue.ToArray(); 80 68 81 var best = BestKnownHypervolumeResultParameter.ActualValue.Value; 82 if (referencePoint.SequenceEqual(testFunction.ReferencePoint(objectives))) { 83 best = Math.Max(best, testFunction.OptimalHypervolume(objectives)); 84 } 85 86 var hv = HypervolumeCalculator.CalculateHypervolume(qualities.Select(x=>x.CloneAsArray()).ToArray(), referencePoint.ToArray(), testFunction.Maximization(objectives)); 87 88 if (hv > best) { 89 best = hv; 90 } 91 92 HypervolumeResultParameter.ActualValue.Value = hv; 69 var hv = HypervolumeCalculator.CalculateHypervolume(qualities, referencePoint, maximization); 70 if (hv > best || double.IsNaN(best)) best = hv; 71 ResultParameter.ActualValue.Value = hv; 93 72 BestKnownHypervolumeResultParameter.ActualValue.Value = best; 94 73 HypervolumeDistanceResultParameter.ActualValue.Value = best - hv; … … 96 75 return base.Apply(); 97 76 } 98 99 77 } 100 78 } -
branches/2943_MOBasicProblem_MOCMAES/HeuristicLab.Analysis/3.3/MultiObjective/InvertedGenerationalDistanceAnalyzer.cs
r16303 r16310 20 20 #endregion 21 21 22 using System. Linq;22 using System.Collections.Generic; 23 23 using HeuristicLab.Common; 24 24 using HeuristicLab.Core; … … 28 28 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; 29 29 30 namespace HeuristicLab. Problems.TestFunctions.MultiObjective{30 namespace HeuristicLab.Analysis { 31 31 [StorableClass] 32 32 [Item("InvertedGenerationalDistanceAnalyzer", "The inverted generational distance between the current and the best known front (see Multi-Objective Performance Metrics - Shodhganga for more information)")] 33 public class InvertedGenerationalDistanceAnalyzer : MOTFAnalyzer { 34 public override bool EnabledByDefault { get { return false; } } 33 public class InvertedGenerationalDistanceAnalyzer : GenerationalDistanceAnalyzer { 34 public override bool EnabledByDefault => false; 35 public override string ResultName => "Inverted Generational Distance"; 35 36 36 private IFixedValueParameter<DoubleValue> DampeningParameter { 37 get { return (IFixedValueParameter<DoubleValue>)Parameters["Dampening"]; } 38 } 39 40 public double Dampening { 41 get { return DampeningParameter.Value.Value; } 42 set { DampeningParameter.Value.Value = value; } 43 } 44 45 public IResultParameter<DoubleValue> InvertedGenerationalDistanceResultParameter { 46 get { return (IResultParameter<DoubleValue>)Parameters["Inverted Generational Distance"]; } 47 } 37 public IResultParameter<DoubleValue> InvertedGenerationalDistanceResultParameter => (IResultParameter<DoubleValue>)Parameters["Inverted Generational Distance"]; 48 38 49 39 [StorableConstructor] … … 54 44 } 55 45 56 public InvertedGenerationalDistanceAnalyzer() { 57 Parameters.Add(new FixedValueParameter<DoubleValue>("Dampening", "", new DoubleValue(1))); 58 Parameters.Add(new ResultParameter<DoubleValue>("Inverted Generational Distance", "The genrational distance between the current front and the optimal front"));59 InvertedGenerationalDistanceResultParameter.DefaultValue = new DoubleValue(double.NaN);46 public InvertedGenerationalDistanceAnalyzer() { } 47 48 protected override double CalculateDistance(ItemArray<DoubleArray> qualities, IList<List<double>> optimalFront) { 49 return GenerationalDistanceCalculator.CalculateGenerationalDistance(optimalFront, qualities, Dampening); 60 50 } 61 51 62 public override IOperation Apply() {63 var qualities = QualitiesParameter.ActualValue;64 var optimalfront = TestFunctionParameter.ActualValue.OptimalParetoFront(qualities[0].Length);65 if (optimalfront == null) return base.Apply();66 InvertedGenerationalDistanceResultParameter.ActualValue.Value = GenerationalDistanceCalculator.CalculateInverseGenerationalDistance(qualities, optimalfront, Dampening);67 return base.Apply();68 }69 52 } 70 53 } -
branches/2943_MOBasicProblem_MOCMAES/HeuristicLab.Analysis/3.3/MultiObjective/MultiObjectiveSuccessAnalyzer.cs
r16303 r16310 29 29 30 30 31 namespace HeuristicLab. Problems.TestFunctions.MultiObjective{31 namespace HeuristicLab.Analysis { 32 32 33 33 [StorableClass] 34 public abstract class MOTFAnalyzer : SingleSuccessorOperator, IMultiObjectiveTestFunctionAnalyzer { 35 public virtual bool EnabledByDefault { get { return true; } } 34 public abstract class MultiObjectiveSuccessAnalyzer : SingleSuccessorOperator, IAnalyzer, IMultiObjectiveOperator { 35 public virtual bool EnabledByDefault => true; 36 public abstract string ResultName { get; } 36 37 37 public IScopeTreeLookupParameter<DoubleArray> QualitiesParameter { 38 get { return (IScopeTreeLookupParameter<DoubleArray>)Parameters["Qualities"]; } 39 } 38 public IScopeTreeLookupParameter<DoubleArray> QualitiesParameter => (IScopeTreeLookupParameter<DoubleArray>)Parameters["Qualities"]; 40 39 41 public ILookupParameter<ResultCollection> ResultsParameter { 42 get { return (ILookupParameter<ResultCollection>)Parameters["Results"]; } 43 } 40 public ILookupParameter<BoolArray> MaximizationParameter => (ILookupParameter<BoolArray>)Parameters["Maximization"]; 44 41 45 public ILookupParameter<IMultiObjectiveTestFunction> TestFunctionParameter { 46 get { return (ILookupParameter<IMultiObjectiveTestFunction>)Parameters["TestFunction"]; } 47 } 42 public ResultParameter<DoubleValue> ResultParameter => (ResultParameter<DoubleValue>)Parameters[ResultName]; 48 43 49 public ILookupParameter<DoubleMatrix> BestKnownFrontParameter { 50 get { return (ILookupParameter<DoubleMatrix>)Parameters["BestKnownFront"]; } 51 } 52 53 protected MOTFAnalyzer(MOTFAnalyzer original, Cloner cloner) : base(original, cloner) { } 54 44 protected MultiObjectiveSuccessAnalyzer(MultiObjectiveSuccessAnalyzer original, Cloner cloner) : base(original, cloner) { } 55 45 [StorableConstructor] 56 protected M OTFAnalyzer(bool deserializing) : base(deserializing) { }57 protected M OTFAnalyzer() {46 protected MultiObjectiveSuccessAnalyzer(bool deserializing) : base(deserializing) { } 47 protected MultiObjectiveSuccessAnalyzer() { 58 48 Parameters.Add(new ScopeTreeLookupParameter<DoubleArray>("Qualities", "The qualities of the parameter vector.")); 59 Parameters.Add(new LookupParameter<ResultCollection>("Results", "The results collection to write to."));60 Parameters.Add(new LookupParameter<IMultiObjectiveTestFunction>("TestFunction", "The Testfunction that is analyzed"));61 49 Parameters.Add(new LookupParameter<DoubleMatrix>("BestKnownFront", "The currently best known Pareto front")); 50 Parameters.Add(new LookupParameter<BoolArray>("Maximization", "")); 62 51 } 63 52 } -
branches/2943_MOBasicProblem_MOCMAES/HeuristicLab.Analysis/3.3/MultiObjective/SpacingAnalyzer.cs
r16303 r16310 27 27 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; 28 28 29 namespace HeuristicLab. Problems.TestFunctions.MultiObjective{29 namespace HeuristicLab.Analysis { 30 30 [StorableClass] 31 31 [Item("SpacingAnalyzer", "The spacing of the current front (see Multi-Objective Performance Metrics - Shodhganga for more information)")] 32 public class SpacingAnalyzer : MOTFAnalyzer { 32 public class SpacingAnalyzer : MultiObjectiveSuccessAnalyzer { 33 public override string ResultName => "Spacing"; 33 34 34 public IResultParameter<DoubleValue> SpacingResultParameter {35 get { return (IResultParameter<DoubleValue>)Parameters["Spacing"]; }36 }37 35 [StorableConstructor] 38 36 protected SpacingAnalyzer(bool deserializing) : base(deserializing) { } … … 45 43 46 44 public SpacingAnalyzer() { 47 Parameters.Add(new ResultParameter<DoubleValue>("Spacing", "The spacing of the current front")); 48 SpacingResultParameter.DefaultValue = new DoubleValue(double.NaN); 45 Parameters.Add(new ResultParameter<DoubleValue>("Spacing", "The spacing of the current front", "Results", new DoubleValue(double.NaN))); 49 46 } 50 47 51 48 public override IOperation Apply() { 52 49 var qualities = QualitiesParameter.ActualValue; 53 SpacingResultParameter.ActualValue.Value = SpacingCalculator.CalculateSpacing(qualities);50 ResultParameter.ActualValue.Value = SpacingCalculator.CalculateSpacing(qualities); 54 51 return base.Apply(); 55 52 } -
branches/2943_MOBasicProblem_MOCMAES/HeuristicLab.Analysis/3.3/MultiObjective/TimelineAnalyzer.cs
r16303 r16310 20 20 #endregion 21 21 22 using System.Collections.Generic; 22 23 using System.Linq; 23 24 using HeuristicLab.Common; 24 25 using HeuristicLab.Core; 25 26 using HeuristicLab.Data; 27 using HeuristicLab.Operators; 26 28 using HeuristicLab.Optimization; 29 using HeuristicLab.Parameters; 27 30 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; 28 31 29 namespace HeuristicLab. Problems.TestFunctions.MultiObjective{32 namespace HeuristicLab.Analysis { 30 33 [StorableClass] 31 [Item("SpacingAnalyzer", "The spacing of the current front (see Multi-Objective Performance Metrics - Shodhganga for more information)")] 32 public class SpacingAnalyzer : MOTFAnalyzer { 34 [Item("TimelineAnalyzer", "Collects the specified double values from the results and displays them as a timeline")] 35 public class TimelineAnalyzer : SingleSuccessorOperator, IAnalyzer, IMultiObjectiveOperator { 36 public bool EnabledByDefault => true; 37 public string ResultName => "Timeline"; 33 38 34 public IResultParameter<DoubleValue> SpacingResultParameter { 35 get { return (IResultParameter<DoubleValue>)Parameters["Spacing"]; } 36 } 39 public IFixedValueParameter<CheckedItemList<StringValue>> CollectedSuccessMeasuresParameter => 40 (IFixedValueParameter<CheckedItemList<StringValue>>)Parameters["CollectedSuccessMeasures"]; 41 42 public ILookupParameter<ResultCollection> ResultsParameter => (ILookupParameter<ResultCollection>)Parameters["Results"]; 43 44 public ResultParameter<DataTable> ResultParameter => (ResultParameter<DataTable>)Parameters[ResultName]; 45 46 public CheckedItemList<StringValue> CollectedSuccessMeasures => CollectedSuccessMeasuresParameter.Value; 47 37 48 [StorableConstructor] 38 protected SpacingAnalyzer(bool deserializing) : base(deserializing) { }49 protected TimelineAnalyzer(bool deserializing) : base(deserializing) { } 39 50 40 51 41 protected SpacingAnalyzer(SpacingAnalyzer original, Cloner cloner) : base(original, cloner) { }52 protected TimelineAnalyzer(TimelineAnalyzer original, Cloner cloner) : base(original, cloner) { } 42 53 public override IDeepCloneable Clone(Cloner cloner) { 43 return new SpacingAnalyzer(this, cloner);54 return new TimelineAnalyzer(this, cloner); 44 55 } 45 56 46 public SpacingAnalyzer() { 47 Parameters.Add(new ResultParameter<DoubleValue>("Spacing", "The spacing of the current front")); 48 SpacingResultParameter.DefaultValue = new DoubleValue(double.NaN); 57 public TimelineAnalyzer() { 58 var names = new List<string> { 59 new CrowdingAnalyzer().ResultName, 60 new GenerationalDistanceAnalyzer().ResultName, 61 new InvertedGenerationalDistanceAnalyzer().ResultName, 62 new HypervolumeAnalyzer().ResultName, 63 new SpacingAnalyzer().ResultName 64 }; 65 var analyzers = new CheckedItemList<StringValue> (names.Select(n=> new StringValue(n))); 66 Parameters.Add(new FixedValueParameter<CheckedItemList<StringValue>>("CollectedSuccessMeasures",analyzers)); 67 Parameters.Add(new LookupParameter<ResultCollection>("Results")); 68 Parameters.Add(new ResultParameter<DataTable>("Timeline", "The development of the success measures over the generations","Results", new DataTable("Timeline",""))); 49 69 } 50 70 51 71 public override IOperation Apply() { 52 var qualities = QualitiesParameter.ActualValue; 53 SpacingResultParameter.ActualValue.Value = SpacingCalculator.CalculateSpacing(qualities); 72 if (ResultParameter.ActualValue == null) ResultParameter.ActualValue = new DataTable(ResultName,""); 73 var plot = ResultParameter.ActualValue; 74 var resultCollection = ResultsParameter.ActualValue; 75 foreach (var resultName in CollectedSuccessMeasures.CheckedItems.Select(i=>i.Value.Value)) { 76 if(!resultCollection.ContainsKey(resultName)) continue; 77 if(!(resultCollection[resultName].Value is DoubleValue res)) continue; 78 if(!plot.Rows.ContainsKey(resultName)) plot.Rows.Add(new DataRow(resultName)); 79 plot.Rows[resultName].Values.Add(res.Value); 80 } 54 81 return base.Apply(); 55 82 }
Note: See TracChangeset
for help on using the changeset viewer.