package ij.gui;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.awt.datatransfer.*;
import java.util.*;
import ij.*;
import ij.process.*;
import ij.util.*;
import ij.text.TextWindow;
import ij.plugin.filter.Analyzer;
import ij.plugin.filter.PlugInFilterRunner;
import ij.measure.*;
import ij.io.SaveDialog;
public class PlotWindow extends ImageWindow implements ActionListener, ItemListener,
ClipboardOwner, ImageListener, RoiListener, Runnable {
private static final int WIDTH = 600;
private static final int HEIGHT = 340;
private static final int FONT_SIZE = 14;
private static final String PREFS_WIDTH = "pp.width";
private static final String PREFS_HEIGHT = "pp.height";
private static final String PREFS_FONT_SIZE = "pp.fontsize";
public static final int CIRCLE = Plot.CIRCLE;
public static final int X = Plot.X;
public static final int BOX = Plot.BOX;
public static final int TRIANGLE = Plot.TRIANGLE;
public static final int CROSS = Plot.CROSS;
public static final int LINE = Plot.LINE;
public static boolean saveXValues = true;
public static boolean autoClose;
public static boolean listValues;
public static boolean interpolate = true;
private static int defaultFontSize = Prefs.getInt(PREFS_FONT_SIZE, FONT_SIZE);
public static int plotWidth = WIDTH;
public static int plotHeight = HEIGHT;
public static int fontSize = defaultFontSize;
public static boolean noGridLines;
public static boolean noTicks;
private static final String OPTIONS = "pp.options";
private static final int SAVE_X_VALUES = 1;
private static final int AUTO_CLOSE = 2;
private static final int LIST_VALUES = 4;
private static final int INTERPOLATE = 8;
private static final int NO_GRID_LINES = 16;
private static final int NO_TICKS = 32;
private static String moreButtonLabel = "More "+'\u00bb';
private static String dataButtonLabel = "Data "+'\u00bb';
boolean wasActivated;
private Button list, data, more, live;
private PopupMenu dataPopupMenu, morePopupMenu;
private static final int NUM_MENU_ITEMS = 20; private MenuItem[] menuItems = new MenuItem[NUM_MENU_ITEMS];
private Label statusLabel;
private String userStatusText;
private static String defaultDirectory = null;
private static int options;
private int defaultDigits = -1;
private int markSize = 5;
private static Plot staticPlot;
private Plot plot;
private PlotMaker plotMaker;
private ImagePlus srcImp; private Thread bgThread; private boolean doUpdate;
private Roi[] rangeArrowRois; private boolean rangeArrowsVisible;
private int activeRangeArrow = -1;
private static Color inactiveRangeArrowColor = Color.GRAY;
private static Color inactiveRangeRectColor = new Color(0x20404040, true); private static Color activeRangeArrowColor = Color.RED;
private static Color activeRangeRectColor = new Color(0x18ff0000, true);
static {
options = Prefs.getInt(OPTIONS, SAVE_X_VALUES);
autoClose = (options&AUTO_CLOSE)!=0;
plotWidth = Prefs.getInt(PREFS_WIDTH, WIDTH);
plotHeight = Prefs.getInt(PREFS_HEIGHT, HEIGHT);
Dimension screen = IJ.getScreenSize();
if (plotWidth>screen.width && plotHeight>screen.height) {
plotWidth = WIDTH;
plotHeight = HEIGHT;
}
}
public PlotWindow(String title, String xLabel, String yLabel, float[] xValues, float[] yValues) {
super(createImage(title, xLabel, yLabel, xValues, yValues));
plot = staticPlot;
((PlotCanvas)getCanvas()).setPlot(plot);
}
public PlotWindow(String title, String xLabel, String yLabel, double[] xValues, double[] yValues) {
this(title, xLabel, yLabel, Tools.toFloat(xValues), Tools.toFloat(yValues));
}
public PlotWindow(ImagePlus imp, Plot plot) {
super(imp);
((PlotCanvas)getCanvas()).setPlot(plot);
this.plot = plot;
draw();
}
PlotWindow(Plot plot) {
super(plot.getImagePlus());
((PlotCanvas)getCanvas()).setPlot(plot);
this.plot = plot;
draw();
}
static ImagePlus createImage(String title, String xLabel, String yLabel, float[] xValues, float[] yValues) {
staticPlot = new Plot(title, xLabel, yLabel, xValues, yValues);
return new ImagePlus(title, staticPlot.getBlankProcessor());
}
public void setLimits(double xMin, double xMax, double yMin, double yMax) {
plot.setLimits(xMin, xMax, yMin, yMax);
}
public void addPoints(float[] x, float[] y, int shape) {
plot.addPoints(x, y, shape);
}
public void addPoints(double[] x, double[] y, int shape) {
addPoints(Tools.toFloat(x), Tools.toFloat(y), shape);
}
public void addErrorBars(float[] errorBars) {
plot.addErrorBars(errorBars);
}
public void addLabel(double x, double y, String label) {
plot.addLabel(x, y, label);
}
public void setColor(Color c) {
plot.setColor(c);
}
public void setLineWidth(int lineWidth) {
plot.setLineWidth(lineWidth);
}
public void changeFont(Font font) {
plot.changeFont(font);
}
public void draw() {
Panel bottomPanel = new Panel();
int hgap = IJ.isMacOSX()?1:5;
list = new Button(" List ");
list.addActionListener(this);
bottomPanel.add(list);
bottomPanel.setLayout(new FlowLayout(FlowLayout.RIGHT,hgap,0));
data = new Button(dataButtonLabel);
data.addActionListener(this);
bottomPanel.add(data);
more = new Button(moreButtonLabel);
more.addActionListener(this);
bottomPanel.add(more);
if (plot!=null && plot.getPlotMaker()!=null) {
live = new Button("Live");
live.addActionListener(this);
bottomPanel.add(live);
}
statusLabel = new Label();
statusLabel.setFont(new Font("Monospaced", Font.PLAIN, 12));
statusLabel.setBackground(new Color(220, 220, 220));
bottomPanel.add(statusLabel);
add(bottomPanel);
data.add(getDataPopupMenu());
more.add(getMorePopupMenu());
plot.draw();
LayoutManager lm = getLayout();
if (lm instanceof ImageLayout)
((ImageLayout)lm).ignoreNonImageWidths(true); GUI.scale(bottomPanel);
maximizeCoordinatesLabelWidth();
pack();
ImageProcessor ip = plot.getProcessor();
boolean ipIsColor = ip instanceof ColorProcessor;
boolean impIsColor = imp.getProcessor() instanceof ColorProcessor;
if (ipIsColor != impIsColor)
imp.setProcessor(null, ip);
else
imp.updateAndDraw();
if (listValues)
showList(false);
else
ic.requestFocus(); if (Prefs.autoLivePlots && bgThread==null)
enableLivePlot();
}
public void setPlot(Plot plot) {
this.plot = plot;
((PlotCanvas)getCanvas()).setPlot(plot);
}
public void dispose() {
if (plot!=null)
plot.dispose();
disableLivePlot();
plot = null;
plotMaker = null;
srcImp = null;
super.dispose();
}
public void windowActivated(WindowEvent e) {
super.windowActivated(e);
if (!wasActivated) {
new Thread(new Runnable() {
public void run() {
IJ.wait(50); wasActivated = true;
}
}).start();
}
}
void canvasResized() {
if (plot == null) return;
maximizeCoordinatesLabelWidth();
}
void maximizeCoordinatesLabelWidth() {
Insets insets = getInsets(); Component parent = statusLabel.getParent(); if (!parent.isValid()) parent.validate();
int cWidth = getWidth() - 2*HGAP - statusLabel.getX() - insets.left - insets.right;
int cHeight = statusLabel.getPreferredSize().height;
statusLabel.setPreferredSize(new Dimension(cWidth, cHeight));
parent.setSize(getWidth() - 2*HGAP, parent.getHeight());
}
public void showStatus(String text) {
userStatusText = text;
if (statusLabel != null)
statusLabel.setText(text == null ? "" : text);
}
private static int SAVE=0, COPY=1, COPY_ALL=2, LIST_SIMPLE=3, ADD_FROM_TABLE=4, ADD_FROM_PLOT=5, ADD_FIT=6, SET_RANGE=7, PREV_RANGE=8, RESET_RANGE=9, FIT_RANGE=10, ZOOM_SELECTION=11, AXIS_OPTIONS=12, LEGEND=13, STYLE=14, TEMPLATE=15, RESET_PLOT=16,
FREEZE=17, HI_RESOLUTION=18, PROFILE_PLOT_OPTIONS=19;
private static int[] DISABLED_WHEN_FROZEN = new int[]{ADD_FROM_TABLE, ADD_FROM_PLOT, ADD_FIT,
SET_RANGE, PREV_RANGE, RESET_RANGE, FIT_RANGE, ZOOM_SELECTION, AXIS_OPTIONS, LEGEND, STYLE, RESET_PLOT};
PopupMenu getDataPopupMenu() {
dataPopupMenu = new PopupMenu();
GUI.scalePopupMenu(dataPopupMenu);
menuItems[SAVE] = addPopupItem(dataPopupMenu, "Save Data...");
menuItems[COPY] = addPopupItem(dataPopupMenu, "Copy 1st Data Set");
menuItems[COPY_ALL] = addPopupItem(dataPopupMenu, "Copy All Data");
menuItems[LIST_SIMPLE] = addPopupItem(dataPopupMenu, "List (Simple Headings)");
dataPopupMenu.addSeparator();
menuItems[ADD_FROM_TABLE] = addPopupItem(dataPopupMenu, "Add from Table...");
menuItems[ADD_FROM_PLOT] = addPopupItem(dataPopupMenu, "Add from Plot...");
menuItems[ADD_FIT] = addPopupItem(dataPopupMenu, "Add Fit...");
return dataPopupMenu;
}
PopupMenu getMorePopupMenu() {
morePopupMenu = new PopupMenu();
GUI.scalePopupMenu(morePopupMenu);
menuItems[SET_RANGE] = addPopupItem(morePopupMenu, "Set Range...");
menuItems[PREV_RANGE] = addPopupItem(morePopupMenu, "Previous Range");
menuItems[RESET_RANGE] = addPopupItem(morePopupMenu, "Reset Range");
menuItems[FIT_RANGE] = addPopupItem(morePopupMenu, "Set Range to Fit All");
menuItems[ZOOM_SELECTION] = addPopupItem(morePopupMenu, "Zoom to Selection");
morePopupMenu.addSeparator();
menuItems[AXIS_OPTIONS] = addPopupItem(morePopupMenu, "Axis Options...");
menuItems[LEGEND] = addPopupItem(morePopupMenu, "Legend...");
menuItems[STYLE] = addPopupItem(morePopupMenu, "Contents Style...");
menuItems[TEMPLATE] = addPopupItem(morePopupMenu, "Use Template...");
menuItems[RESET_PLOT] = addPopupItem(morePopupMenu, "Reset Format");
menuItems[FREEZE] = addPopupItem(morePopupMenu, "Freeze Plot", true);
menuItems[HI_RESOLUTION] = addPopupItem(morePopupMenu, "High-Resolution Plot...");
morePopupMenu.addSeparator();
menuItems[PROFILE_PLOT_OPTIONS] = addPopupItem(morePopupMenu, "Plot Defaults...");
return morePopupMenu;
}
MenuItem addPopupItem(PopupMenu popupMenu, String s) {
return addPopupItem(popupMenu, s, false);
}
MenuItem addPopupItem(PopupMenu popupMenu, String s, boolean isCheckboxItem) {
MenuItem mi = null;
if (isCheckboxItem) {
mi = new CheckboxMenuItem(s);
((CheckboxMenuItem)mi).addItemListener(this);
} else {
mi = new MenuItem(s);
mi.addActionListener(this);
}
popupMenu.add(mi);
return mi;
}
public void actionPerformed(ActionEvent e) {
try {
Object b = e.getSource();
if (b==live)
toggleLiveProfiling();
else if (b==list)
showList(true);
else if (b==data) {
enableDisableMenuItems();
dataPopupMenu.show((Component)b, 1, 1);
} else if (b==more) {
enableDisableMenuItems();
morePopupMenu.show((Component)b, 1, 1);
} else if (b==menuItems[SAVE])
saveAsText();
else if (b==menuItems[COPY])
copyToClipboard(false);
else if (b==menuItems[COPY_ALL])
copyToClipboard(true);
else if (b==menuItems[LIST_SIMPLE])
showList(false);
else if (b==menuItems[ADD_FROM_TABLE])
new PlotContentsDialog(plot, PlotContentsDialog.ADD_FROM_TABLE).showDialog(this);
else if (b==menuItems[ADD_FROM_PLOT])
new PlotContentsDialog(plot, PlotContentsDialog.ADD_FROM_PLOT).showDialog(this);
else if (b==menuItems[ADD_FIT])
new PlotContentsDialog(plot, PlotContentsDialog.ADD_FIT).showDialog(this);
else if (b==menuItems[ZOOM_SELECTION]) {
if (imp!=null && imp.getRoi()!=null && imp.getRoi().isArea())
plot.zoomToRect(imp.getRoi().getBounds());
} else if (b==menuItems[SET_RANGE])
new PlotDialog(plot, PlotDialog.SET_RANGE).showDialog(this);
else if (b==menuItems[PREV_RANGE])
plot.setPreviousMinMax();
else if (b==menuItems[RESET_RANGE])
plot.setLimitsToDefaults(true);
else if (b==menuItems[FIT_RANGE])
plot.setLimitsToFit(true);
else if (b==menuItems[AXIS_OPTIONS])
new PlotDialog(plot, PlotDialog.AXIS_OPTIONS).showDialog(this);
else if (b==menuItems[LEGEND])
new PlotDialog(plot, PlotDialog.LEGEND).showDialog(this);
else if (b==menuItems[STYLE])
new PlotContentsDialog(plot, PlotContentsDialog.STYLE).showDialog(this);
else if (b==menuItems[TEMPLATE])
new PlotDialog(plot, PlotDialog.TEMPLATE).showDialog(this);
else if (b==menuItems[RESET_PLOT]) {
plot.setFont(Font.PLAIN, fontSize);
plot.setAxisLabelFont(Font.PLAIN, fontSize);
plot.setFormatFlags(Plot.getDefaultFlags());
plot.setFrameSize(plotWidth, plotHeight); plot.updateImage();
} else if (b==menuItems[HI_RESOLUTION])
new PlotDialog(plot, PlotDialog.HI_RESOLUTION).showDialog(this);
else if (b==menuItems[PROFILE_PLOT_OPTIONS])
IJ.doCommand("Plots...");
ic.requestFocus(); } catch (Exception ex) { IJ.handleException(ex); }
}
private void enableDisableMenuItems() {
boolean frozen = plot.isFrozen(); ((CheckboxMenuItem)menuItems[FREEZE]).setState(frozen);
for (int i : DISABLED_WHEN_FROZEN)
menuItems[i].setEnabled(!frozen);
if (!PlotContentsDialog.tableWindowExists())
menuItems[ADD_FROM_TABLE].setEnabled(false);
if (plot.getDataObjectDesignations().length == 0)
menuItems[ADD_FIT].setEnabled(false);
}
public void itemStateChanged(ItemEvent e) {
if (e.getSource()==menuItems[FREEZE]) {
boolean frozen = ((CheckboxMenuItem)menuItems[FREEZE]).getState();
plot.setFrozen(frozen);
}
}
public void mouseMoved(int x, int y) {
super.mouseMoved(x, y);
if (plot == null)
return;
String statusText = null;
if (x < plot.leftMargin || y > plot.topMargin + plot.frameHeight) {
if (!rangeArrowsVisible && !plot.isFrozen())
showRangeArrows();
if (activeRangeArrow < 0) {}
else if (activeRangeArrow < 8) statusText = ((activeRangeArrow+1)&0x02) != 0 ? "Decrease Range" : "Increase Range";
else if (activeRangeArrow == 8) statusText = "Reset Range";
else if (activeRangeArrow == 9) statusText = "Full Range (Fit All)";
else if (activeRangeArrow >= 10 &&
activeRangeArrow < 14) statusText = "Set limit...";
else if (activeRangeArrow >= 14)
statusText = "Axis Range & Options...";
boolean repaint = false;
if (activeRangeArrow >= 0 && !rangeArrowRois[activeRangeArrow].contains(x, y)) {
rangeArrowRois[activeRangeArrow].setFillColor(
activeRangeArrow < 10 ? inactiveRangeArrowColor : inactiveRangeRectColor);
repaint = true; activeRangeArrow = -1;
}
if (activeRangeArrow < 0) { int i = getRangeArrowIndex(x, y);
if (i >= 0) { rangeArrowRois[i].setFillColor(
i < 14 ? activeRangeArrowColor : activeRangeRectColor);
activeRangeArrow = i;
repaint = true;
}
}
if (repaint) ic.repaint();
} else if (rangeArrowsVisible)
hideRangeArrows();
if (statusText == null)
statusText = userStatusText != null ? userStatusText : plot.getCoordinates(x, y);
if (statusLabel != null)
statusLabel.setText(statusText);
}
void mouseExited(MouseEvent e) {
if (rangeArrowsVisible)
hideRangeArrows();
}
public synchronized void mouseWheelMoved(MouseWheelEvent e) {
if (plot.isFrozen() || !(ic instanceof PlotCanvas)) { super.mouseWheelMoved(e);
return;
}
int rotation = e.getWheelRotation();
int amount = e.getScrollAmount();
if (e.getX() < plot.leftMargin || e.getX() > plot.leftMargin + plot.frameWidth) return;
if (e.getY() < plot.topMargin || e.getY() > plot.topMargin + plot.frameHeight)
return;
boolean ctrl = (e.getModifiers()&Event.CTRL_MASK)!=0;
if (amount<1) amount=1;
if (rotation==0)
return;
if (ctrl||IJ.shiftKeyDown()) {
double zoomFactor = rotation<0 ? Math.pow(2, 0.2) : Math.pow(0.5, 0.2);
Point loc = ic.getCursorLoc();
int x = ic.screenX(loc.x);
int y = ic.screenY(loc.y);
((PlotCanvas)ic).zoom(x, y, zoomFactor);
} else if (IJ.spaceBarDown())
plot.scroll(rotation*amount*Math.max(ic.imageWidth/50, 1), 0);
else
plot.scroll(0, rotation*amount*Math.max(ic.imageHeight/50, 1));
}
void showRangeArrows() {
if (imp == null)
return;
hideRangeArrows(); rangeArrowRois = new Roi[4 * 2 + 2 + 4 + 2]; int i = 0;
int height = imp.getHeight();
int arrowH = plot.topMargin < 14 ? 6 : 8; float[] yP = new float[]{height - arrowH / 2, height - 3 * arrowH / 2, height - 5 * arrowH / 2 - 0.1f};
for (float x : new float[]{plot.leftMargin, plot.leftMargin + plot.frameWidth}) { float[] x0 = new float[]{x - arrowH / 2, x - 3 * arrowH / 2 - 0.1f, x - arrowH / 2};
rangeArrowRois[i++] = new PolygonRoi(x0, yP, 3, Roi.POLYGON);
float[] x1 = new float[]{x + arrowH / 2, x + 3 * arrowH / 2 + 0.1f, x + arrowH / 2};
rangeArrowRois[i++] = new PolygonRoi(x1, yP, 3, Roi.POLYGON);
}
float[] xP = new float[]{arrowH / 2 - 0.1f, 3 * arrowH / 2, 5 * arrowH / 2 + 0.1f};
for (float y : new float[]{plot.topMargin + plot.frameHeight, plot.topMargin}) { float[] y0 = new float[]{y + arrowH / 2, y + 3 * arrowH / 2 + 0.1f, y + arrowH / 2};
rangeArrowRois[i++] = new PolygonRoi(xP, y0, 3, Roi.POLYGON);
float[] y1 = new float[]{y - arrowH / 2, y - 3 * arrowH / 2 - 0.1f, y - arrowH / 2};
rangeArrowRois[i++] = new PolygonRoi(xP, y1, 3, Roi.POLYGON);
}
Font theFont = new Font("SansSerif", Font.BOLD, 13);
TextRoi txtRoi = new TextRoi(1, height - 19, "\u2009R\u2009", theFont); rangeArrowRois[8] = txtRoi;
TextRoi txtRoi2 = new TextRoi(20, height - 19, "\u2009F\u2009", theFont);
rangeArrowRois[9] = txtRoi2;
rangeArrowRois[10] = new Roi(plot.leftMargin - arrowH/2 + 1, height - 5 * arrowH / 2, arrowH - 2, arrowH * 2); rangeArrowRois[11] = new Roi(plot.leftMargin + plot.frameWidth - arrowH/2 + 1, height - 5 * arrowH / 2, arrowH - 2, arrowH * 2); rangeArrowRois[12] = new Roi(arrowH / 2, plot.topMargin + plot.frameHeight - arrowH/2 + 1, arrowH * 2, arrowH -2); rangeArrowRois[13] = new Roi(arrowH / 2, plot.topMargin - arrowH/2 + 1, arrowH * 2, arrowH - 2 );
int topMargin = plot.topMargin;
int bottomMargin = topMargin + plot.frameHeight;
int leftMargin = plot.leftMargin;
int rightMargin = plot.leftMargin + plot.frameWidth;
rangeArrowRois[14] = new Roi(leftMargin, bottomMargin+2, rightMargin - leftMargin + 1, 2*arrowH);
rangeArrowRois[15] = new Roi(leftMargin-2*arrowH-2, topMargin, 2*arrowH, bottomMargin - topMargin + 1);
Overlay ovly = imp.getOverlay();
if (ovly == null)
ovly = new Overlay();
for (Roi roi : rangeArrowRois) {
if (roi instanceof PolygonRoi)
roi.setFillColor(inactiveRangeArrowColor);
else if (roi instanceof TextRoi) {
roi.setStrokeColor(Color.WHITE);
roi.setFillColor(inactiveRangeArrowColor);
} else
roi.setFillColor(inactiveRangeRectColor); ovly.add(roi);
}
imp.setOverlay(ovly);
ic.repaint();
rangeArrowsVisible = true;
}
void hideRangeArrows() {
if (imp == null || rangeArrowRois==null) return;
Overlay ovly = imp.getOverlay();
if (ovly == null) return;
for (Roi roi : rangeArrowRois)
ovly.remove(roi);
ic.repaint();
rangeArrowsVisible = false;
activeRangeArrow = -1;
}
int getRangeArrowIndex(int x, int y) {
if (!rangeArrowsVisible) return -1;
for (int i=0; i<rangeArrowRois.length; i++)
if (rangeArrowRois[i].getBounds().contains(x,y))
return i;
return -1;
}
void showList(boolean useLabels){
ResultsTable rt = plot.getResultsTable(saveXValues, useLabels);
if (rt==null) return;
rt.show("Plot Values");
if (autoClose) {
imp.changes=false;
close();
}
}
public ResultsTable getResultsTable() {
return plot.getResultsTable(saveXValues);
}
private String getValuesAsString(){
ResultsTable rt = getResultsTable();
StringBuffer sb = new StringBuffer();
for (int i=0; i<rt.size(); i++) {
sb.append(rt.getRowAsString(i));
sb.append("\n");
}
return sb.toString();
}
void saveAsText() {
if (plot.getXValues() == null) {
IJ.error("Plot has no data");
return;
}
SaveDialog sd = new SaveDialog("Save as Text", "Values", Prefs.defaultResultsExtension());
String name = sd.getFileName();
if (name==null) return;
String directory = sd.getDirectory();
IJ.wait(250); IJ.showStatus("Saving plot values...");
ResultsTable rt = plot.getResultsTable(saveXValues, true);
try {
rt.saveAs(directory+name);
} catch (IOException e) {
IJ.error("" + e);
return;
}
if (autoClose)
{imp.changes=false; close();}
}
void copyToClipboard(boolean writeAllColumns) {
float[] xValues = plot.getXValues();
float[] yValues = plot.getYValues();
if (xValues == null) return;
Clipboard systemClipboard = null;
try {systemClipboard = getToolkit().getSystemClipboard();}
catch (Exception e) {systemClipboard = null; }
if (systemClipboard==null)
{IJ.error("Unable to copy to Clipboard."); return;}
IJ.showStatus("Copying plot values...");
CharArrayWriter aw = new CharArrayWriter(10*xValues.length);
PrintWriter pw = new PrintWriter(aw);
if (writeAllColumns) {
ResultsTable rt = plot.getResultsTableWithLabels();
if (!Prefs.dontSaveHeaders) {
String headings = rt.getColumnHeadings();
pw.println(headings);
}
for (int i=0; i<rt.size(); i++)
pw.println(rt.getRowAsString(i));
} else {
int xdigits = 0;
if (saveXValues)
xdigits = plot.getPrecision(xValues);
int ydigits = plot.getPrecision(yValues);
for (int i=0; i<Math.min(xValues.length, yValues.length); i++) {
if (saveXValues)
pw.println(IJ.d2s(xValues[i],xdigits)+"\t"+IJ.d2s(yValues[i],ydigits));
else
pw.println(IJ.d2s(yValues[i],ydigits));
}
}
String text = aw.toString();
pw.close();
StringSelection contents = new StringSelection(text);
systemClipboard.setContents(contents, this);
IJ.showStatus(text.length() + " characters copied to Clipboard");
if (autoClose)
{imp.changes=false; close();}
}
public void lostOwnership(Clipboard clipboard, Transferable contents) {}
public float[] getXValues() {
return plot.getXValues();
}
public float[] getYValues() {
return plot.getYValues();
}
public void drawPlot(Plot plot) {
this.plot = plot;
if (imp!=null) {
if (ic instanceof PlotCanvas)
((PlotCanvas)ic).setPlot(plot);
imp.setProcessor(null, plot.getProcessor());
plot.setImagePlus(imp); }
}
public static void savePreferences(Properties prefs) {
double min = ProfilePlot.getFixedMin();
double max = ProfilePlot.getFixedMax();
prefs.put(PREFS_WIDTH, Integer.toString(plotWidth));
prefs.put(PREFS_HEIGHT, Integer.toString(plotHeight));
prefs.put(PREFS_FONT_SIZE, Integer.toString(defaultFontSize));
int options = 0;
if (!interpolate) options |= INTERPOLATE; prefs.put(OPTIONS, Integer.toString(options));
}
private void toggleLiveProfiling() {
boolean liveMode = bgThread != null;
if (liveMode)
disableLivePlot();
else
enableLivePlot();
}
private void enableLivePlot() {
if (plotMaker==null)
plotMaker = plot!=null?plot.getPlotMaker():null;
if (plotMaker==null) return;
srcImp = plotMaker.getSourceImage();
if (srcImp==null)
return;
if (bgThread==null) {
bgThread = new Thread(this, "Live Plot");
bgThread.setPriority(Math.max(bgThread.getPriority()-3, Thread.MIN_PRIORITY));
doUpdate = true;
bgThread.start();
}
if (IJ.debugMode) IJ.log("PlotWindow.createListeners");
ImagePlus.addImageListener(this);
Roi.addRoiListener(this);
Font font = live.getFont();
live.setFont(new Font(font.getName(), Font.BOLD, font.getSize()));
live.setForeground(Color.red);
}
private void disableLivePlot() {
if (IJ.debugMode) IJ.log("PlotWindow.disableLivePlot: "+srcImp);
if (srcImp==null)
return;
if (bgThread!=null)
bgThread.interrupt();
bgThread = null;
ImagePlus.removeImageListener(this);
Roi.removeRoiListener(this);
if (live != null) {
Font font = live.getFont();
live.setFont(new Font(font.getName(), Font.PLAIN, font.getSize()));
live.setForeground(Color.black);
}
}
public synchronized void roiModified(ImagePlus img, int id) {
if (IJ.debugMode) IJ.log("PlotWindow.roiModified: "+img+" "+id);
if (img==srcImp) {
doUpdate=true;
notify();
}
}
public void imageOpened(ImagePlus imp) {
}
public synchronized void imageUpdated(ImagePlus imp) {
if (imp==srcImp) {
doUpdate = true;
notify();
}
}
public void imageClosed(ImagePlus imp) {
if (imp==srcImp || imp==this.imp) {
disableLivePlot();
srcImp = null;
plotMaker = null;
}
}
public void run() {
while (true) {
IJ.wait(50); Plot plot = plotMaker!=null?plotMaker.getPlot():null;
if (doUpdate && plot!=null && plot.getNumPlotObjects()>0) {
plot.useTemplate(this.plot, this.plot.templateFlags | Plot.COPY_SIZE | Plot.COPY_LABELS | Plot.COPY_AXIS_STYLE |
Plot.COPY_CONTENTS_STYLE | Plot.COPY_LEGEND | Plot.COPY_EXTRA_OBJECTS);
plot.setPlotMaker(plotMaker);
this.plot = plot;
((PlotCanvas)ic).setPlot(plot);
ImageProcessor ip = plot.getProcessor();
if (ip!=null && imp!=null) {
imp.setProcessor(null, ip);
plot.setImagePlus(imp);
}
}
synchronized(this) {
if (doUpdate) {
doUpdate = false; } else {
try {wait();} catch(InterruptedException e) { return;
}
}
}
}
}
public Plot getPlot() {
return plot;
}
public static void freeze() {
Window win = WindowManager.getActiveWindow();
if (win!=null && (win instanceof PlotWindow))
((PlotWindow)win).getPlot().setFrozen(true);
}
public static void setDefaultFontSize(int size) {
if (size < 9) size = 9;
defaultFontSize = size;
}
public static int getDefaultFontSize() {
return defaultFontSize;
}
}