示例#1
0
        public void Execute()
        {
            using (var suspendToken = _destinationTable.SuspendGetToken())
            {
                var numRows = _sourceMatrix.RowCount;
                var numCols = _sourceMatrix.ColumnCount;

                int columnNumber = 0;

                var dataCols = _destinationTable.DataColumns;

                foreach (var tuple in _rowHeaderColumns)
                {
                    var col = dataCols.EnsureExistenceAtPositionStrictly <DoubleColumn>(columnNumber, tuple.Item2, GetIndependendVariableColumnKind(columnNumber), 0);
                    col.AssignVector = tuple.Item1;
                    col.CutToMaximumLength(numRows);
                    ++columnNumber;
                }

                for (int i = 0; i < _sourceMatrix.ColumnCount; ++i)
                {
                    string columnName;
                    if (null != ColumnNameGenerator)
                    {
                        columnName = ColumnNameGenerator(i);
                    }
                    else
                    {
                        columnName = string.Format("{0}{1}", string.IsNullOrEmpty(_columnNameBase) ? DefaultColumnBaseName : _columnNameBase, i);
                    }

                    var col = dataCols.EnsureExistenceAtPositionStrictly <DoubleColumn>(columnNumber, columnName, ColumnKind.V, 0);
                    col.AssignVector = MatrixMath.ColumnToROVector(_sourceMatrix, i);
                    col.CutToMaximumLength(numRows);
                    ++columnNumber;
                }

                // property columns
                var numXDataCols     = _rowHeaderColumns.Count;
                int propColumnNumber = 0;
                var propCols         = _destinationTable.PropertyColumns;
                foreach (var tuple in _columnHeaderColumns)
                {
                    var col = propCols.EnsureExistenceAtPositionStrictly <DoubleColumn>(propColumnNumber, tuple.Item2, GetIndependendVariableColumnKind(propColumnNumber), 0);
                    VectorMath.Copy(tuple.Item1, col.ToVector(numXDataCols, _sourceMatrix.ColumnCount));
                    col.CutToMaximumLength(numXDataCols + _sourceMatrix.ColumnCount);
                    ++propColumnNumber;
                }

                suspendToken.Dispose();
            }
        }
示例#2
0
        /// <summary>
        /// Asks for a file name of an image file, and imports the image data into a data table.
        /// </summary>
        /// <param name="table">The table to import to.</param>
        public static void ShowImportImageDialog(this DataTable table)
        {
            ColorAmplitudeFunction colorfunc;
            var options = new Altaxo.Gui.OpenFileOptions();

            options.AddFilter("*.bmp;*.jpg;*.png,*.tif", "Image files (*.bmp;*.jpg;*.png,*.tif)");
            options.AddFilter("*.*", "All files (*.*)");
            options.FilterIndex      = 0;
            options.RestoreDirectory = true;

            if (Current.Gui.ShowOpenFileDialog(options))
            {
                using (Stream myStream = new FileStream(options.FileName, FileMode.Open, FileAccess.Read, FileShare.Read))
                {
                    var bmp = new System.Drawing.Bitmap(myStream);

                    int sizex = bmp.Width;
                    int sizey = bmp.Height;
                    //if(Format16bppGrayScale==bmp.PixelFormat)

                    colorfunc = new ColorAmplitudeFunction(ColorToBrightness);
                    // add here other function or the result of a dialog box

                    // now add new columns to the worksheet,
                    // the name of the columns should preferabbly simply
                    // the index in x direction

                    using (var suspendToken = table.SuspendGetToken())
                    {
                        for (int i = 0; i < sizex; i++)
                        {
                            var dblcol = new Altaxo.Data.DoubleColumn();
                            for (int j = sizey - 1; j >= 0; j--)
                            {
                                dblcol[j] = colorfunc(bmp.GetPixel(i, j));
                            }

                            table.DataColumns.Add(dblcol, table.DataColumns.FindUniqueColumnName(i.ToString())); // Spalte hinzufügen
                        } // end for all x coordinaates

                        suspendToken.Dispose();
                    }
                    myStream.Close();
                } // end using myStream
            }
        }
示例#3
0
文件: Sorting.cs 项目: olesar/Altaxo
        /// <summary>
        /// Sort the order of the data columns (not rows!) of a table based on a specified property column. The relationship of property data to data columns is maintained.
        /// </summary>
        /// <param name="table">The table where to sort the columns.</param>
        /// <param name="selectedDataCols">Data columns to sort.</param>
        /// <param name="propCol">The property column where the sorting order is based on.</param>
        /// <param name="inAscendingOrder">If true, the sorting is in ascending order. If false, the sorting is in descending order.</param>
        public static void SortDataColumnsByPropertyColumn(this DataTable table, IAscendingIntegerCollection selectedDataCols, DataColumn propCol, bool inAscendingOrder)
        {
            if (!table.PropCols.ContainsColumn(propCol))
            {
                throw new ArgumentException("The sorting column provided must be part of the table.PropertyColumnCollection (otherwise the swap algorithm can not sort this column)");
            }

            using (var token = table.SuspendGetToken())
            {
                if (propCol is DoubleColumn)
                {
                    HeapSort(selectedDataCols.Count, new SelectedDoubleColumnComparer((DoubleColumn)propCol, selectedDataCols, inAscendingOrder).Compare, new DataTableSelectedColumnSwapper(table, selectedDataCols).Swap);
                }
                else
                {
                    HeapSort(selectedDataCols.Count, new SelectedDataColumnComparer(propCol, selectedDataCols, inAscendingOrder).Compare, new DataTableSelectedColumnSwapper(table, selectedDataCols).Swap);
                }
            }
        }
示例#4
0
		/// <summary>
		/// Makes a PLS (a partial least squares) analysis of the table or the selected columns / rows and stores the results in a newly created table.
		/// </summary>
		/// <param name="mainDocument">The main document of the application.</param>
		/// <param name="srctable">The table where the data come from.</param>
		/// <param name="selectedColumns">The selected columns.</param>
		/// <param name="selectedRows">The selected rows.</param>
		/// <param name="selectedPropertyColumns">The selected property column(s).</param>
		/// <param name="bHorizontalOrientedSpectrum">True if a spectrum is a single row, False if a spectrum is a single column.</param>
		/// <param name="plsOptions">Provides information about the max number of factors and the calculation of cross PRESS value.</param>
		/// <param name="preprocessOptions">Provides information about how to preprocess the spectra.</param>
		/// <returns></returns>
		public virtual string ExecuteAnalysis(
			Altaxo.AltaxoDocument mainDocument,
			Altaxo.Data.DataTable srctable,
			IAscendingIntegerCollection selectedColumns,
			IAscendingIntegerCollection selectedRows,
			IAscendingIntegerCollection selectedPropertyColumns,
			bool bHorizontalOrientedSpectrum,
			MultivariateAnalysisOptions plsOptions,
			SpectralPreprocessingOptions preprocessOptions
			)
		{
			IMatrix matrixX, matrixY;
			IROVector xOfX;
			var plsContent = new MultivariateContentMemento();
			plsContent.Analysis = this;

			// now we have to create a new table where to place the calculated factors and loads
			// we will do that in a vertical oriented manner, i.e. even if the loads are
			// here in horizontal vectors: in our table they are stored in (vertical) columns
			string newName = this.AnalysisName + " of " + Main.ProjectFolder.GetNamePart(srctable.Name);
			newName = Main.ProjectFolder.CreateFullName(srctable.Name, newName);
			Altaxo.Data.DataTable table = new Altaxo.Data.DataTable(newName);
			// Fill the Table
			using (var suspendToken = table.SuspendGetToken())
			{
				table.SetTableProperty("Content", plsContent);
				plsContent.OriginalDataTableName = srctable.Name;

				// Get matrices
				GetXYMatrices(
					srctable,
					selectedColumns,
					selectedRows,
					selectedPropertyColumns,
					bHorizontalOrientedSpectrum,
					plsContent,
					out matrixX, out matrixY, out xOfX);

				StoreXOfX(xOfX, table);

				// Preprocess
				plsContent.SpectralPreprocessing = preprocessOptions;
				IVector meanX, scaleX, meanY, scaleY;
				MultivariateRegression.PreprocessForAnalysis(preprocessOptions, xOfX, matrixX, matrixY,
					out meanX, out scaleX, out meanY, out scaleY);

				StorePreprocessedData(meanX, scaleX, meanY, scaleY, table);

				// Analyze and Store
				IROVector press;
				ExecuteAnalysis(
					matrixX,
					matrixY,
					plsOptions,
					plsContent,
					table, out press);

				this.StorePRESSData(press, table);

				if (plsOptions.CrossPRESSCalculation != CrossPRESSCalculationType.None)
					CalculateCrossPRESS(xOfX, matrixX, matrixY, plsOptions, plsContent, table);

				StoreFRatioData(table, plsContent);

				StoreOriginalY(table, plsContent);

				suspendToken.Dispose();
			}
			Current.Project.DataTableCollection.Add(table);
			// create a new worksheet without any columns
			Current.ProjectService.CreateNewWorksheet(table);

			return null;
		}
示例#5
0
		/// <summary>
		/// Transfers a temporary table to a destination table. The first data columns and property columns of the destination table are replaced by the columns of the temporary table. The source table is destoyed during the transfer process (in order to save memory).
		/// </summary>
		/// <param name="fromSourceTable">Source table. Is destroyed during the transfer operation.</param>
		/// <param name="toDestinationTable">Destination table.</param>
		private static void TransferTemporaryTable(DataTable fromSourceTable, DataTable toDestinationTable)
		{
			using (var suspendToken = toDestinationTable.SuspendGetToken())
			{
				// data columns first
				var srcCollection = fromSourceTable.DataColumns;
				var destCollection = toDestinationTable.DataColumns;
				for (int i = 0; i < srcCollection.ColumnCount; ++i)
				{
					var srcColumn = srcCollection[i];
					var destColumn = destCollection.EnsureExistenceAtPositionStrictly(i, srcCollection.GetColumnName(srcColumn), srcColumn.GetType(), srcCollection.GetColumnKind(srcColumn), srcCollection.GetColumnGroup(srcColumn));
					destColumn.Clear();
					destColumn.CopyDataFrom(srcColumn);
					srcColumn.Clear();
				}

				// then property columns
				srcCollection = fromSourceTable.PropCols;
				destCollection = toDestinationTable.PropCols;
				for (int i = 0; i < srcCollection.ColumnCount; ++i)
				{
					var srcColumn = srcCollection[i];
					var destColumn = destCollection.EnsureExistenceAtPositionStrictly(i, srcCollection.GetColumnName(srcColumn), srcColumn.GetType(), srcCollection.GetColumnKind(srcColumn), srcCollection.GetColumnGroup(srcColumn));
					destColumn.Clear();
					destColumn.CopyDataFrom(srcColumn);
					srcColumn.Clear();
				}

				suspendToken.Dispose();
			}
		}
示例#6
0
        /// <summary>
        /// Transpose transpose the table, i.e. exchange columns and rows
        /// this can only work if all columns in the table are of the same type
        /// </summary>
        /// <param name="srcTable">Table to transpose.</param>
        /// <param name="options">Options that control the transpose process.</param>
        /// <param name="destTable">Table in which the transposed table should be stored.</param>
        /// <exception cref="ArgumentNullException">
        /// </exception>
        /// <exception cref="ArgumentException"></exception>
        /// <exception cref="InvalidOperationException">The data columns to transpose are not of the same type. The first column that has a deviating type is column number  + firstDifferentColumnIndex.ToString()</exception>
        public static void Transpose(this DataTable srcTable, DataTableTransposeOptions options, DataTable destTable)
        {
            if (null == srcTable)
            {
                throw new ArgumentNullException(nameof(srcTable));
            }
            if (null == destTable)
            {
                throw new ArgumentNullException(nameof(destTable));
            }
            if (object.ReferenceEquals(srcTable, destTable))
            {
                throw new ArgumentException(nameof(srcTable) + " and " + nameof(destTable) + " are identical. This inline transpose operation is not supported.");
            }

            int numberOfDataColumnsChangeToPropertyColumns = Math.Min(options.DataColumnsMoveToPropertyColumns, srcTable.DataColumnCount);

            int numberOfPropertyColumnsChangeToDataColumns = Math.Min(options.PropertyColumnsMoveToDataColumns, srcTable.PropertyColumnCount);

            // number of data columns in the destination table that originates either from converted property columns or from the label column which contains the column names
            int numberOfPriorDestDataColumns = numberOfPropertyColumnsChangeToDataColumns + (options.StoreDataColumnNamesInFirstDataColumn ? 1 : 0);

            var dataColumnsToTransposeIndices = ContiguousIntegerRange.FromStartAndEndExclusive(numberOfDataColumnsChangeToPropertyColumns, srcTable.DataColumnCount);

            if (!AreAllColumnsOfTheSameType(srcTable.DataColumns, dataColumnsToTransposeIndices, out var firstDifferentColumnIndex))
            {
                throw new InvalidOperationException("The data columns to transpose are not of the same type. The first column that has a deviating type is column number " + firstDifferentColumnIndex.ToString());
            }

            using (var suspendToken = destTable.SuspendGetToken())
            {
                destTable.DataColumns.ClearData();
                destTable.PropCols.ClearData();

                // 0th, store the data column names in the first column
                if (options.StoreDataColumnNamesInFirstDataColumn)
                {
                    var destCol = destTable.DataColumns.EnsureExistenceAtPositionStrictly(0, "DataColumnNames", typeof(TextColumn), ColumnKind.Label, 0);
                    for (int j = numberOfDataColumnsChangeToPropertyColumns, k = 0; j < srcTable.DataColumnCount; ++j, ++k)
                    {
                        destCol[k] = srcTable.DataColumns.GetColumnName(j);
                    }
                }

                int numberOfExtraPriorDestColumns = (options.StoreDataColumnNamesInFirstDataColumn ? 1 : 0);

                // 1st, copy the property columns to data columns
                for (int i = 0; i < numberOfPropertyColumnsChangeToDataColumns; ++i)
                {
                    var destCol = destTable.DataColumns.EnsureExistenceAtPositionStrictly(i + numberOfExtraPriorDestColumns, srcTable.PropertyColumns.GetColumnName(i), srcTable.PropertyColumns[i].GetType(), srcTable.PropertyColumns.GetColumnKind(i), srcTable.PropertyColumns.GetColumnGroup(i));
                    var srcCol  = srcTable.PropertyColumns[i];
                    for (int j = numberOfDataColumnsChangeToPropertyColumns, k = 0; j < srcCol.Count; ++j, ++k)
                    {
                        destCol[k] = srcCol[j];
                    }
                }

                // 2rd, transpose the data columns
                int srcRows = 0;
                foreach (int i in dataColumnsToTransposeIndices)
                {
                    srcRows = Math.Max(srcRows, srcTable.DataColumns[i].Count);
                }

                // create as many columns in destTable as srcRows and fill them with data
                Type columnType = dataColumnsToTransposeIndices.Count > 0 ? srcTable.DataColumns[dataColumnsToTransposeIndices[0]].GetType() : null;
                for (int i = 0; i < srcRows; ++i)
                {
                    string destColName = string.Format("{0}{1}", options.ColumnNamingPreString, i);
                    if (options.UseFirstDataColumnForColumnNaming)
                    {
                        destColName = string.Format("{0}{1}", options.ColumnNamingPreString, srcTable.DataColumns[0][i]);
                    }

                    var destCol = destTable.DataColumns.EnsureExistenceAtPositionStrictly(numberOfPriorDestDataColumns + i, destColName, false, columnType, ColumnKind.V, 0);
                    int k       = 0;
                    foreach (int j in dataColumnsToTransposeIndices)
                    {
                        destCol[k++] = srcTable.DataColumns[j][i];
                    }
                }

                // 3rd, copy the first data columns to property columns
                for (int i = 0; i < numberOfDataColumnsChangeToPropertyColumns; ++i)
                {
                    var destCol = destTable.PropertyColumns.EnsureExistenceAtPositionStrictly(i, srcTable.DataColumns.GetColumnName(i), srcTable.DataColumns[i].GetType(), srcTable.DataColumns.GetColumnKind(i), srcTable.DataColumns.GetColumnGroup(i));
                    var srcCol  = srcTable.DataColumns[i];
                    for (int j = numberOfPriorDestDataColumns, k = 0; k < srcCol.Count; ++j, ++k)
                    {
                        destCol[j] = srcCol[k];
                    }
                }

                // 4th, fill the rest of the property columns with the rest of the data columns
                for (int i = 0; i < numberOfDataColumnsChangeToPropertyColumns; ++i)
                {
                    for (int j = 0; j < numberOfPropertyColumnsChangeToDataColumns; ++j)
                    {
                        try
                        {
                            destTable.PropertyColumns[i][j + numberOfExtraPriorDestColumns] = srcTable.PropertyColumns[j][i];
                        }
                        catch { }
                    }
                }

                // and 5th, copy the remaining property columns to property columns
                for (int i = numberOfPropertyColumnsChangeToDataColumns, j = numberOfDataColumnsChangeToPropertyColumns; i < srcTable.PropertyColumns.ColumnCount; ++i, ++j)
                {
                    var destCol = destTable.PropertyColumns.EnsureExistenceAtPositionStrictly(j, srcTable.PropertyColumns.GetColumnName(i), false, srcTable.PropertyColumns[i].GetType(), srcTable.PropertyColumns.GetColumnKind(i), srcTable.DataColumns.GetColumnGroup(i));
                    destCol.Data = srcTable.PropertyColumns[i];
                }

                suspendToken.Resume();
            }
        }
示例#7
0
		/// <summary>
		/// Multiplies selected columns to form a matrix.
		/// </summary>
		/// <param name="mainDocument"></param>
		/// <param name="srctable"></param>
		/// <param name="selectedColumns"></param>
		/// <returns>Null if successful, else the description of the error.</returns>
		/// <remarks>The user must select an even number of columns. All columns of the first half of the selection
		/// must have the same number of rows, and all columns of the second half of selection must also have the same
		/// number of rows. The first half of selected columns form a matrix of dimensions(firstrowcount,halfselected), and the second half
		/// of selected columns form a matrix of dimension(halfselected, secondrowcount). The resulting matrix has dimensions (firstrowcount,secondrowcount) and is
		/// stored in a separate worksheet.</remarks>
		public static string MultiplyColumnsToMatrix(
			Altaxo.AltaxoDocument mainDocument,
			Altaxo.Data.DataTable srctable,
			IAscendingIntegerCollection selectedColumns
			)
		{
			// check that there are columns selected
			if (0 == selectedColumns.Count)
				return "You must select at least two columns to multiply!";
			// selected columns must contain an even number of columns
			if (0 != selectedColumns.Count % 2)
				return "You selected an odd number of columns. Please select an even number of columns to multiply!";
			// all selected columns must be numeric columns
			for (int i = 0; i < selectedColumns.Count; i++)
			{
				if (!(srctable[selectedColumns[i]] is Altaxo.Data.INumericColumn))
					return string.Format("The column[{0}] (name:{1}) is not a numeric column!", selectedColumns[i], srctable[selectedColumns[i]].Name);
			}

			int halfselect = selectedColumns.Count / 2;

			// check that all columns from the first half of selected colums contain the same
			// number of rows

			int rowsfirsthalf = int.MinValue;
			for (int i = 0; i < halfselect; i++)
			{
				int idx = selectedColumns[i];
				if (rowsfirsthalf < 0)
					rowsfirsthalf = srctable[idx].Count;
				else if (rowsfirsthalf != srctable[idx].Count)
					return "The first half of selected columns have not all the same length!";
			}

			int rowssecondhalf = int.MinValue;
			for (int i = halfselect; i < selectedColumns.Count; i++)
			{
				int idx = selectedColumns[i];
				if (rowssecondhalf < 0)
					rowssecondhalf = srctable[idx].Count;
				else if (rowssecondhalf != srctable[idx].Count)
					return "The second half of selected columns have not all the same length!";
			}

			// now create the matrices to multiply from the

			MatrixMath.REMatrix firstMat = new MatrixMath.REMatrix(rowsfirsthalf, halfselect);
			for (int i = 0; i < halfselect; i++)
			{
				Altaxo.Data.INumericColumn col = (Altaxo.Data.INumericColumn)srctable[selectedColumns[i]];
				for (int j = 0; j < rowsfirsthalf; j++)
					firstMat[j, i] = col[j];
			}

			MatrixMath.BEMatrix secondMat = new MatrixMath.BEMatrix(halfselect, rowssecondhalf);
			for (int i = 0; i < halfselect; i++)
			{
				Altaxo.Data.INumericColumn col = (Altaxo.Data.INumericColumn)srctable[selectedColumns[i + halfselect]];
				for (int j = 0; j < rowssecondhalf; j++)
					secondMat[i, j] = col[j];
			}

			// now multiply the two matrices
			MatrixMath.BEMatrix resultMat = new MatrixMath.BEMatrix(rowsfirsthalf, rowssecondhalf);
			MatrixMath.Multiply(firstMat, secondMat, resultMat);

			// and store the result in a new worksheet
			Altaxo.Data.DataTable table = new Altaxo.Data.DataTable("ResultMatrix of " + srctable.Name);
			using (var suspendToken = table.SuspendGetToken())
			{
				// first store the factors
				for (int i = 0; i < resultMat.Columns; i++)
				{
					Altaxo.Data.DoubleColumn col = new Altaxo.Data.DoubleColumn();
					for (int j = 0; j < resultMat.Rows; j++)
						col[j] = resultMat[j, i];

					table.DataColumns.Add(col, i.ToString());
				}
				suspendToken.Dispose();
			}

			mainDocument.DataTableCollection.Add(table);
			// create a new worksheet without any columns
			Current.ProjectService.CreateNewWorksheet(table);

			return null;
		}
示例#8
0
		/// <summary>
		/// Makes a PCA (a principal component analysis) of the table or the selected columns / rows and stores the results in a newly created table.
		/// </summary>
		/// <param name="mainDocument">The main document of the application.</param>
		/// <param name="srctable">The table where the data come from.</param>
		/// <param name="selectedColumns">The selected columns.</param>
		/// <param name="selectedRows">The selected rows.</param>
		/// <param name="bHorizontalOrientedSpectrum">True if a spectrum is a single row, False if a spectrum is a single column.</param>
		/// <param name="maxNumberOfFactors">The maximum number of factors to calculate.</param>
		/// <returns></returns>
		public static string PrincipalComponentAnalysis(
			Altaxo.AltaxoDocument mainDocument,
			Altaxo.Data.DataTable srctable,
			IAscendingIntegerCollection selectedColumns,
			IAscendingIntegerCollection selectedRows,
			bool bHorizontalOrientedSpectrum,
			int maxNumberOfFactors
			)
		{
			bool bUseSelectedColumns = (null != selectedColumns && 0 != selectedColumns.Count);
			int prenumcols = bUseSelectedColumns ? selectedColumns.Count : srctable.DataColumns.ColumnCount;

			// check for the number of numeric columns
			int numcols = 0;
			for (int i = 0; i < prenumcols; i++)
			{
				int idx = bUseSelectedColumns ? selectedColumns[i] : i;
				if (srctable[i] is Altaxo.Data.INumericColumn)
					numcols++;
			}

			// check the number of rows
			bool bUseSelectedRows = (null != selectedRows && 0 != selectedRows.Count);

			int numrows;
			if (bUseSelectedRows)
				numrows = selectedRows.Count;
			else
			{
				numrows = 0;
				for (int i = 0; i < numcols; i++)
				{
					int idx = bUseSelectedColumns ? selectedColumns[i] : i;
					numrows = Math.Max(numrows, srctable[idx].Count);
				}
			}

			// check that both dimensions are at least 2 - otherwise PCA is not possible
			if (numrows < 2)
				return "At least two rows are neccessary to do Principal Component Analysis!";
			if (numcols < 2)
				return "At least two numeric columns are neccessary to do Principal Component Analysis!";

			// Create a matrix of appropriate dimensions and fill it

			MatrixMath.BEMatrix matrixX;
			if (bHorizontalOrientedSpectrum)
			{
				matrixX = new MatrixMath.BEMatrix(numrows, numcols);
				int ccol = 0; // current column in the matrix
				for (int i = 0; i < prenumcols; i++)
				{
					int colidx = bUseSelectedColumns ? selectedColumns[i] : i;
					Altaxo.Data.INumericColumn col = srctable[colidx] as Altaxo.Data.INumericColumn;
					if (null != col)
					{
						for (int j = 0; j < numrows; j++)
						{
							int rowidx = bUseSelectedRows ? selectedRows[j] : j;
							matrixX[j, ccol] = col[rowidx];
						}
						++ccol;
					}
				}
			} // end if it was a horizontal oriented spectrum
			else // if it is a vertical oriented spectrum
			{
				matrixX = new MatrixMath.BEMatrix(numcols, numrows);
				int ccol = 0; // current column in the matrix
				for (int i = 0; i < prenumcols; i++)
				{
					int colidx = bUseSelectedColumns ? selectedColumns[i] : i;
					Altaxo.Data.INumericColumn col = srctable[colidx] as Altaxo.Data.INumericColumn;
					if (null != col)
					{
						for (int j = 0; j < numrows; j++)
						{
							int rowidx = bUseSelectedRows ? selectedRows[j] : j;
							matrixX[ccol, j] = col[rowidx];
						}
						++ccol;
					}
				}
			} // if it was a vertical oriented spectrum

			// now do PCA with the matrix
			MatrixMath.REMatrix factors = new MatrixMath.REMatrix(0, 0);
			MatrixMath.BEMatrix loads = new MatrixMath.BEMatrix(0, 0);
			MatrixMath.BEMatrix residualVariances = new MatrixMath.BEMatrix(0, 0);
			MatrixMath.HorizontalVector meanX = new MatrixMath.HorizontalVector(matrixX.Columns);
			// first, center the matrix
			MatrixMath.ColumnsToZeroMean(matrixX, meanX);
			MatrixMath.NIPALS_HO(matrixX, maxNumberOfFactors, 1E-9, factors, loads, residualVariances);

			// now we have to create a new table where to place the calculated factors and loads
			// we will do that in a vertical oriented manner, i.e. even if the loads are
			// here in horizontal vectors: in our table they are stored in (vertical) columns
			Altaxo.Data.DataTable table = new Altaxo.Data.DataTable("PCA of " + srctable.Name);

			// Fill the Table
			using (var suspendToken = table.SuspendGetToken())
			{
				// first of all store the meanscore
				{
					double meanScore = MatrixMath.LengthOf(meanX);
					MatrixMath.NormalizeRows(meanX);

					Altaxo.Data.DoubleColumn col = new Altaxo.Data.DoubleColumn();
					for (int i = 0; i < factors.Rows; i++)
						col[i] = meanScore;
					table.DataColumns.Add(col, "MeanFactor", Altaxo.Data.ColumnKind.V, 0);
				}

				// first store the factors
				for (int i = 0; i < factors.Columns; i++)
				{
					Altaxo.Data.DoubleColumn col = new Altaxo.Data.DoubleColumn();
					for (int j = 0; j < factors.Rows; j++)
						col[j] = factors[j, i];

					table.DataColumns.Add(col, "Factor" + i.ToString(), Altaxo.Data.ColumnKind.V, 1);
				}

				// now store the mean of the matrix
				{
					Altaxo.Data.DoubleColumn col = new Altaxo.Data.DoubleColumn();

					for (int j = 0; j < meanX.Columns; j++)
						col[j] = meanX[0, j];
					table.DataColumns.Add(col, "MeanLoad", Altaxo.Data.ColumnKind.V, 2);
				}

				// now store the loads - careful - they are horizontal in the matrix
				for (int i = 0; i < loads.Rows; i++)
				{
					Altaxo.Data.DoubleColumn col = new Altaxo.Data.DoubleColumn();

					for (int j = 0; j < loads.Columns; j++)
						col[j] = loads[i, j];

					table.DataColumns.Add(col, "Load" + i.ToString(), Altaxo.Data.ColumnKind.V, 3);
				}

				// now store the residual variances, they are vertical in the vector
				{
					Altaxo.Data.DoubleColumn col = new Altaxo.Data.DoubleColumn();

					for (int i = 0; i < residualVariances.Rows; i++)
						col[i] = residualVariances[i, 0];
					table.DataColumns.Add(col, "ResidualVariance", Altaxo.Data.ColumnKind.V, 4);
				}

				suspendToken.Dispose();
			}

			mainDocument.DataTableCollection.Add(table);
			// create a new worksheet without any columns
			Current.ProjectService.CreateNewWorksheet(table);

			return null;
		}