Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
05/11/16 12:18:00 (8 years ago)
Author:
pfleck
Message:

#2597

  • Reduced memory consumption greatly by reusing existing datapoints from existing series instead of creating new series on update.
  • Rearranged methods and properties in GradientChart.
  • Added properties to set fixed axis limits instead of calculation.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis.Views/3.4/GradientChart.cs

    r13840 r13842  
    3838    private ModifiableDataset internalDataset; // holds the x values for each point drawn
    3939
    40     private CancellationTokenSource cancelCurrentRefresh;
    41 
     40    private CancellationTokenSource cancelCurrentRecalculateSource;
     41
     42    private readonly List<IRegressionSolution> solutions;
     43    private readonly Dictionary<IRegressionSolution, Series> seriesCache;
     44    private readonly Dictionary<IRegressionSolution, Series> ciSeriesCache;
     45
     46    #region Properties
    4247    public bool ShowLegend {
    4348      get { return chart.Legends[0].Enabled; }
     
    6065    public int XAxisTicks {
    6166      get { return xAxisTicks; }
    62       set { if (xAxisTicks != value) { xAxisTicks = value; UpdateChart(); } }
    63     }
     67      set { xAxisTicks = value; }
     68    }
     69    private double? fixedXAxisMin;
     70    public double? FixedXAxisMin {
     71      get { return fixedXAxisMin; }
     72      set {
     73        if ((value.HasValue && fixedXAxisMin.HasValue && !value.Value.IsAlmost(fixedXAxisMin.Value)) || (value.HasValue != fixedXAxisMin.HasValue)) {
     74          fixedXAxisMin = value;
     75          RecalculateInternalDataset();
     76        }
     77      }
     78    }
     79    private double? fixedXAxisMax;
     80    public double? FixedXAxisMax {
     81      get { return fixedXAxisMax; }
     82      set {
     83        if ((value.HasValue && fixedXAxisMax.HasValue && !value.Value.IsAlmost(fixedXAxisMax.Value)) || (value.HasValue != fixedXAxisMax.HasValue)) {
     84          fixedXAxisMax = value;
     85          RecalculateInternalDataset();
     86        }
     87      }
     88    }
     89
    6490    private int yAxisTicks = 5;
    65     public int YXAxisTicks {
     91    public int YAxisTicks {
    6692      get { return yAxisTicks; }
    67       set { if (yAxisTicks != value) { yAxisTicks = value; UpdateChart(); } }
     93      set { yAxisTicks = value; }
     94    }
     95    private double? fixedYAxisMin;
     96    public double? FixedYAxisMin {
     97      get { return fixedYAxisMin; }
     98      set {
     99        if ((value.HasValue && fixedYAxisMin.HasValue && !value.Value.IsAlmost(fixedYAxisMin.Value)) || (value.HasValue != fixedYAxisMin.HasValue)) {
     100          fixedYAxisMin = value;
     101        }
     102      }
     103    }
     104    private double? fixedYAxisMax;
     105    public double? FixedYAxisMax {
     106      get { return fixedYAxisMax; }
     107      set {
     108        if ((value.HasValue && fixedYAxisMax.HasValue && !value.Value.IsAlmost(fixedYAxisMax.Value)) || (value.HasValue != fixedYAxisMax.HasValue)) {
     109          fixedYAxisMax = value;
     110        }
     111      }
    68112    }
    69113
     
    71115    public double TrainingMin {
    72116      get { return trainingMin; }
    73       set { if (!value.IsAlmost(trainingMin)) { trainingMin = value; UpdateChart(); } }
     117      set { trainingMin = value; }
    74118    }
    75119    private double trainingMax = double.MaxValue;
    76120    public double TrainingMax {
    77121      get { return trainingMax; }
    78       set { if (!value.IsAlmost(trainingMax)) { trainingMax = value; UpdateChart(); } }
     122      set { trainingMax = value; }
    79123    }
    80124
     
    82126    public int DrawingSteps {
    83127      get { return drawingSteps; }
    84       set { if (value != drawingSteps) { drawingSteps = value; UpdateChart(); } }
     128      set {
     129        if (value != drawingSteps) {
     130          drawingSteps = value;
     131          RecalculateInternalDataset();
     132          ResizeAllSeriesData();
     133        }
     134      }
    85135    }
    86136
     
    95145        freeVariable = value;
    96146        RecalculateInternalDataset();
    97         UpdateChart();
    98       }
    99     }
    100 
    101     private readonly List<IRegressionSolution> solutions = new List<IRegressionSolution>();
    102     public IEnumerable<IRegressionSolution> Solutions {
    103       get { return solutions; }
     147      }
    104148    }
    105149
     
    107151      get { return (VerticalLineAnnotation)chart.Annotations.SingleOrDefault(x => x is VerticalLineAnnotation); }
    108152    }
     153    #endregion
    109154
    110155    public GradientChart() {
    111156      InitializeComponent();
     157
     158      solutions = new List<IRegressionSolution>();
     159      seriesCache = new Dictionary<IRegressionSolution, Series>();
     160      ciSeriesCache = new Dictionary<IRegressionSolution, Series>();
    112161
    113162      // Configure axis
     
    121170      chart.ChartAreas[0].CursorY.Interval = 0;
    122171
    123       Disposed +=GradientChart_Disposed;
    124     }
    125 
     172      Disposed += GradientChart_Disposed;
     173    }
    126174    private void GradientChart_Disposed(object sender, EventArgs e) {
    127       if (cancelCurrentRefresh != null) {
    128         if (cancelCurrentRefresh.IsCancellationRequested)
    129           cancelCurrentRefresh.Cancel();
    130         cancelCurrentRefresh.Dispose();
    131       }
    132     }
    133 
    134     public void Configure(IEnumerable<IRegressionSolution> solutions, ModifiableDataset sharedFixedVariables, string freeVariable, int drawingSteps) {
     175      if (cancelCurrentRecalculateSource != null) {
     176        if (cancelCurrentRecalculateSource.IsCancellationRequested)
     177          cancelCurrentRecalculateSource.Cancel();
     178      }
     179    }
     180
     181    public void Configure(IEnumerable<IRegressionSolution> solutions, ModifiableDataset sharedFixedVariables, string freeVariable, int drawingSteps, bool initializeAxisRanges = true) {
    135182      if (!SolutionsCompatible(solutions))
    136183        throw new ArgumentException("Solutions are not compatible with the problem data.");
     184      this.freeVariable = freeVariable;
     185      this.drawingSteps = drawingSteps;
     186
    137187      this.solutions.Clear();
    138188      this.solutions.AddRange(solutions);
    139       this.freeVariable = freeVariable;
    140       this.drawingSteps = drawingSteps;
    141189
    142190      // add an event such that whenever a value is changed in the shared dataset,
     
    147195      this.sharedFixedVariables.ItemChanged += sharedFixedVariables_ItemChanged;
    148196
    149       RecalculateTrainingLimits();
     197      RecalculateTrainingLimits(initializeAxisRanges);
    150198      RecalculateInternalDataset();
    151     }
    152 
    153     private void sharedFixedVariables_ItemChanged(object o, EventArgs<int, int> e) {
    154       if (o != sharedFixedVariables) return;
    155       var variables = sharedFixedVariables.DoubleVariables.ToList();
    156       var rowIndex = e.Value;
    157       var columnIndex = e.Value2;
    158 
    159       var variableName = variables[columnIndex];
    160       if (variableName == FreeVariable) return;
    161       var v = sharedFixedVariables.GetDoubleValue(variableName, rowIndex);
    162       var values = new List<double>(Enumerable.Repeat(v, DrawingSteps));
    163       internalDataset.ReplaceVariable(variableName, values);
     199
     200      chart.Series.Clear();
     201      seriesCache.Clear();
     202      ciSeriesCache.Clear();
     203      foreach (var solution in this.solutions) {
     204        var series = CreateSeries(solution);
     205        seriesCache.Add(solution, series.Item1);
     206        if (series.Item2 != null)
     207          ciSeriesCache.Add(solution, series.Item2);
     208      }
     209
     210      ResizeAllSeriesData();
     211      OrderAndColorSeries();
     212    }
     213
     214    public async Task RecalculateAsync() {
     215      if (IsDisposed
     216        || sharedFixedVariables == null || !solutions.Any() || string.IsNullOrEmpty(freeVariable)
     217        || trainingMin.IsAlmost(trainingMax) || trainingMin > trainingMax || drawingSteps == 0)
     218        return;
     219
     220      statusLabel.Visible = true;
     221      Update(); // immediately show label
     222
     223      // cancel previous recalculate call
     224      if (cancelCurrentRecalculateSource != null)
     225        cancelCurrentRecalculateSource.Cancel();
     226      cancelCurrentRecalculateSource = new CancellationTokenSource();
     227
     228      // Set cursor and x-axis
     229      var defaultValue = sharedFixedVariables.GetDoubleValue(freeVariable, 0);
     230      VerticalLineAnnotation.X = defaultValue;
     231      chart.ChartAreas[0].AxisX.Title = FreeVariable + " : " + defaultValue.ToString("N3", CultureInfo.CurrentCulture);
     232      SetupAxis(chart.ChartAreas[0].AxisX, trainingMin, trainingMax, XAxisTicks, fixedXAxisMin, fixedXAxisMax);
     233
     234      // Update series
     235      var cancellationToken = cancelCurrentRecalculateSource.Token;
     236      try {
     237        await UpdateSeriesData(cancellationToken);
     238        chart.Update();
     239
     240        // Set y-axis
     241        double ymin = 0, ymax = 0;
     242        foreach (var vs in chart.Series.SelectMany(series => series.Points.Select(s => s.YValues))) {
     243          for (int i = 0; i < vs.Length; i++) {
     244            var v = vs[i];
     245            if (ymin > v) ymin = v;
     246            if (ymax < v) ymax = v;
     247          }
     248        }
     249        SetupAxis(chart.ChartAreas[0].AxisY, ymin, ymax, YAxisTicks, FixedYAxisMin, FixedYAxisMax);
     250        chart.ChartAreas[0].RecalculateAxesScale();
     251
     252        UpdateOutOfTrainingRangeStripLines();
     253
     254        statusLabel.Visible = false;
     255        Update(); // immediately show
     256      }
     257      catch (OperationCanceledException) { }
     258      catch (AggregateException ae) {
     259        if (!ae.InnerExceptions.Any(e => e is OperationCanceledException))
     260          throw;
     261      }
     262    }
     263
     264    private static void SetupAxis(Axis axis, double minValue, double maxValue, int ticks, double? fixedAxisMin, double? fixedAxisMax) {
     265      double axisMin, axisMax, axisInterval;
     266      ChartUtil.CalculateAxisInterval(minValue, maxValue, ticks, out axisMin, out axisMax, out axisInterval);
     267      axis.Minimum = fixedAxisMin ?? axisMin;
     268      axis.Maximum = fixedAxisMax ?? axisMax;
     269      axis.Interval = (axisMax - axisMin) / ticks;
     270    }
     271
     272    private void RecalculateTrainingLimits(bool initializeAxisRanges) {
     273      trainingMin = solutions.Select(s => s.ProblemData.Dataset.GetDoubleValues(freeVariable, s.ProblemData.TrainingIndices).Min()).Max();
     274      trainingMax = solutions.Select(s => s.ProblemData.Dataset.GetDoubleValues(freeVariable, s.ProblemData.TrainingIndices).Max()).Min();
     275
     276      if (initializeAxisRanges) {
     277        double xmin, xmax, xinterval;
     278        ChartUtil.CalculateAxisInterval(trainingMin, trainingMax, XAxisTicks, out xmin, out xmax, out xinterval);
     279        FixedXAxisMin = xmin;
     280        FixedXAxisMax = xmax;
     281      }
    164282    }
    165283
     
    168286      double xmin, xmax, xinterval;
    169287      ChartUtil.CalculateAxisInterval(trainingMin, trainingMax, XAxisTicks, out xmin, out xmax, out xinterval);
     288
     289      if (FixedXAxisMin.HasValue) xmin = FixedXAxisMin.Value;
     290      if (FixedXAxisMax.HasValue) xmax = FixedXAxisMax.Value;
    170291      double step = (xmax - xmin) / drawingSteps;
    171292
     
    183304    }
    184305
    185     private void RecalculateTrainingLimits() {
    186       trainingMin = solutions.Select(s => s.ProblemData.Dataset.GetDoubleValues(freeVariable, s.ProblemData.TrainingIndices).Min()).Max();
    187       trainingMax = solutions.Select(s => s.ProblemData.Dataset.GetDoubleValues(freeVariable, s.ProblemData.TrainingIndices).Max()).Min();
    188     }
    189 
    190     public async void UpdateChart() {
    191       // throw exceptions?
    192       if (sharedFixedVariables == null || solutions == null || !solutions.Any())
    193         return;
    194       if (trainingMin.IsAlmost(trainingMax) || trainingMin > trainingMax || drawingSteps == 0)
    195         return;
    196       if (IsDisposed)
    197         return;
    198 
    199       statusLabel.Visible = true;
    200 
    201       if (cancelCurrentRefresh != null && !cancelCurrentRefresh.IsCancellationRequested)
    202         cancelCurrentRefresh.Cancel();
    203       cancelCurrentRefresh = new CancellationTokenSource();
    204 
    205       // Set cursor
    206       var defaultValue = sharedFixedVariables.GetDoubleValue(freeVariable, 0);
    207       VerticalLineAnnotation.X = defaultValue;
    208 
    209       // Calculate X-axis interval
    210       double axisMin, axisMax, axisInterval;
    211       ChartUtil.CalculateAxisInterval(trainingMin, trainingMax, XAxisTicks, out axisMin, out axisMax, out axisInterval);
    212       var axis = chart.ChartAreas[0].AxisX;
    213       axis.Minimum = axisMin;
    214       axis.Maximum = axisMax;
    215       axis.Interval = axisInterval;
    216 
    217       var cancellationToken = cancelCurrentRefresh.Token;
    218       // Create series <mean, conf. interval>
    219       var seriesDict = new Dictionary<Series, Series>();
    220       for (int i = 0; i < solutions.Count; i++) {
    221         var solution = solutions[i];
    222         try {
    223           var series = await CreateSeriesAsync(solution, cancellationToken);
    224           if (cancellationToken.IsCancellationRequested)
    225             return;
    226           series.Item1.Tag = i; // for sorting
    227           var meanSeries = series.Item1;
    228           var confidenceIntervalSeries = series.Item2;
    229           meanSeries.Name = solution.ProblemData.TargetVariable + " " + i;
    230           seriesDict.Add(meanSeries, confidenceIntervalSeries);
    231           if (confidenceIntervalSeries != null)
    232             confidenceIntervalSeries.Name = "95% Conf. Interval " + meanSeries.Name;
    233         }
    234         catch (TaskCanceledException) {
    235           return;
    236         }
    237       }
    238 
     306    private Tuple<Series, Series> CreateSeries(IRegressionSolution solution) {
     307      var series = new Series {
     308        ChartType = SeriesChartType.Line,
     309        Name = solution.ProblemData.TargetVariable + " " + solutions.IndexOf(solution)
     310      };
     311      series.LegendText = series.Name;
     312
     313      var confidenceBoundSolution = solution as IConfidenceBoundRegressionSolution;
     314      Series confidenceIntervalSeries = null;
     315      if (confidenceBoundSolution != null) {
     316        confidenceIntervalSeries = new Series {
     317          ChartType = SeriesChartType.Range,
     318          YValuesPerPoint = 2,
     319          Name = "95% Conf. Interval " + series.Name,
     320          IsVisibleInLegend = false
     321        };
     322      }
     323      return Tuple.Create(series, confidenceIntervalSeries);
     324    }
     325
     326    private void OrderAndColorSeries() {
    239327      chart.SuspendRepaint();
     328
    240329      chart.Series.Clear();
    241330      // Add mean series for applying palette colors
    242       foreach (var series in seriesDict.Keys.OrderBy(s => (int)s.Tag)) {
    243         series.LegendText = series.Name;
    244         chart.Series.Add(series);
    245       }
     331      foreach (var solution in solutions) {
     332        chart.Series.Add(seriesCache[solution]);
     333      }
     334
    246335      chart.Palette = ChartColorPalette.BrightPastel;
    247336      chart.ApplyPaletteColors();
    248337      chart.Palette = ChartColorPalette.None;
    249338
    250       foreach (var series in seriesDict.OrderBy(s => (int)s.Key.Tag)) {
    251         if (series.Value == null) continue;
    252         int idx = chart.Series.IndexOf(series.Key);
    253         series.Value.Color = Color.FromArgb(40, series.Key.Color);
    254         series.Value.IsVisibleInLegend = false;
    255         chart.Series.Insert(idx, series.Value);
    256       }
     339      // Add confidence interval series before its coresponding series for correct z index
     340      foreach (var solution in solutions) {
     341        Series ciSeries;
     342        if (ciSeriesCache.TryGetValue(solution, out ciSeries)) {
     343          var series = seriesCache[solution];
     344          ciSeries.Color =  Color.FromArgb(40, series.Color);
     345          int idx = chart.Series.IndexOf(seriesCache[solution]);
     346          chart.Series.Insert(idx, ciSeries);
     347        }
     348      }
     349
    257350      chart.ResumeRepaint(true);
    258 
    259 
    260       ////calculate Y-axis interval
    261       //double ymin = 0, ymax = 0;
    262       //foreach (var vs in chart.Series.SelectMany(series => series.Points.Select(s => s.YValues))) {
    263       //  for (int index = 0; index < vs.Length; index++) {
    264       //    var v = vs[index];
    265       //    if (ymin > v) ymin = v;
    266       //    if (ymax < v) ymax = v;
    267       //  }
    268       //}
    269       //ChartUtil.CalculateAxisInterval(ymin, ymax, YXAxisTicks, out axisMin, out axisMax, out axisInterval);
    270       //axis = chart.ChartAreas[0].AxisY;
    271       //axis.Minimum = axisMin;
    272       //axis.Maximum = axisMax;
    273       //axis.Interval = axisInterval;
    274       //chart.ChartAreas[0].RecalculateAxesScale();
    275 
    276       // set axis title
    277       chart.ChartAreas[0].AxisX.Title = FreeVariable + " : " + defaultValue.ToString("N3", CultureInfo.CurrentCulture);
    278 
    279       UpdateStripLines();
    280 
    281       statusLabel.Visible = false;
    282     }
    283 
    284     private Task<Tuple<Series, Series>> CreateSeriesAsync(IRegressionSolution solution, CancellationToken cancellationToken) {
     351    }
     352
     353    private Task UpdateSeriesData(CancellationToken cancellationToken) {
    285354      return Task.Run(() => {
    286         var xvalues = internalDataset.GetDoubleValues(FreeVariable).ToList();
    287         var yvalues = solution.Model.GetEstimatedValues(internalDataset, Enumerable.Range(0, internalDataset.Rows)).ToList();
    288 
    289         var series = new Series { ChartType = SeriesChartType.Line };
    290         series.Points.DataBindXY(xvalues, yvalues);
    291 
    292         var confidenceBoundSolution = solution as IConfidenceBoundRegressionSolution;
    293         Series confidenceIntervalSeries = null;
    294         if (confidenceBoundSolution != null) {
    295           var variances = confidenceBoundSolution.Model.GetEstimatedVariances(internalDataset, Enumerable.Range(0, internalDataset.Rows)).ToList();
    296 
    297           var lower = yvalues.Zip(variances, (m, s2) => m - 1.96 * Math.Sqrt(s2)).ToList();
    298           var upper = yvalues.Zip(variances, (m, s2) => m + 1.96 * Math.Sqrt(s2)).ToList();
    299 
    300           confidenceIntervalSeries = new Series { ChartType = SeriesChartType.Range, YValuesPerPoint = 2 };
    301           confidenceIntervalSeries.Points.DataBindXY(xvalues, lower, upper);
    302         }
    303         return Tuple.Create(series, confidenceIntervalSeries);
     355        Parallel.ForEach(solutions, new ParallelOptions { CancellationToken = cancellationToken }, solution => {
     356          var xvalues = internalDataset.GetDoubleValues(FreeVariable).ToList();
     357          var yvalues = solution.Model.GetEstimatedValues(internalDataset, Enumerable.Range(0, internalDataset.Rows)).ToList();
     358
     359          var series = seriesCache[solution];
     360          for (int i = 0; i < xvalues.Count; i++)
     361            series.Points[i].SetValueXY(xvalues[i], yvalues[i]);
     362
     363          var confidenceBoundSolution = solution as IConfidenceBoundRegressionSolution;
     364          if (confidenceBoundSolution != null) {
     365            var confidenceIntervalSeries = ciSeriesCache[solution];
     366
     367            cancellationToken.ThrowIfCancellationRequested();
     368            var variances =
     369              confidenceBoundSolution.Model.GetEstimatedVariances(internalDataset,
     370                Enumerable.Range(0, internalDataset.Rows)).ToList();
     371            for (int i = 0; i < xvalues.Count; i++) {
     372              var lower = yvalues[i] - 1.96 * Math.Sqrt(variances[i]);
     373              var upper = yvalues[i] + 1.96 * Math.Sqrt(variances[i]);
     374              confidenceIntervalSeries.Points[i].SetValueXY(xvalues[i], lower, upper);
     375            }
     376          }
     377          cancellationToken.ThrowIfCancellationRequested();
     378        });
    304379      }, cancellationToken);
    305380    }
    306381
    307     public void AddSolution(IRegressionSolution solution) {
     382    private void ResizeAllSeriesData() {
     383      var xvalues = internalDataset.GetDoubleValues(FreeVariable).ToList();
     384      foreach (var solution in solutions)
     385        ResizeSeriesData(solution, xvalues);
     386    }
     387    private void ResizeSeriesData(IRegressionSolution solution, IList<double> xvalues = null) {
     388      if (xvalues == null)
     389        xvalues = internalDataset.GetDoubleValues(FreeVariable).ToList();
     390
     391      var series = seriesCache[solution];
     392      series.Points.SuspendUpdates();
     393      for (int i = 0; i < xvalues.Count; i++)
     394        series.Points.Add(new DataPoint(xvalues[i], 0.0));
     395      series.Points.ResumeUpdates();
     396
     397      Series confidenceIntervalSeries;
     398      if (ciSeriesCache.TryGetValue(solution, out confidenceIntervalSeries)) {
     399        confidenceIntervalSeries.Points.SuspendUpdates();
     400        for (int i = 0; i < xvalues.Count; i++)
     401          confidenceIntervalSeries.Points.Add(new DataPoint(xvalues[i], new[] { -1.0, 1.0 }));
     402        confidenceIntervalSeries.Points.ResumeUpdates();
     403      }
     404    }
     405
     406    public async Task AddSolutionAsync(IRegressionSolution solution) {
    308407      if (!SolutionsCompatible(solutions.Concat(new[] { solution })))
    309408        throw new ArgumentException("The solution is not compatible with the problem data.");
    310       if (solutions.Contains(solution)) return;
     409      if (solutions.Contains(solution))
     410        return;
     411
    311412      solutions.Add(solution);
    312       RecalculateTrainingLimits();
    313       UpdateChart();
    314     }
    315     public void RemoveSolution(IRegressionSolution solution) {
    316       if (!solutions.Remove(solution)) return;
    317       RecalculateTrainingLimits();
    318       UpdateChart();
     413      RecalculateTrainingLimits(true);
     414
     415      var series = CreateSeries(solution);
     416      seriesCache.Add(solution, series.Item1);
     417      if (series.Item2 != null)
     418        ciSeriesCache.Add(solution, series.Item2);
     419
     420      ResizeSeriesData(solution);
     421      OrderAndColorSeries();
     422
     423      await RecalculateAsync();
     424    }
     425    public async Task RemoveSolutionAsync(IRegressionSolution solution) {
     426      if (!solutions.Remove(solution))
     427        return;
     428
     429      RecalculateTrainingLimits(true);
     430
     431      seriesCache.Remove(solution);
     432      ciSeriesCache.Remove(solution);
     433
     434      await RecalculateAsync();
    319435    }
    320436
     
    333449    }
    334450
    335     private void UpdateStripLines() {
     451    private void UpdateOutOfTrainingRangeStripLines() {
    336452      var axisX = chart.ChartAreas[0].AxisX;
    337453      var lowerStripLine = axisX.StripLines[0];
     
    345461    }
    346462
    347     #region events
     463    #region Events
    348464    public event EventHandler VariableValueChanged;
    349465    public void OnVariableValueChanged(object sender, EventArgs args) {
     
    353469    }
    354470
    355     private void chart_AnnotationPositionChanged(object sender, EventArgs e) {
    356       //var annotation = VerticalLineAnnotation;
    357       //var x = annotation.X;
    358       //sharedFixedVariables.SetVariableValue(x, FreeVariable, 0);
    359 
    360       //chart.ChartAreas[0].AxisX.Title = FreeVariable + " : " + x.ToString("N3", CultureInfo.CurrentCulture);
    361       //chart.Update();
    362 
    363       //OnVariableValueChanged(this, EventArgs.Empty);
    364     }
    365 
     471    private void sharedFixedVariables_ItemChanged(object o, EventArgs<int, int> e) {
     472      if (o != sharedFixedVariables) return;
     473      var variables = sharedFixedVariables.DoubleVariables.ToList();
     474      var rowIndex = e.Value;
     475      var columnIndex = e.Value2;
     476
     477      var variableName = variables[columnIndex];
     478      if (variableName == FreeVariable) return;
     479      var v = sharedFixedVariables.GetDoubleValue(variableName, rowIndex);
     480      var values = new List<double>(Enumerable.Repeat(v, DrawingSteps));
     481      internalDataset.ReplaceVariable(variableName, values);
     482    }
     483
     484    private double oldCurserPosition = double.NaN;
    366485    private void chart_AnnotationPositionChanging(object sender, AnnotationPositionChangingEventArgs e) {
     486      if (oldCurserPosition.IsAlmost(e.NewLocationX))
     487        return;
     488      oldCurserPosition = e.NewLocationX;
     489
    367490      var step = (trainingMax - trainingMin) / drawingSteps;
    368491      e.NewLocationX = step * (long)Math.Round(e.NewLocationX / step);
     
    384507
    385508    private void chart_MouseMove(object sender, MouseEventArgs e) {
    386       chart.Cursor = chart.HitTest(e.X, e.Y).ChartElementType == ChartElementType.Annotation ? Cursors.VSplit : Cursors.Default;
     509      bool hitCursor = chart.HitTest(e.X, e.Y).ChartElementType == ChartElementType.Annotation;
     510      chart.Cursor = hitCursor ? Cursors.VSplit : Cursors.Default;
    387511    }
    388512
     
    402526    }
    403527
    404     private void GradientChart_DragDrop(object sender, DragEventArgs e) {
     528    private void chart_DragDrop(object sender, DragEventArgs e) {
    405529      var data = e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat);
    406530      if (data != null) {
    407531        var solution = data as IRegressionSolution;
    408         if (!Solutions.Contains(solution))
    409           AddSolution(solution);
    410       }
    411     }
    412     private void GradientChart_DragEnter(object sender, DragEventArgs e) {
     532        if (!solutions.Contains(solution))
     533          AddSolutionAsync(solution);
     534      }
     535    }
     536    private void chart_DragEnter(object sender, DragEventArgs e) {
    413537      if (!e.Data.GetDataPresent(HeuristicLab.Common.Constants.DragDropDataFormat)) return;
    414538      e.Effect = DragDropEffects.None;
Note: See TracChangeset for help on using the changeset viewer.