|
ResultsTable |
|
package ij.measure; import ij.*; import ij.plugin.filter.Analyzer; import ij.text.*; import java.awt.*; /** This is a table for storing measurement results as columns of numeric values. Call the static ResultsTable.getResultsTable() method to get a reference to the ResultsTable used by the <i>Analyze/Measure</i> command. @see ij.plugin.filter.Analyzer#getResultsTable */ public class ResultsTable { public static final int MAX_COLUMNS = 150; public static final int COLUMN_NOT_FOUND = -1; public static final int COLUMN_IN_USE = -2; public static final int TABLE_FULL = -3; public static final int AREA=0, MEAN=1, STD_DEV=2, MODE=3, MIN=4, MAX=5, X_CENTROID=6, Y_CENTROID=7, X_CENTER_OF_MASS=8, Y_CENTER_OF_MASS=9, PERIMETER=10, ROI_X=11, ROI_Y=12, ROI_WIDTH=13, ROI_HEIGHT=14, MAJOR=15, MINOR=16, ANGLE=17, CIRCULARITY=18, FERET=19, INTEGRATED_DENSITY=20, MEDIAN=21, SKEWNESS=22, KURTOSIS=23, AREA_FRACTION=24, SLICE=25; private String[] headings = new String[MAX_COLUMNS]; private String[] defaultHeadings = {"Area","Mean","StdDev","Mode","Min","Max", "X","Y","XM","YM","Perim.","BX","BY","Width","Height","Major","Minor","Angle", "Circ.", "Feret", "IntDen", "Median","Skew","Kurt", "%Area", "Slice"}; private int counter; private double[][] columns = new double[MAX_COLUMNS][]; private String[] rowLabels; private int maxRows = 100; // will be increased as needed private int lastColumn = -1; private StringBuffer sb; private int precision = 3; private String rowLabelHeading = ""; /** Constructs an empty ResultsTable with the counter=0 and no columns. */ public ResultsTable() { for(int i=0; i<defaultHeadings.length; i++) headings[i] = defaultHeadings[i]; } /** Returns the ResultsTable used by the Measure command. */ public static ResultsTable getResultsTable() { return Analyzer.getResultsTable(); } /** Increments the measurement counter by one. */ public synchronized void incrementCounter() { counter++; if (counter==maxRows) { if (rowLabels!=null) { String[] s = new String[maxRows*2]; System.arraycopy(rowLabels, 0, s, 0, maxRows); rowLabels = s; } for (int i=0; i<=lastColumn; i++) { if (columns[i]!=null) { double[] tmp = new double[maxRows*2]; System.arraycopy(columns[i], 0, tmp, 0, maxRows); columns[i] = tmp; } } maxRows *= 2; } } /** Returns the current value of the measurement counter. */ public int getCounter() { return counter; } /** Adds a value to the end of the given column. Counter must be >0.*/ public void addValue(int column, double value) { if ((column<0) || (column>=MAX_COLUMNS)) throw new IllegalArgumentException("Index out of range: "+column); if (counter==0) throw new IllegalArgumentException("Counter==0"); if (columns[column]==null) { columns[column] = new double[maxRows]; if (headings[column]==null) headings[column] = "---"; if (column>lastColumn) lastColumn = column; } columns[column][counter-1] = value; } /** Adds a value to the end of the given column. If the column does not exist, it is created. Counter must be >0. */ public void addValue(String column, double value) { int index = getColumnIndex(column); if (index==COLUMN_NOT_FOUND) { index = getFreeColumn(column); if (index==TABLE_FULL) throw new IllegalArgumentException("table is full"); } addValue(index, value); } /** Adds a label to the beginning of the current row. Counter must be >0. */ public void addLabel(String columnHeading, String label) { if (counter==0) throw new IllegalArgumentException("Counter==0"); if (rowLabels==null) rowLabels = new String[maxRows]; rowLabels[counter-1] = label; if (columnHeading!=null) rowLabelHeading = columnHeading; } /** Adds a label to the beginning of the specified row, or updates an existing lable, where 0<=row<counter. After labels are added or modified, call <code>show()</code> to update the window displaying the table. */ public void setLabel(String label, int row) { if (row<0||row>=counter) throw new IllegalArgumentException("row>=counter"); if (rowLabels==null) rowLabels = new String[maxRows]; if (rowLabelHeading.equals("")) rowLabelHeading = "Label"; rowLabels[row] = label; } /** Set the row label column to null. */ public void disableRowLabels() { rowLabels = null; } /** Returns a copy of the given column as a float array. Returns null if the column is empty. */ public float[] getColumn(int column) { if ((column<0) || (column>=MAX_COLUMNS)) throw new IllegalArgumentException("Index out of range: "+column); if (columns[column]==null) return null; else { float[] data = new float[counter]; for (int i=0; i<counter; i++) data[i] = (float)columns[column][i]; return data; } } /** Returns true if the specified column exists and is not empty. */ public boolean columnExists(int column) { if ((column<0) || (column>=MAX_COLUMNS)) return false; else return columns[column]!=null; } /** Returns the index of the first column with the given heading. heading. If not found, returns COLUMN_NOT_FOUND. */ public int getColumnIndex(String heading) { for(int i=0; i<headings.length; i++) { if (headings[i]==null) return COLUMN_NOT_FOUND; else if (headings[i].equals(heading)) return i; } return COLUMN_NOT_FOUND; } /** Sets the heading of the the first available column and returns that column's index. Returns COLUMN_IN_USE if this is a duplicate heading. Returns TABLE_FULL if there are no free columns. */ public int getFreeColumn(String heading) { for(int i=0; i<headings.length; i++) { if (headings[i]==null) { columns[i] = new double[maxRows]; headings[i] = heading; if (i>lastColumn) lastColumn = i; return i; } if (headings[i].equals(heading)) return COLUMN_IN_USE; } return TABLE_FULL; } /** Returns the value of the given column and row, where column must be greater than or equal zero and less than MAX_COLUMNS and row must be greater than or equal zero and less than counter. */ public double getValueAsDouble(int column, int row) { if (columns[column]==null) throw new IllegalArgumentException("Column not defined: "+column); if (column>=MAX_COLUMNS || row>=counter) throw new IllegalArgumentException("Index out of range: "+column+","+row); return columns[column][row]; } /** Obsolete, replaced by getValueAsDouble. */ public float getValue(int column, int row) { return (float)getValueAsDouble(column, row); } /** Returns the value of the specified column and row, where column is the column heading and row is a number greater than or equal zero and less than value returned by getCounter(). Throws an IllegalArgumentException if this ResultsTable does not have a column with the specified heading. */ public double getValue(String column, int row) { if (row<0 || row>=getCounter()) throw new IllegalArgumentException("Row out of range"); int col = getColumnIndex(column); if (col==COLUMN_NOT_FOUND) throw new IllegalArgumentException("\""+column+"\" column not found"); //IJ.log("col: "+col+" "+(col==COLUMN_NOT_FOUND?"not found":""+columns[col])); return getValueAsDouble(col,row); } /** Returns the label of the specified row. Returns null if the row does not have a label. */ public String getLabel(int row) { if (row<0 || row>=getCounter()) throw new IllegalArgumentException("Row out of range"); String label = null; if (rowLabels!=null && rowLabels[row]!=null) label = rowLabels[row]; return label; } /** Sets the value of the given column and row, where where 0<=row<counter. If the specified column does not exist, it is created. When adding columns, <code>show()</code> must be called to update the window that displays the table.*/ public void setValue(String column, int row, double value) { int col = getColumnIndex(column); if (col==COLUMN_NOT_FOUND) { col = getFreeColumn(column); if (col==TABLE_FULL) throw new IllegalArgumentException("Too many columns (>"+(MAX_COLUMNS-defaultHeadings.length)+")"); } setValue(col, row, value); } /** Sets the value of the given column and row, where where 0<=column<MAX_COLUMNS and 0<=row<counter. */ public void setValue(int column, int row, double value) { if ((column<0) || (column>=MAX_COLUMNS)) throw new IllegalArgumentException("Column out of range: "+column); if (row>=counter) throw new IllegalArgumentException("row>=counter"); if (columns[column]==null) { columns[column] = new double[maxRows]; if (column>lastColumn) lastColumn = column; } columns[column][row] = value; } /** Returns a tab-delimited string containing the column headings. */ public String getColumnHeadings() { StringBuffer sb = new StringBuffer(200); sb.append(" \t"); if (rowLabels!=null) sb.append(rowLabelHeading + "\t"); String heading; for (int i=0; i<=lastColumn; i++) { if (columns[i]!=null) { heading = headings[i]; if (heading==null) heading ="---"; sb.append(heading + "\t"); } } return new String(sb); } /** Returns the heading of the specified column or null if the column is empty. */ public String getColumnHeading(int column) { if ((column<0) || (column>=MAX_COLUMNS)) throw new IllegalArgumentException("Index out of range: "+column); return headings[column]; } /** Returns a tab-delimited string representing the given row, where 0<=row<=counter-1. */ public String getRowAsString(int row) { if ((row<0) || (row>=counter)) throw new IllegalArgumentException("Row out of range: "+row); if (sb==null) sb = new StringBuffer(200); else sb.setLength(0); sb.append(Integer.toString(row+1)); sb.append("\t"); if (rowLabels!=null) { if (rowLabels[row]!=null) sb.append(rowLabels[row]); sb.append("\t"); } for (int i=0; i<=lastColumn; i++) { if (columns[i]!=null) sb.append(n(columns[i][row])); } return new String(sb); } /** Changes the heading of the given column. */ public void setHeading(int column, String heading) { if ((column<0) || (column>=headings.length)) throw new IllegalArgumentException("Column out of range: "+column); headings[column] = heading; } /** Sets the number of digits to the right of decimal point. */ public void setPrecision(int precision) { this.precision = precision; } String n(double n) { String s; if (Math.round(n)==n) s = IJ.d2s(n,0); else s = IJ.d2s(n,precision); return s+"\t"; } /** Deletes the specified row. */ public synchronized void deleteRow(int row) { if (counter==0 || row>counter-1) return; if (counter==1) {reset(); return;} if (rowLabels!=null) { for (int i=row; i<counter-1; i++) rowLabels[i] = rowLabels[i+1]; } for (int i=0; i<=lastColumn; i++) { if (columns[i]!=null) { for (int j=row; j<counter-1; j++) columns[i][j] = columns[i][j+1]; } } counter--; } /** Clears all the columns and sets the counter to zero. */ public synchronized void reset() { counter = 0; maxRows = 100; for (int i=0; i<=lastColumn; i++) { columns[i] = null; if (i<defaultHeadings.length) headings[i] = defaultHeadings[i]; else headings[i] = null; } lastColumn = -1; rowLabels = null; } /** Displays the contents of this ResultsTable in a window with the specified title. Opens a new window if there is no open text window with this title. */ public void show(String windowTitle) { String tableHeadings = getColumnHeadings(); TextPanel tp; if (windowTitle.equals("Results")) { tp = IJ.getTextPanel(); if (tp==null) return; IJ.setColumnHeadings(tableHeadings); } else { Frame frame = WindowManager.getFrame(windowTitle); TextWindow win; if (frame!=null && frame instanceof TextWindow) win = (TextWindow)frame; else win = new TextWindow(windowTitle, "", 300, 200); tp = win.getTextPanel(); tp.setColumnHeadings(tableHeadings); } int n = getCounter(); if (n>0) { StringBuffer sb = new StringBuffer(n*tableHeadings.length()); for (int i=0; i<n; i++) sb.append(getRowAsString(i)+"\n"); tp.append(new String(sb)); } } public String toString() { return ("ctr="+counter+", hdr="+getColumnHeadings()); } }
|
ResultsTable |
|