All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ij.measure.ResultsTable Maven / Gradle / Ivy

Go to download

ImageJ is an open source Java image processing program inspired by NIH Image for the Macintosh.

There is a newer version: 1.54p
Show newest version
package ij.measure;
import ij.*;
import ij.plugin.filter.Analyzer;
import ij.text.*;
import ij.process.*;
import ij.gui.Roi;
import ij.util.Tools;
import ij.io.SaveDialog;
import java.awt.*;
import java.text.*;
import java.util.*;
import java.io.*;


/** This is a table for storing measurement results and strings as columns of values. 
	Call the static ResultsTable.getResultsTable() method to get a reference to the 
	ResultsTable used by the Analyze/Measure command. 
	@see ij.plugin.filter.Analyzer#getResultsTable
*/
public class ResultsTable implements Cloneable {

	/** Obsolete; use getLastColumn(). */
	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; // no longer used
	
	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, RAW_INTEGRATED_DENSITY=25, CHANNEL=26, SLICE=27, FRAME=28, 
		FERET_X=29, FERET_Y=30, FERET_ANGLE=31, MIN_FERET=32, ASPECT_RATIO=33,
		ROUNDNESS=34, SOLIDITY=35, LAST_HEADING=35;
	private static final 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", "RawIntDen", "Ch", "Slice", "Frame", 
		 "FeretX", "FeretY", "FeretAngle", "MinFeret", "AR", "Round", "Solidity"};

	private int maxRows = 100; // will be increased as needed
	private int maxColumns = MAX_COLUMNS; // will be increased as needed
	private String[] headings = new String[maxColumns];
	private boolean[] keep = new boolean[maxColumns];
	private int counter;
	private double[][] columns = new double[maxColumns][];
	private String[] rowLabels;
	private int lastColumn = -1;
	private	StringBuilder sb;
	private int precision = 3;
	private String rowLabelHeading = "";
	private char delimiter = '\t';
	private boolean headingSet; 
	private boolean showRowNumbers = true;
	private boolean autoFormat = true;
	private Hashtable stringColumns;


	/** Constructs an empty ResultsTable with the counter=0, no columns
		and the precision set to 3 or the "Decimal places" value in
		Analyze/Set Measurements if that value is higher than 3. */
	public ResultsTable() {
		int p = Analyzer.getPrecision();
		if (p>precision)
			setPrecision(p);
	}
	
	/** Returns the ResultsTable used by the Measure command. This
		table must be displayed in the "Results" window. */
	public static ResultsTable getResultsTable() {
		return Analyzer.getResultsTable();
	}
		
	/** Returns the "Results" TextWindow. */
	public static TextWindow getResultsWindow() {
		Frame f = WindowManager.getFrame("Results");
		if (f==null || !(f instanceof TextWindow))
			return null;
		else
			return (TextWindow)f;
	}

	/** 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;
		}
	}
	
	/** Obsolete; the addValue() method automatically adds columns as needed.
	* @see #addValue(String, double)
	*/
	public synchronized void addColumns() {
		String[] tmp1 = new String[maxColumns*2];
		System.arraycopy(headings, 0, tmp1, 0, maxColumns);
		headings = tmp1;
		double[][] tmp2 = new double[maxColumns*2][];
		for (int i=0; i0.*/
	public void addValue(int column, double value) {
		if (column>=maxColumns)
			addColumns();
		if (column<0 || column>=maxColumns)
			throw new IllegalArgumentException("Column out of range");
		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.
		There is an example at:
http://imagej.nih.gov/ij/plugins/sine-cosine.html */ public void addValue(String column, double value) { if (column==null) throw new IllegalArgumentException("Column is null"); int index = getColumnIndex(column); if (index==COLUMN_NOT_FOUND) index = getFreeColumn(column); addValue(index, value); keep[index] = true; } /** Adds a string 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, String value) { if (column==null) throw new IllegalArgumentException("Column is null"); int index = getColumnIndex(column); if (index==COLUMN_NOT_FOUND) index = getFreeColumn(column); addValue(index, Double.NaN); setValue(column, getCounter()-1, value); keep[index] = true; } /** Adds a label to the beginning of the current row. Counter must be >0. */ public void addLabel(String label) { if (rowLabelHeading.equals("")) rowLabelHeading = "Label"; addLabel(rowLabelHeading, label); } /** 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<=rowshow()
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 if the column label is "Label". */ public void disableRowLabels() { if (rowLabelHeading.equals("Label")) rowLabels = null; } /** Returns a copy of the given column as a float array, or null if the column is empty. */ public float[] getColumn(int column) { if ((column<0) || (column>=maxColumns)) 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=maxColumns)) throw new IllegalArgumentException("Index out of range: "+column); if (columns[column]==null) return null; else { double[] data = new double[counter]; for (int i=0; i=maxColumns)) 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; ilastColumn) lastColumn = i; return i; } if (headings[i].equals(heading)) return COLUMN_IN_USE; } addColumns(); lastColumn++; columns[lastColumn] = new double[maxRows]; headings[lastColumn] = heading; return lastColumn; } /** Returns the value of the given column and row, where column must be less than or equal the value returned by getLastColumn() and row must be greater than or equal zero and less than the value returned by getCounter(). */ public double getValueAsDouble(int column, int row) { if (column>=maxColumns || row>=counter) throw new IllegalArgumentException("Index out of range: "+column+","+row); if (columns[column]==null) throw new IllegalArgumentException("Column not defined: "+column); return columns[column][row]; } /** * @deprecated * 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 string value of the given column and row, where row must be greater than or equal zero and less than the value returned by getCounter(). */ public String getStringValue(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"); return getStringValue(col, row); } /** Returns the string value of the given column and row, where column must be less than or equal the value returned by getLastColumn() and row must be greater than or equal zero and less than the value returned by getCounter(). */ public String getStringValue(int column, int row) { if (column>=maxColumns || row>=counter) throw new IllegalArgumentException("Index out of range: "+column+","+row); if (columns[column]==null) throw new IllegalArgumentException("Column not defined: "+column); return getValueAsString(column, 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, show() must be called to update the window that displays the table.*/ public void setValue(String column, int row, double value) { if (column==null) throw new IllegalArgumentException("Column is null"); int col = getColumnIndex(column); if (col==COLUMN_NOT_FOUND) { col = getFreeColumn(column); } setValue(col, row, value); } /** Sets the value of the given column and row, where where 0<=column<=(lastRow+1 and 0<=row<=counter. */ public void setValue(int column, int row, double value) { if (column>=maxColumns) addColumns(); if (column<0 || column>=maxColumns) throw new IllegalArgumentException("Column out of range"); if (row>=counter) { if (row==counter) incrementCounter(); else throw new IllegalArgumentException("row>counter"); } if (columns[column]==null) { columns[column] = new double[maxRows]; if (column>lastColumn) lastColumn = column; } columns[column][row] = value; } /** Sets the string 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, show() must be called to update the window that displays the table.*/ public void setValue(String column, int row, String value) { if (column==null) throw new IllegalArgumentException("Column is null"); int col = getColumnIndex(column); if (col==COLUMN_NOT_FOUND) col = getFreeColumn(column); setValue(col, row, value); } /** Sets the string value of the given column and row, where where 0<=column<=(lastRow+1 and 0<=row<=counter. */ public void setValue(int column, int row, String value) { setValue(column, row, Double.NaN); if (stringColumns==null) stringColumns = new Hashtable(); ArrayList stringColumn = (ArrayList)stringColumns.get(new Integer(column)); if (stringColumn==null) { stringColumn = new ArrayList(); stringColumns.put(new Integer(column), stringColumn); } int size = stringColumn.size(); if (row>=size) { for (int i=size; i=maxColumns)) throw new IllegalArgumentException("Index out of range: "+column); return headings[column]; } /** Returns a tab or comma 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 StringBuilder(200); else sb.setLength(0); if (showRowNumbers) { sb.append(Integer.toString(row+1)); sb.append(delimiter); } if (rowLabels!=null) { if (rowLabels[row]!=null) { String label = rowLabels[row]; if (delimiter==',') label = label.replaceAll(",", ";"); sb.append(label); } sb.append(delimiter); } for (int i=0; i<=lastColumn; i++) { if (columns[i]!=null) { sb.append(getValueAsString(i,row)); if (i!=lastColumn) sb.append(delimiter); } } return new String(sb); } private String getValueAsString(int column, int row) { double value = columns[column][row]; //IJ.log("getValueAsString1: col="+column+ ", row= "+row+", value= "+value+", size="+stringColumns.size()); if (Double.isNaN(value) && stringColumns!=null) { String string = "NaN"; ArrayList stringColumn = (ArrayList)stringColumns.get(new Integer(column)); if (stringColumn==null) return string; //IJ.log("getValueAsString2: "+column+ +row+" "+stringColumn.size()); if (row>=0 && row=headings.length)) throw new IllegalArgumentException("Column out of range: "+column); headings[column] = heading; if (columns[column]==null) columns[column] = new double[maxRows]; if (column>lastColumn) lastColumn = column; headingSet = true; } /** Sets the headings used by the Measure command ("Area", "Mean", etc.). */ public void setDefaultHeadings() { for(int i=0; i=0) s = d2s(n, 0); else s = d2s(n, precision); return s; } private static DecimalFormat[] df; private static DecimalFormat[] sf; private static DecimalFormatSymbols dfs; /** This is a version of IJ.d2s() that uses scientific notation for small numbes that would otherwise display as zero. */ public static String d2s(double n, int decimalPlaces) { if (Double.isNaN(n)||Double.isInfinite(n)) return ""+n; if (n==Float.MAX_VALUE) // divide by 0 in FloatProcessor return "3.4e38"; double np = n; if (n<0.0) np = -n; if (df==null) { dfs = new DecimalFormatSymbols(Locale.US); df = new DecimalFormat[10]; df[0] = new DecimalFormat("0", dfs); df[1] = new DecimalFormat("0.0", dfs); df[2] = new DecimalFormat("0.00", dfs); df[3] = new DecimalFormat("0.000", dfs); df[4] = new DecimalFormat("0.0000", dfs); df[5] = new DecimalFormat("0.00000", dfs); df[6] = new DecimalFormat("0.000000", dfs); df[7] = new DecimalFormat("0.0000000", dfs); df[8] = new DecimalFormat("0.00000000", dfs); df[9] = new DecimalFormat("0.000000000", dfs); } if ((np<0.001 && np!=0.0 && np<1.0/Math.pow(10,decimalPlaces)) || np>999999999999d || decimalPlaces<0) { if (decimalPlaces<0) { decimalPlaces = -decimalPlaces; if (decimalPlaces>9) decimalPlaces=9; } else decimalPlaces = 3; if (sf==null) { sf = new DecimalFormat[10]; sf[1] = new DecimalFormat("0.0E0",dfs); sf[2] = new DecimalFormat("0.00E0",dfs); sf[3] = new DecimalFormat("0.000E0",dfs); sf[4] = new DecimalFormat("0.0000E0",dfs); sf[5] = new DecimalFormat("0.00000E0",dfs); sf[6] = new DecimalFormat("0.000000E0",dfs); sf[7] = new DecimalFormat("0.0000000E0",dfs); sf[8] = new DecimalFormat("0.00000000E0",dfs); sf[9] = new DecimalFormat("0.000000000E0",dfs); } return sf[decimalPlaces].format(n); // use scientific notation } if (decimalPlaces<0) decimalPlaces = 0; if (decimalPlaces>9) decimalPlaces = 9; return df[decimalPlaces].format(n); } /** Deletes the specified row. */ public synchronized void deleteRow(int row) { if (counter==0 || row<0 || row>counter-1) return; if (rowLabels!=null) { rowLabels[row] = null; for (int i=row; i0) Analyzer.setUnsavedMeasurements(true); } else { Frame frame = WindowManager.getFrame(windowTitle); TextWindow win; if (frame!=null && frame instanceof TextWindow) { win = (TextWindow)frame; win.toFront(); } else { int width = getLastColumn()<=1?250:400; win = new TextWindow(windowTitle, "", width, 300); cloneNeeded = true; } tp = win.getTextPanel(); tp.setColumnHeadings(tableHeadings); newWindow = tp.getLineCount()==0; autoFormat = false; } tp.setResultsTable(cloneNeeded?(ResultsTable)this.clone():this); int n = getCounter(); if (n>0) { if (tp.getLineCount()>0) tp.clear(); for (int i=0; i=getMaxColumns()) { addColumns(); //IJ.log("addColumns: "+getMaxColumns()); } if (last=rt2.getMaxColumns()) last = rt2.getMaxColumns() - 1; } for (int i=0; i<=last; i++) { //IJ.log(i+" "+rt2.getColumn(i)+" "+columns[i]+" "+rt2.getColumnHeading(i)+" "+getColumnHeading(i)); if (rt2.getColumn(i)!=null && columns[i]==null) { columns[i] = new double[maxRows]; headings[i] = rt2.getColumnHeading(i); if (i>lastColumn) lastColumn = i; } else if (rt2.getColumn(i)==null && columns[i]!=null && !keep[i]) columns[i] = null; } if (rt2.getRowLabels()==null) rowLabels = null; else if (rt2.getRowLabels()!=null && rowLabels==null) { rowLabels = new String[maxRows]; rowLabelHeading = "Label"; } if (getCounter()>0) show("Results"); } int getMaxColumns() { return maxColumns; } String[] getRowLabels() { return rowLabels; } /** Opens a tab or comma delimited text file and returns it * as a ResultsTable, without requiring a try/catch statement. * Displays a file open dialog if 'path' is empty or null. */ public static ResultsTable open2(String path) { ResultsTable rt = null; try { rt = open(path); } catch (IOException e) { IJ.error("Open Results", e.getMessage()); rt = null; } return rt; } /** Opens a tab or comma delimited text file and returns it as a * ResultsTable. Displays a file open dialog if 'path' is empty or null. * @see #open2(String) */ public static ResultsTable open(String path) throws IOException { final String lineSeparator = "\n"; final String cellSeparator = ",\t"; String text =IJ.openAsString(path); if (text==null) return null; if (text.startsWith("Error:")) throw new IOException("Error opening "+path); String[] lines = Tools.split(text, lineSeparator); if (lines.length==0) throw new IOException("Table is empty or invalid"); String[] headings = Tools.split(lines[0], cellSeparator); if (headings.length==1) throw new IOException("This is not a tab or comma delimited text file."); int numbersInHeadings = 0; for (int i=0; i=0 && index
Related Artifacts
Related Groups
-->


© 2015 - 2025 Weber Informatics LLC | Privacy Policy