private void Values_ItemsRemoved(object sender, CollectionItemsChangedEventArgs <IndexedItem <Tuple <T, double> > > e) { if (InvokeRequired) { Invoke(new CollectionItemsChangedEventHandler <IndexedItem <Tuple <T, double> > >(Values_ItemsRemoved), sender, e); } else { IndexedDataRow <T> row = null; valuesRowsTable.TryGetValue((IObservableList <Tuple <T, double> >)sender, out row); if (row != null) { if (row.Values.Count == 0) { RemoveDataRow(row); } else { Series rowSeries = chart.Series[row.Name]; if (!invisibleSeries.Contains(rowSeries)) { rowSeries.Points.Clear(); FillSeriesWithRowValues(rowSeries, row); RecalculateAxesScale(chart.ChartAreas[0]); UpdateYCursorInterval(); } } } } }
/// <summary> /// Add the DataRow as a series to the chart. /// </summary> /// <param name="row">DataRow to add as series to the chart.</param> protected virtual void AddDataRow(IndexedDataRow <T> row) { if (row.Values.Count == 0) { return; } Series series = new Series(row.Name); if (row.VisualProperties.DisplayName.Trim() != String.Empty) { series.LegendText = row.VisualProperties.DisplayName; } else { series.LegendText = row.Name; } ConfigureSeries(series, row); FillSeriesWithRowValues(series, row); chart.Series.Add(series); ConfigureChartArea(chart.ChartAreas[0]); RecalculateAxesScale(chart.ChartAreas[0]); UpdateYCursorInterval(); }
/// <summary> /// Automatically called for every existing data row and whenever a data row is added /// to the data table. Do not call this method directly. /// </summary> /// <param name="row">The DataRow that was added.</param> protected virtual void RegisterDataRowEvents(IndexedDataRow <T> row) { row.NameChanged += new EventHandler(Row_NameChanged); row.VisualPropertiesChanged += new EventHandler(Row_VisualPropertiesChanged); valuesRowsTable.Add(row.Values, row); row.Values.ItemsAdded += new CollectionItemsChangedEventHandler <IndexedItem <Tuple <T, double> > >(Values_ItemsAdded); row.Values.ItemsRemoved += new CollectionItemsChangedEventHandler <IndexedItem <Tuple <T, double> > >(Values_ItemsRemoved); row.Values.ItemsReplaced += new CollectionItemsChangedEventHandler <IndexedItem <Tuple <T, double> > >(Values_ItemsReplaced); row.Values.ItemsMoved += new CollectionItemsChangedEventHandler <IndexedItem <Tuple <T, double> > >(Values_ItemsMoved); row.Values.CollectionReset += new CollectionItemsChangedEventHandler <IndexedItem <Tuple <T, double> > >(Values_CollectionReset); }
/// <summary> /// Remove the corresponding series for a certain DataRow. /// </summary> /// <param name="row">DataRow which series should be removed.</param> protected virtual void RemoveDataRow(IndexedDataRow <T> row) { if (chart.Series.All(x => x.Name != row.Name)) { return; } Series series = chart.Series[row.Name]; chart.Series.Remove(series); if (invisibleSeries.Contains(series)) { invisibleSeries.Remove(series); } RecalculateAxesScale(chart.ChartAreas[0]); }
public void TestIndexedDataTable() { var dt = new IndexedDataTable <int>("test", "test description"); var dr = new IndexedDataRow <int>("test row"); dr.Values.Add(Tuple.Create(1, 1.0)); dr.Values.Add(Tuple.Create(2, 2.0)); dr.Values.Add(Tuple.Create(3, 3.0)); dt.Rows.Add(dr); var ser = new ProtoBufSerializer(); ser.Serialize(dt, tempFile); var dt2 = (IndexedDataTable <int>)ser.Deserialize(tempFile); Assert.AreEqual(dt.Rows["test row"].Values[0], dt2.Rows["test row"].Values[0]); Assert.AreEqual(dt.Rows["test row"].Values[1], dt2.Rows["test row"].Values[1]); Assert.AreEqual(dt.Rows["test row"].Values[2], dt2.Rows["test row"].Values[2]); }
private void FillSeriesWithRowValues(Series series, IndexedDataRow <T> row) { for (int i = 0; i < row.Values.Count; i++) { var value = row.Values[i]; if (IsInvalidValue(value.Item2)) { continue; } var point = new DataPoint(); point.SetValueXY(value.Item1, value.Item2); if (i == row.Values.Count - 1) { point.Label = series.Name; point.MarkerStyle = MarkerStyle.Cross; point.MarkerSize = 15; point.MarkerBorderWidth = 1; } series.Points.Add(point); } }
private void CreateSolutionPath() { double[] lambda; double[] trainNMSE; double[] testNMSE; double[,] coeff; double[] intercept; RunElasticNetLinearRegression(Problem.ProblemData, Penality, out lambda, out trainNMSE, out testNMSE, out coeff, out intercept); var coeffTable = new IndexedDataTable <double>("Coefficients", "The paths of standarized coefficient values over different lambda values"); coeffTable.VisualProperties.YAxisMaximumAuto = false; coeffTable.VisualProperties.YAxisMinimumAuto = false; coeffTable.VisualProperties.XAxisMaximumAuto = false; coeffTable.VisualProperties.XAxisMinimumAuto = false; coeffTable.VisualProperties.XAxisLogScale = true; coeffTable.VisualProperties.XAxisTitle = "Lambda"; coeffTable.VisualProperties.YAxisTitle = "Coefficients"; coeffTable.VisualProperties.SecondYAxisTitle = "Number of variables"; var nLambdas = lambda.Length; var nCoeff = coeff.GetLength(1); var dataRows = new IndexedDataRow <double> [nCoeff]; var allowedVars = Problem.ProblemData.AllowedInputVariables.ToArray(); var numNonZeroCoeffs = new int[nLambdas]; var ds = Problem.ProblemData.Dataset; var doubleVariables = allowedVars.Where(ds.VariableHasType <double>); var factorVariableNames = allowedVars.Where(ds.VariableHasType <string>); var factorVariablesAndValues = ds.GetFactorVariableValues(factorVariableNames, Enumerable.Range(0, ds.Rows)); // must consider all factor values (in train and test set) { int i = 0; foreach (var factorVariableAndValues in factorVariablesAndValues) { foreach (var factorValue in factorVariableAndValues.Value) { double sigma = ds.GetStringValues(factorVariableAndValues.Key) .Select(s => s == factorValue ? 1.0 : 0.0) .StandardDeviation(); // calc std dev of binary indicator var path = Enumerable.Range(0, nLambdas).Select(r => Tuple.Create(lambda[r], coeff[r, i] * sigma)).ToArray(); dataRows[i] = new IndexedDataRow <double>(factorVariableAndValues.Key + "=" + factorValue, factorVariableAndValues.Key + "=" + factorValue, path); i++; } } foreach (var doubleVariable in doubleVariables) { double sigma = ds.GetDoubleValues(doubleVariable).StandardDeviation(); var path = Enumerable.Range(0, nLambdas).Select(r => Tuple.Create(lambda[r], coeff[r, i] * sigma)).ToArray(); dataRows[i] = new IndexedDataRow <double>(doubleVariable, doubleVariable, path); i++; } // add to coeffTable by total weight (larger area under the curve => more important); foreach (var r in dataRows.OrderByDescending(r => r.Values.Select(t => t.Item2).Sum(x => Math.Abs(x)))) { coeffTable.Rows.Add(r); } } for (int i = 0; i < coeff.GetLength(0); i++) { for (int j = 0; j < coeff.GetLength(1); j++) { if (!coeff[i, j].IsAlmost(0.0)) { numNonZeroCoeffs[i]++; } } } if (lambda.Length > 2) { coeffTable.VisualProperties.XAxisMinimumFixedValue = Math.Pow(10, Math.Floor(Math.Log10(lambda.Last()))); coeffTable.VisualProperties.XAxisMaximumFixedValue = Math.Pow(10, Math.Ceiling(Math.Log10(lambda.Skip(1).First()))); } coeffTable.Rows.Add(new IndexedDataRow <double>("Number of variables", "The number of non-zero coefficients for each step in the path", lambda.Zip(numNonZeroCoeffs, (l, v) => Tuple.Create(l, (double)v)))); coeffTable.Rows["Number of variables"].VisualProperties.ChartType = DataRowVisualProperties.DataRowChartType.Points; coeffTable.Rows["Number of variables"].VisualProperties.SecondYAxis = true; Results.Add(new Result(coeffTable.Name, coeffTable.Description, coeffTable)); var errorTable = new IndexedDataTable <double>("NMSE", "Path of NMSE values over different lambda values"); errorTable.VisualProperties.YAxisMaximumAuto = false; errorTable.VisualProperties.YAxisMinimumAuto = false; errorTable.VisualProperties.XAxisMaximumAuto = false; errorTable.VisualProperties.XAxisMinimumAuto = false; errorTable.VisualProperties.YAxisMinimumFixedValue = 0; errorTable.VisualProperties.YAxisMaximumFixedValue = 1.0; errorTable.VisualProperties.XAxisLogScale = true; errorTable.VisualProperties.XAxisTitle = "Lambda"; errorTable.VisualProperties.YAxisTitle = "Normalized mean of squared errors (NMSE)"; errorTable.VisualProperties.SecondYAxisTitle = "Number of variables"; errorTable.Rows.Add(new IndexedDataRow <double>("NMSE (train)", "Path of NMSE values over different lambda values", lambda.Zip(trainNMSE, (l, v) => Tuple.Create(l, v)))); errorTable.Rows.Add(new IndexedDataRow <double>("NMSE (test)", "Path of NMSE values over different lambda values", lambda.Zip(testNMSE, (l, v) => Tuple.Create(l, v)))); errorTable.Rows.Add(new IndexedDataRow <double>("Number of variables", "The number of non-zero coefficients for each step in the path", lambda.Zip(numNonZeroCoeffs, (l, v) => Tuple.Create(l, (double)v)))); if (lambda.Length > 2) { errorTable.VisualProperties.XAxisMinimumFixedValue = Math.Pow(10, Math.Floor(Math.Log10(lambda.Last()))); errorTable.VisualProperties.XAxisMaximumFixedValue = Math.Pow(10, Math.Ceiling(Math.Log10(lambda.Skip(1).First()))); } errorTable.Rows["NMSE (train)"].VisualProperties.ChartType = DataRowVisualProperties.DataRowChartType.Points; errorTable.Rows["NMSE (test)"].VisualProperties.ChartType = DataRowVisualProperties.DataRowChartType.Points; errorTable.Rows["Number of variables"].VisualProperties.ChartType = DataRowVisualProperties.DataRowChartType.Points; errorTable.Rows["Number of variables"].VisualProperties.SecondYAxis = true; Results.Add(new Result(errorTable.Name, errorTable.Description, errorTable)); }
private void ConfigureSeries(Series series, IndexedDataRow <T> row) { RemoveCustomPropertyIfExists(series, "PointWidth"); series.BorderWidth = 1; series.BorderDashStyle = ChartDashStyle.Solid; series.BorderColor = Color.Empty; series.Color = row.VisualProperties.Color; series.IsVisibleInLegend = row.VisualProperties.IsVisibleInLegend; series.SmartLabelStyle.Enabled = true; series.SmartLabelStyle.AllowOutsidePlotArea = LabelOutsidePlotAreaStyle.No; series.SmartLabelStyle.CalloutLineAnchorCapStyle = LineAnchorCapStyle.None; series.SmartLabelStyle.CalloutLineColor = series.Color; series.SmartLabelStyle.CalloutLineWidth = 2; series.SmartLabelStyle.CalloutStyle = LabelCalloutStyle.Underlined; series.SmartLabelStyle.IsOverlappedHidden = false; series.SmartLabelStyle.MaxMovingDistance = 200; switch (row.VisualProperties.ChartType) { case DataRowVisualProperties.DataRowChartType.Line: series.ChartType = SeriesChartType.FastLine; series.BorderWidth = row.VisualProperties.LineWidth; series.BorderDashStyle = ConvertLineStyle(row.VisualProperties.LineStyle); break; case DataRowVisualProperties.DataRowChartType.Bars: // Bar is incompatible with anything but Bar and StackedBar* if (!chart.Series.Any(x => x.ChartType != SeriesChartType.Bar && x.ChartType != SeriesChartType.StackedBar && x.ChartType != SeriesChartType.StackedBar100)) { series.ChartType = SeriesChartType.Bar; chart.ChartAreas[0].AxisX.Interval = 1; } else { series.ChartType = SeriesChartType.FastPoint; //default row.VisualProperties.ChartType = DataRowVisualProperties.DataRowChartType.Points; } break; case DataRowVisualProperties.DataRowChartType.Columns: series.ChartType = SeriesChartType.Column; break; case DataRowVisualProperties.DataRowChartType.Points: series.ChartType = SeriesChartType.FastPoint; break; case DataRowVisualProperties.DataRowChartType.StepLine: series.ChartType = SeriesChartType.StepLine; series.BorderWidth = row.VisualProperties.LineWidth; series.BorderDashStyle = ConvertLineStyle(row.VisualProperties.LineStyle); break; default: series.ChartType = SeriesChartType.FastPoint; break; } series.YAxisType = row.VisualProperties.SecondYAxis ? AxisType.Secondary : AxisType.Primary; series.XAxisType = row.VisualProperties.SecondXAxis ? AxisType.Secondary : AxisType.Primary; if (row.VisualProperties.DisplayName.Trim() != String.Empty) { series.LegendText = row.VisualProperties.DisplayName; } else { series.LegendText = row.Name; } series.ToolTip = series.LegendText + " X = #VALX, Y = #VALY"; }
private static IndexedDataTable <double> CoefficientGraph(double[,] coeff, double[] lambda, IEnumerable <string> allowedVars, IDataset ds, bool showOnlyRelevantBasisFuncs = true) { var coeffTable = new IndexedDataTable <double>("Coefficients", "The paths of standarized coefficient values over different lambda values"); coeffTable.VisualProperties.YAxisMaximumAuto = false; coeffTable.VisualProperties.YAxisMinimumAuto = false; coeffTable.VisualProperties.XAxisMaximumAuto = false; coeffTable.VisualProperties.XAxisMinimumAuto = false; coeffTable.VisualProperties.XAxisLogScale = true; coeffTable.VisualProperties.XAxisTitle = "Lambda"; coeffTable.VisualProperties.YAxisTitle = "Coefficients"; coeffTable.VisualProperties.SecondYAxisTitle = "Number of variables"; var nLambdas = lambda.Length; var nCoeff = coeff.GetLength(1); var dataRows = new IndexedDataRow <double> [nCoeff]; var numNonZeroCoeffs = new int[nLambdas]; var doubleVariables = allowedVars.Where(ds.VariableHasType <double>); var factorVariableNames = allowedVars.Where(ds.VariableHasType <string>); var factorVariablesAndValues = ds.GetFactorVariableValues(factorVariableNames, Enumerable.Range(0, ds.Rows)); //must consider all factor values (in train and test set) for (int i = 0; i < coeff.GetLength(0); i++) { for (int j = 0; j < coeff.GetLength(1); j++) { if (!coeff[i, j].IsAlmost(0.0)) { numNonZeroCoeffs[i]++; } } } { int i = 0; foreach (var factorVariableAndValues in factorVariablesAndValues) { foreach (var factorValue in factorVariableAndValues.Value) { double sigma = ds.GetStringValues(factorVariableAndValues.Key) .Select(s => s == factorValue ? 1.0 : 0.0) .StandardDeviation(); // calc std dev of binary indicator var path = Enumerable.Range(0, nLambdas).Select(r => Tuple.Create(lambda[r], coeff[r, i] * sigma)).ToArray(); dataRows[i] = new IndexedDataRow <double>(factorVariableAndValues.Key + "=" + factorValue, factorVariableAndValues.Key + "=" + factorValue, path); i++; } } foreach (var doubleVariable in doubleVariables) { double sigma = ds.GetDoubleValues(doubleVariable).StandardDeviation(); var path = Enumerable.Range(0, nLambdas).Select(r => Tuple.Create(lambda[r], coeff[r, i] * sigma)).ToArray(); dataRows[i] = new IndexedDataRow <double>(doubleVariable, doubleVariable, path); i++; } // add to coeffTable by total weight (larger area under the curve => more important); foreach (var r in dataRows.OrderByDescending(r => r.Values.Select(t => t.Item2).Sum(x => Math.Abs(x)))) { coeffTable.Rows.Add(r); } } if (lambda.Length > 2) { coeffTable.VisualProperties.XAxisMinimumFixedValue = Math.Pow(10, Math.Floor(Math.Log10(lambda.Last()))); coeffTable.VisualProperties.XAxisMaximumFixedValue = Math.Pow(10, Math.Ceiling(Math.Log10(lambda.Skip(1).First()))); } coeffTable.Rows.Add(new IndexedDataRow <double>("Number of variables", "The number of non-zero coefficients for each step in the path", lambda.Zip(numNonZeroCoeffs, (l, v) => Tuple.Create(l, (double)v)))); coeffTable.Rows["Number of variables"].VisualProperties.ChartType = DataRowVisualProperties.DataRowChartType.Points; coeffTable.Rows["Number of variables"].VisualProperties.SecondYAxis = true; return(coeffTable); }