/// <summary> /// Does Arian's PCA-ANOVA idea. /// </summary> public double PcaAnova(IntensityMatrix source, Peak peak, Core core, List <GroupInfo> types, List <int> replicates) { Range times = GetOverlappingTimeRange(core, source, types); // Create a matrix thusly: // Control Replicate 1: <day1> <day2> <day3> ... // Control Replicate 2: <day1> <day2> <day3> ... // Control Replicate 3: <day1> <day2> <day3> ... // Drought Replicate 1: <day1> <day2> <day3> ... // Drought Replicate 2: <day1> <day2> <day3> ... // ... // Create and clear the matrix int rowCount = types.Count * replicates.Count; int colCount = times.Count; double[,] matrix = new double[rowCount, colCount]; for (int r = 0; r < rowCount; r++) { for (int c = 0; c < colCount; c++) { matrix[r, c] = double.NaN; } } // Create the group vector double[] groups = new double[rowCount]; for (int r = 0; r < rowCount; r++) { groups[r] = types[r / replicates.Count].Order; } IReadOnlyList <double> raw = source.Find(peak).Values; // TODO: Dirty // Fill out the values we know for (int i = 0; i < core.Observations.Count; i++) { ObservationInfo o = core.Observations[i]; int typeIndex = types.IndexOf(o.Group); int repIndex = replicates.IndexOf(o.Rep); if (times.Contains(o.Time) && typeIndex != -1 && repIndex != -1) { int timeIndex = o.Time - times.Min; int row = typeIndex * replicates.Count + repIndex; UiControls.Assert(double.IsNaN(matrix[row, timeIndex]), "Duplicate day/time/rep observations in dataset are not allowed."); matrix[row, timeIndex] = raw[i]; } } // Guess missing values for (int r = 0; r < rowCount; r++) { for (int c = 0; c < colCount; c++) { if (double.IsNaN(matrix[r, c])) { // Missing values - average other values for this point int repIndex = r % replicates.Count; int typeStart = r - repIndex; double total = 0; int count = 0; for (int rep = 0; rep < replicates.Count; rep++) { int newRow = typeStart + rep; if (!double.IsNaN(matrix[newRow, c])) { total += matrix[newRow, c]; count += 1; } } matrix[r, c] = total / count; } } } // Now do that R stuff... var rMatrix = _r.CreateNumericMatrix(matrix); var rVector = _r.CreateNumericVector(groups); _r.SetSymbol("a", rMatrix); _r.SetSymbol("g", rVector); //R.Evaluate("write.csv(a, file = \"E:/MJR/Project/05. PEAS/AbstressData/Leaf/Positive/CCor/LP1131.cs.csv\")"); try { double result = _r.Evaluate( @"p = prcomp(a) f = data.frame(y = p$x[,1], group = factor(g)) fit = lm(y ~ group, f) an = anova(fit) pval = an$""Pr(>F)""[1]").AsNumeric()[0]; return(result); } catch (Exception ex) { throw new Exception("Something went wrong calculating PCA-ANOVA statistics. See inner exception for details. (Note that this error can occur if only 1 replicate is specified and PCA-ANOVA is calculated with missing values - make sure the replicates are specified correctly.)", ex); } }
/// <summary> /// Generates the preview image. /// </summary> /// <param name="sel">Correction to generate the preview for</param> private void GeneratePreview(ArgsCorrection sel) { // No error unless otherwise this._lnkError.Visible = false; // No selection, no preview if (sel == null) { this.SetPreviewError("Nothing to preview", null); return; } // No peak, no preview if (this._selectedPeak == null) { this.SetPreviewError("No peak selected", null); return; } // Title this._lblPreviewTitle.Text = "Preview (" + this._selectedPeak.DisplayName + ")"; // Get source matrix IntensityMatrix source = sel.SourceProvider?.Provide; if (source == null) { this.SetPreviewError(StrRes.NoPreview, StrRes.MissingSourceDetails(sel)); return; } // Get vectors Vector original = source.Find(this._selectedPeak); Vector trend; Vector corrected; ConfigurationCorrection temp = new ConfigurationCorrection() { Args = sel }; try { IReadOnlyList <ObservationInfo> order; double[] trendData = temp.ExtractTrend(this._core, original.Values, out order); trend = (trendData != null) ? new Vector(trendData, original.Header, order.Select(z => new IntensityMatrix.ColumnHeader(z)).ToArray()) : null; corrected = new Vector(temp.Calculate(this._core, original.Values), original.Header, original.ColHeaders); } catch (Exception ex) { this._chartOrig.Plot(null); this._chartChanged.Plot(null); this._lnkError.Text = StrRes.PreviewError; this._lnkError.Tag = ex.ToString(); this._lnkError.Visible = true; return; } // Special flag for batch ordering bool isBatchMode; if (sel.IsUsingTrend) { isBatchMode = sel.Mode == ECorrectionMode.Batch; } else { isBatchMode = false; } // Create displays StylisedPeak oldDisplay = new StylisedPeak(this._selectedPeak) { OverrideDefaultOptions = new StylisedPeakOptions(this._core) { ShowAcqisition = isBatchMode, ViewBatches = this._vBatches, ViewGroups = this._vTypes, ConditionsSideBySide = true, ShowPoints = true, ShowTrend = sel.IsUsingTrend, ShowRanges = false, }, ForceTrend = trend }; StylisedPeak newDisplay = new StylisedPeak(this._selectedPeak) { OverrideDefaultOptions = oldDisplay.OverrideDefaultOptions.Clone(), ForceObservations = corrected }; newDisplay.OverrideDefaultOptions.ShowTrend = false; // Draw it! this._chartOrig.Plot(oldDisplay); this._chartChanged.Plot(newDisplay); }
public void Plot(StylisedPeak stylisedPeak) { // Get observations Vector vector; if (stylisedPeak.ForceObservations != null) { vector = stylisedPeak.ForceObservations; } else { IntensityMatrix matrix = this._core.Options.SelectedMatrix; if (matrix == null) { vector = null; } else { vector = matrix.Find(stylisedPeak.Peak); } } Debug.WriteLine("PeakPlot: " + stylisedPeak); Dictionary <string, MCharting.Series> seriesNames = new Dictionary <string, MCharting.Series>(); Peak peak = stylisedPeak?.Peak; // Clear plot MCharting.Plot plot = this.PrepareNewPlot(stylisedPeak != null && !stylisedPeak.IsPreview, peak, vector?.Source); try // <- CompletNewPlot { // Get selection this.SelectedPeak = peak; this.SetCaption("Plot of {0}.", peak); if (peak == null) { return; } // Get options StylisedPeakOptions opts = stylisedPeak.OverrideDefaultOptions ?? new StylisedPeakOptions(this._core); // Get order data ObservationInfo[] obsOrder = this._core.Observations.ToArray(); // Group legends IEnumerable <GroupInfoBase> order = opts.ShowAcqisition ? (IEnumerable <GroupInfoBase>)opts.ViewBatches : (IEnumerable <GroupInfoBase>)opts.ViewGroups; Dictionary <GroupInfoBase, MCharting.Series> groupLegends = this.DrawLegend(plot, order); if (vector == null) { return; } // Show acquisition and batches? if (opts.ShowAcqisition) { // --- RAW DATA (points) --- MCharting.Series legendEntry = new MCharting.Series(); legendEntry.Name = "Observations"; legendEntry.Style.DrawPoints = new SolidBrush(Color.Black); plot.LegendEntries.Add(legendEntry); this.AddToPlot(plot, peak, seriesNames, vector, "Raw data", opts, EPlot.ByBatch, groupLegends, legendEntry); // --- TREND (thick line) --- if (stylisedPeak.ForceTrend != null) { MCharting.Series legendEntry2 = new MCharting.Series(); legendEntry2.Name = "Trend"; legendEntry2.Style.DrawLines = new Pen(Color.Black, this._core.Options.LineWidth); legendEntry2.Style.DrawLines.Width = 4; plot.LegendEntries.Add(legendEntry2); this.AddToPlot(plot, peak, seriesNames, stylisedPeak.ForceTrend, "Trend data", opts, EPlot.ByBatch | EPlot.DrawLine | EPlot.DrawBold, groupLegends, legendEntry2); } this.DrawLabels(plot, opts.ConditionsSideBySide, order, opts.DrawExperimentalGroupAxisLabels); return; } // Sort data ConfigurationTrend trend = opts.SelectedTrend; Vector avg = stylisedPeak.ForceTrend ?? trend.CreateTrend(this._core, vector); Vector min = MinSmoother.CreateTrend(this._core, vector); Vector max = MaxSmoother.CreateTrend(this._core, vector); // --- PLOT MEAN & SD (lines across) if (opts.ShowVariableMean) { this.AddMeanAndSdLines(plot, opts, vector.Values, peak, groupLegends); } // --- RANGE (shaded area) --- if (opts.ShowRanges) { this.AddUpperAndLowerShade(plot, opts, seriesNames, peak, min, max, groupLegends); } // --- RAW DATA (points) --- if (opts.ShowPoints && !stylisedPeak.IsPreview) { MCharting.Series legendEntry = new MCharting.Series(); legendEntry.Name = "Observations"; legendEntry.Style.DrawPoints = new SolidBrush(Color.Black); plot.LegendEntries.Add(legendEntry); this.AddToPlot(plot, peak, seriesNames, vector, "Raw data", opts, EPlot.None, groupLegends, legendEntry); } // --- RANGE (lines) --- if (opts.ShowMinMax) { MCharting.Series legendEntry = new MCharting.Series(); legendEntry.Name = "Range min/max"; legendEntry.Style.DrawLines = new Pen(Color.Gray, this._core.Options.LineWidth); plot.LegendEntries.Add(legendEntry); this.AddToPlot(plot, peak, seriesNames, min, "Min value", opts, EPlot.DrawLine, groupLegends, legendEntry); this.AddToPlot(plot, peak, seriesNames, max, "Max value", opts, EPlot.DrawLine, groupLegends, legendEntry); } // --- TREND (thick line) --- if (opts.ShowTrend) { MCharting.Series legendEntry = new MCharting.Series(); legendEntry.Name = "Trend"; legendEntry.Style.DrawLines = new Pen(Color.Black, this._core.Options.LineWidth); legendEntry.Style.DrawLines.Width = this._core.Options.LineWidth * 4; plot.LegendEntries.Add(legendEntry); this.AddToPlot(plot, peak, seriesNames, avg, "Trend data", opts, EPlot.DrawLine | EPlot.DrawBold, groupLegends, legendEntry); } // --- LABELS --- this.DrawLabels(plot, opts.ConditionsSideBySide, order, opts.DrawExperimentalGroupAxisLabels); } finally { this.CompleteNewPlot(plot); } }