Put X axis and calibration bar outside of image

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

Put X axis and calibration bar outside of image

Laurent.guerard
Hello,

Sorry for a question that may seem stupid, but I'm writing a plugin to do a spectral Kymograph if I could say, and I need to put a X axis to my image corresponding to the different wavelengths, do you know if it's possible ?
Plus I would like to add a calibration bar outside my picture, like beside it, is there a way to do that quickly or should I change the dimension of my image to put the bar beside ?

Thanks a lot.
This is my first post here so if it's not clear just ask me !
Reply | Threaded
Open this post in threaded view
|

Re: Put X axis and calibration bar outside of image

Michael Schmid
Hi Laurent,

for adding an axis, you could try the 'Label Image' plugin
  http://www.optinav.com/Label-Image.htm

It will create both x and y axes; you have to crop the image to remove the y axis if you don't want it.

For a calibration bar outside the image, as far as I know you have to adjust the canvas size first, to make space. Add the calibration bar before using the 'Label Image' plugin; as far as I remember, the 'Label Image' plugin does not preserve the pixel value calibration.

Michael
________________________________________________________________
On Jun 30, 2015, at 10:06, Laurent.guerard wrote:

> Hello,
>
> Sorry for a question that may seem stupid, but I'm writing a plugin to do a
> spectral Kymograph if I could say, and I need to put a X axis to my image
> corresponding to the different wavelengths, do you know if it's possible ?
> Plus I would like to add a calibration bar outside my picture, like beside
> it, is there a way to do that quickly or should I change the dimension of my
> image to put the bar beside ?
>
> Thanks a lot.
> This is my first post here so if it's not clear just ask me !
>
>
>
>
> --
> View this message in context: http://imagej.1557.x6.nabble.com/Put-X-axis-and-calibration-bar-outside-of-image-tp5013353.html
> Sent from the ImageJ mailing list archive at Nabble.com.
>
> --
> ImageJ mailing list: http://imagej.nih.gov/ij/list.html

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
|

Re: Put X axis and calibration bar outside of image

Laurent.guerard
Hi Michael,

Thanks a lot for this plugin.
I need to understand how to put graduations on that scale bar now, but I don't see any options in the Plugin .. Like a graduatino every 50nm or something.
And thanks for the tip about the calibration bar, I'll try that and come back to you.
Reply | Threaded
Open this post in threaded view
|

Re: Put X axis and calibration bar outside of image

Laurent.guerard
In reply to this post by Michael Schmid
Hi,

So I've been playing with this label image plugin for the day and I really can't find an option to graduate the axis, is it me or is it not possible ? Because that's what I'm looking for actually..
If any of you has an idea, let me know !

Thanks again
Reply | Threaded
Open this post in threaded view
|

Re: Put X axis and calibration bar outside of image

Michael Schmid
In reply to this post by Laurent.guerard
Hi Laurent,

the 'Label Image' plugin autoselects the distance between the ticks. It seems to use the axes of an ImageJ Plot window for this, so it uses the same algorithm, where the distance between the ticks is 10^n, 2*10^n or 5*10^n, with integer n.
If the image is not wide enough (e.g., less than 100 pixels), it may happen that you don't get ticks on the x axis. In such a case, enlarge your image e.g. by a factor of 2.

Michael
________________________________________________________________

On Jun 30, 2015, at 15:48, Laurent.guerard wrote:

> Hi,
>
> So I've been playing with this label image plugin for the day and I really
> can't find an option to graduate the axis, is it me or is it not possible ?
> Because that's what I'm looking for actually..
> If any of you has an idea, let me know !

On Jun 30, 2015, at 11:41, Laurent.guerard wrote:

> Hi Michael,
>
> Thanks a lot for this plugin.
> I need to understand how to put graduations on that scale bar now, but I
> don't see any options in the Plugin .. Like a graduatino every 50nm or
> something.
> And thanks for the tip about the calibration bar, I'll try that and come
> back to you.

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
|

Re: Put X axis and calibration bar outside of image

Laurent.guerard
Hi,

So my image is actually 1024x1024 so this shouldn't be the problem .. I'm trying to get bars between 421nm and 722 nm but get nothing. I've even tried with 420 to 725 (or even 720) and still no ticks ...
Plus I'm looking for a way to put special ticks, they are not always spaced by the same distance, would you have any idea on how to get this to work ?

Thanks again very much !

Laurent
Reply | Threaded
Open this post in threaded view
|

Re: Put X axis and calibration bar outside of image

Eric Barnhill
In reply to this post by Laurent.guerard
Hi Laurent,

If you want additional functionality from the Calibration Bar you might try my Custom Legend plug-in available at https://github.com/ericbarnhill/barnhill_ij_toolkit . If you have any problems I will provide support.

Thanks,
Eric Barnhill

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
|

Re: Put X axis and calibration bar outside of image

Laurent.guerard
Hi,

Thank you for proposing your help !
So is your plugin working only with Fiji or do I need Matlab ? Because I don't want to involve Matlab if possible ...
Then for your plugin, I've never actually worked with a plugin on github, so what should I do ? Sorry, I'm only a beginner ..

Thanks again !
Reply | Threaded
Open this post in threaded view
|

Re: Put X axis and calibration bar outside of image

Michael Schmid
In reply to this post by Laurent.guerard
Hi Laurent,

you could try the slightly modified version that I used a while ago (In contrast to the original, it uses the spatial calibration of the image). I'll simply paste it below.
It's not perfect; e.g. it will truncate text if the label size is too large (usually it works up to font size 14 or so).

Michael
________________________________________________________________
On Jul 2, 2015, at 11:34, Laurent.guerard wrote:

> Hi,
>
> So my image is actually 1024x1024 so this shouldn't be the problem .. I'm
> trying to get bars between 421nm and 722 nm but get nothing. I've even tried
> with 420 to 725 (or even 720) and still no ticks ...
> Plus I'm looking for a way to put special ticks, they are not always spaced
> by the same distance, would you have any idea on how to get this to work ?
>
> Thanks again very much !
>
> Laurent
________________________________________________________________
import java.awt.*;
import java.awt.image.*;
import java.io.*;
import java.util.*;
import ij.*;
import ij.gui.*;
import ij.process.*;
import ij.util.*;
import ij.plugin.filter.Analyzer;
import ij.macro.Interpreter;
import ij.measure.Calibration;
import ij.plugin.filter.PlugInFilter;


/** Bob Dougherty.  Plugin to add x and y axis labels to a plot.
        Borrows extensively from Example-plot by Hajime Hirase and Wayne Rasband.
    and Plot and Plot_Window by Wayne Rasband.
    Version 0  1/30//2008
    Version 0.1 1/30/2008  Uses foreground color for lines and lables and background color for fill
    Version 0.2 1/31/2008  Use of toolbar colors is optional now.
    Version 2014-07-23 M. Schmid, uses image calibration by default

        License:
        Copyright (c)2008, OptiNav, Inc.
        All rights reserved.

        Redistribution and use in source and binary forms, with or without
        modification, are permitted provided that the following conditions
        are met:

                Redistributions of source code must retain the above copyright
        notice, this list of conditions and the following disclaimer.
                Redistributions in binary form must reproduce the above copyright
        notice, this list of conditions and the following disclaimer in the
        documentation and/or other materials provided with the distribution.
                Neither the name of OptiNav, Inc. nor the names of its contributors
        may be used to endorse or promote products derived from this software
        without specific prior written permission.

        THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
        "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
        LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
        A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
        CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
        EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
        PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
        PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
        LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
        NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
        SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

public class Label_Image implements PlugInFilter {
        ImagePlus imp;
        public int setup(String arg, ImagePlus imp) {
                if (IJ.versionLessThan("1.17j"))
                        return DONE;
                this.imp = imp;
                return DOES_ALL;
        }

    public void run(ImageProcessor ip) {
        if (IJ.versionLessThan("1.30c"))
            return;
        String titleFromPrefs = Prefs.get("labelimage.title", "_Labeled");
                String title = titleFromPrefs.length()<15 ? imp.getTitle()+titleFromPrefs : imp.getTitle()+"_Labeled";
                int fontSize = (int)Prefs.get("labelimage.fontSize", 14);
                boolean useToolbarColors = Prefs.get("labelimage.useToolbarColors", false);
                Calibration cal = imp.getCalibration();
                boolean hasXcalibration = cal!=null && (cal.pixelWidth != 1 || cal.xOrigin != 0);
                double xMin = hasXcalibration ? Prefs.get("labelimage.xMin", 0) : -cal.pixelWidth*cal.xOrigin;
                double xMax = hasXcalibration ? Prefs.get("labelimage.xMax", 48) : cal.pixelWidth*(ip.getWidth()-cal.xOrigin);
                double scaleX = Prefs.get("labelimage.scaleX", 1);
                String xUnit = cal==null || cal.getXUnit()==null ? "" : " ("+cal.getXUnit()+")";
                String xLabel = Prefs.get("labelimage.xLabel", " ") + xUnit;
                boolean interpolateX = Prefs.get("labelimage.interpolateX", false);
                double yMin = cal==null ? Prefs.get("labelimage.yMin", 0) : cal.pixelHeight*(ip.getHeight()-cal.yOrigin);
                double yMax = cal==null ? Prefs.get("labelimage.yMax", 45) : -cal.pixelHeight*cal.yOrigin;
                double scaleY = Prefs.get("labelimage.scaleY", 1);
                String yUnit = cal==null || cal.getYUnit()==null ? "" : " ("+cal.getYUnit()+")";
                String yLabel = Prefs.get("labelimage.yLabel", " ") + yUnit;
                boolean interpolateY = Prefs.get("labelimage.interpolateY", false);
                GenericDialog gd = new GenericDialog("Label Image", IJ.getInstance());
                gd.addStringField("Title", title, 30);
                gd.addNumericField("font size", fontSize,0);
                gd.addCheckbox("useToolbarColors (else black letters, white margins)",useToolbarColors);
                gd.addMessage("--------------- Horizontal Axis -----------------");
                gd.addNumericField("xMin", xMin,2);
                gd.addNumericField("xMax", xMax,2);
                gd.addNumericField("scaleX", scaleX,1);
                gd.addStringField("xLabel", xLabel, 30);
        gd.addCheckbox("interpolateX",interpolateX);
                gd.addMessage("--------------- Vertical Axis -----------------");
                gd.addNumericField("yMin (bottom)", yMin,2);
                gd.addNumericField("yMax (top)", yMax,2);
                gd.addNumericField("scaleY", scaleY,1);
                gd.addStringField("yLabel", yLabel, 30);
        gd.addCheckbox("interpolateY",interpolateY);
                gd.showDialog();
                if (gd.wasCanceled()) {
                        return;
                }
                title = gd.getNextString();
  fontSize = (int)gd.getNextNumber();
      useToolbarColors = gd.getNextBoolean();
  xMin = gd.getNextNumber();
  xMax = gd.getNextNumber();
  scaleX = gd.getNextNumber();
                xLabel = gd.getNextString();
      interpolateX = gd.getNextBoolean();
  yMin = gd.getNextNumber();
  yMax = gd.getNextNumber();
  scaleY = gd.getNextNumber();
                yLabel = gd.getNextString();
      interpolateY = gd.getNextBoolean();
      String titleForPrefs = title.startsWith(imp.getTitle()) ? title.substring(imp.getTitle().length()) : title;
                Prefs.set("labelimage.title",titleForPrefs);
  Prefs.set("labelimage.fontSize",fontSize);
  Prefs.set("labelimage.useToolbarColors",useToolbarColors);
                Prefs.set("labelimage.xMin",xMin);
                Prefs.set("labelimage.xMax",xMax);
                Prefs.set("labelimage.scaleX",scaleX);
                String xLabelForPrefs = xLabel.endsWith(xUnit) ? xLabel.substring(0,xLabel.length()-xUnit.length()) : xLabel;
                Prefs.set("labelimage.xLabel",xLabelForPrefs);
                Prefs.set("labelimage.interpolateX",interpolateX);
                Prefs.set("labelimage.yMin",yMin);
                Prefs.set("labelimage.yMax",yMax);
                Prefs.set("labelimage.scaleY",scaleY);
                String yLabelForPrefs = yLabel.endsWith(yUnit) ? yLabel.substring(0,yLabel.length()-yUnit.length()) : yLabel;
                Prefs.set("labelimage.yLabel",yLabelForPrefs);
                Prefs.set("labelimage.interpolateY",interpolateY);
         
        //float[] x = {0.1f, 0.25f, 0.35f, 0.5f, 0.61f,0.7f,0.85f,0.89f,0.95f}; // x-coordinates
        //float[] y = {2f,5.6f,7.4f,9f,9.4f,8.7f,6.3f,4.5f,1f}; // x-coordinates
        //float[] e = {.8f,.6f,.5f,.4f,.3f,.5f,.6f,.7f,.8f}; // error bars
        int w = ip.getWidth();
        int h = ip.getHeight();
        int wScaled = (int)(scaleX*w + 0.5);
        int hScaled = (int)(scaleY*h + 0.5);
        if(wScaled == w)interpolateX = false;
        if(hScaled == h)interpolateY = false;
        ImageProcessor ipDup = ip.duplicate();
                ipDup.setInterpolate(interpolateX);
                ImageProcessor ipScX = ipDup.resize(wScaled,h);
                ipScX.setInterpolate(interpolateY);
                ImageProcessor ipScXY = ipScX.resize(wScaled,hScaled);
      Font labelFont = new Font("Helvetica", Font.PLAIN, fontSize);
      PlotLabeled plot = new PlotLabeled(title,xLabel,yLabel,ipScXY,2,labelFont,useToolbarColors);
        plot.setLimits(xMin, xMax, yMin, yMax);
       // plot.setLineWidth(2);
        //plot.addErrorBars(e);

        // add a second curve
        //float x2[] = {.4f,.5f,.6f,.7f,.8f};
        //float y2[] = {4,3,3,4,5};
        //plot.setColor(Color.red);
        //plot.addPoints(x2,y2,PlotWindow.X);
       // plot.addPoints(x2,y2,PlotWindow.LINE);

        // add label
       // plot.setColor(Color.black);
        //plot.changeFont(new Font("Helvetica", Font.PLAIN, 24));
        //plot.addLabel(0.15, 0.95, "This is a label");

       // plot.changeFont(new Font("Helvetica", Font.PLAIN, 16));
       // plot.setColor(Color.blue);
        plot.show();
    }
}



/** This class is an image that line graphs can be drawn on. */
class PlotLabeled {

    /** Display points using a circle 5 pixels in diameter. */
    public static final int CIRCLE = 0;
    /** Display points using an X-shaped mark. */
    public static final int X = 1;
    /** Display points using an box-shaped mark. */
    public static final int BOX = 3;
    /** Display points using an tiangular mark. */
    public static final int TRIANGLE = 4;
    /** Display points using an cross-shaped mark. */
    public static final int CROSS = 5;
    /** Display points using a single pixel. */
    public static final int DOT = 6;
    /** Connect points with solid lines. */
    public static final int LINE = 2;
    ///** flag multiplier for maximum number of ticks&grid lines along x */
    //public static final int X_INTERVALS_M = 0x1;
    ///** flag multiplier for maximum number of ticks&grid lines along y */
    //public static final int Y_INTERVALS_M = 0x100;
    /** flag for numeric labels of x-axis ticks */
    public static final int X_NUMBERS = 0x1;
    /** flag for numeric labels of x-axis ticks */
    public static final int Y_NUMBERS = 0x2;
    /** flag for drawing x-axis ticks */
    public static final int X_TICKS = 0x4;
    /** flag for drawing x-axis ticks */
    public static final int Y_TICKS = 0x8;
    /** flag for drawing vertical grid lines for x-axis ticks */
    public static final int X_GRID = 0x10;
    /** flag for drawing horizontal grid lines for y-axis ticks */
    public static final int Y_GRID = 0x20;
    /** flag for forcing frame to coincide with the grid/ticks in x direction (results in unused space) */
    public static final int X_FORCE2GRID = 0x40;
    /** flag for forcing frame to coincide with the grid/ticks in y direction (results in unused space) */
    public static final int Y_FORCE2GRID = 0x80;
    /** the default flags */
    public static final int DEFAULT_FLAGS =  X_NUMBERS + Y_NUMBERS + X_TICKS + Y_TICKS /*+ X_GRID + Y_GRID*/;
    /** the margin width left of the plot frame (enough for 5-digit numbers such as unscaled 16-bit data*/
    public static final int LEFT_MARGIN = 60;
    /** the margin width right of the plot frame */
    public static final int RIGHT_MARGIN = 18;
    /** the margin width above the plot frame */
    public static final int TOP_MARGIN = 15;
    /** the margin width below the plot frame */
    public static final int BOTTOM_MARGIN = 40;

    private static final int MAX_INTERVALS = 12;    //maximum number of intervals between ticks or grid lines
    private static final int MIN_X_GRIDWIDTH = 60;  //minimum distance between grid lines or ticks along x
    private static final int MIN_Y_GRIDWIDTH = 25;  //minimum distance between grid lines or ticks along y
    private static final int TICK_LENGTH = 3;       //length of ticks
    private final Color gridColor = new Color(0xc0c0c0); //light gray
    private int frameWidth;
    private int frameHeight;
   
    Rectangle frame = null;
    float[] xValues = new float[1];
    float[] yValues = new float[1];
    ImageProcessor ipSource;
    float[] errorBars;
    int nPoints;
    double xMin, xMax, yMin, yMax;
   
    private double xScale, yScale;
    private static String defaultDirectory = null;
    private String xLabel;
    private String yLabel;
    private int flags;
    private Font font = new Font("Helvetica", Font.PLAIN, 12);
    private boolean fixedYScale;
    private int lineWidth = 1; // Line.getWidth();
    private int frameLineWidth = 1; ;
    private int markSize = 5;
    private ImageProcessor ip;
    private String title;
    private boolean initialized;
    private boolean plotDrawn;
    private int plotWidth, plotHeight;
    //private int plotWidth = PlotWindow.plotWidth;
    //private int plotHeight = PlotWindow.plotHeight;
    private boolean multiplePlots;
    private boolean drawPending;
    private Font labelFont;
    private Color foregroundColor = Color.black;
    private Color backgroundColor = Color.white;
   
    /** Construct a new PlotWindow.
     * @param title the window title
     * @param xLabel    the x-axis label
     * @param yLabel    the y-axis label
     * @param xValues   the x-coodinates, or null
     * @param yValues   the y-coodinates, or null
     * @param flags     sum of flag values controlling appearance of ticks, grid, etc.
     */
    public PlotLabeled(String title, String xLabel, String yLabel, ImageProcessor ipSource, int flags, int frameLineWidth,
           Font labelFont, boolean useToolbarColors) {
        this.title = title;
        this.xLabel = xLabel;
        this.yLabel = yLabel;
        this.flags = flags;
        this.frameLineWidth = frameLineWidth;
        this.labelFont = labelFont;
         //Force frameLineWidth to be even
        if((this.frameLineWidth % 2) == 1)this.frameLineWidth ++;
        this.ipSource = ipSource;
        //double[] a = Tools.getMinMax(xValues);
        //xMin=a[0]; xMax=a[1];
       // a = Tools.getMinMax(yValues);
       //yMin=a[0]; yMax=a[1];
        fixedYScale = false;
        nPoints = xValues.length;
        drawPending = true;
                plotWidth = ipSource.getWidth() + frameLineWidth/2;
                plotHeight = ipSource.getHeight() + frameLineWidth/2;
                if(useToolbarColors){
                        foregroundColor = Toolbar.getForegroundColor();
                        backgroundColor = Toolbar.getBackgroundColor();
                }
    }
   
    /** This version of the constructor uses the default flags. */
    public PlotLabeled(String title, String xLabel, String yLabel, ImageProcessor ipSource, int frameLineWidth, Font labelFont,boolean useToolbarColors) {
        this(title, xLabel, yLabel,ipSource, DEFAULT_FLAGS,frameLineWidth,labelFont,useToolbarColors);
    }

    /** Sets the x-axis and y-axis range. */
    public void setLimits(double xMin, double xMax, double yMin, double yMax) {
        this.xMin = xMin;
        this.xMax = xMax;
        this.yMin = yMin;
        this.yMax = yMax;
        fixedYScale = true;
        if (initialized) setScale();
    }

    /** Sets the canvas size (i.e., size of the resulting ImageProcessor).
     * By default, the size is adjusted for the plot frame size specified
     * in Edit>Options>Profile Plot Options*/
    public void setSize(int width, int height) {
        if (!initialized && width>LEFT_MARGIN+RIGHT_MARGIN+20 && height>TOP_MARGIN+BOTTOM_MARGIN+20) {
            plotWidth = width-LEFT_MARGIN-RIGHT_MARGIN;
            plotHeight = height-TOP_MARGIN-BOTTOM_MARGIN;
        }
    }

    /** Adds a set of points to the plot or adds a curve if shape is set to LINE.
     * @param x         the x-coodinates
     * @param y         the y-coodinates
     * @param shape     CIRCLE, X, BOX, TRIANGLE, CROSS, DOT or LINE
     */
    public void addPoints(float[] x, float[] y, int shape) {
        setup();
        switch(shape) {
            case CIRCLE: case X:  case BOX: case TRIANGLE: case CROSS: case DOT:
                for (int i=0; i<x.length; i++) {
                    int xt = LEFT_MARGIN + (int)((x[i]-xMin)*xScale);
                    int yt = TOP_MARGIN + frameHeight - (int)((y[i]-yMin)*yScale);
                    if (xt>=frame.x && yt>=frame.y && xt<=frame.x+frame.width && yt<=frame.y+frame.height)
                        drawShape(shape, xt, yt, markSize);
                }
                break;
            case LINE:
                ip.setClipRect(frame);
                int xts[] = new int[x.length];
                int yts[] = new int[y.length];
                for (int i=0; i<x.length; i++) {
                    xts[i] = LEFT_MARGIN + (int)((x[i]-xMin)*xScale);
                    yts[i] = TOP_MARGIN + frameHeight - (int)((y[i]-yMin)*yScale);
                }
                drawPolyline(ip, xts, yts, x.length);
                ip.setClipRect(null);
                break;
        }
        multiplePlots = true;
        if (xValues.length==1) {
            xValues = x;
            yValues = y;
            nPoints = x.length;
            drawPending = false;
        }
    }
   
    /** Adds a set of points to the plot using double arrays.
     * Must be called before the plot is displayed. */
    public void addPoints(double[] x, double[] y, int shape) {
        addPoints(Tools.toFloat(x), Tools.toFloat(y), shape);
    }
   
    void drawShape(int shape, int x, int y, int size) {
        int xbase = x-size/2;
        int ybase = y-size/2;
        switch(shape) {
            case X:
                ip.drawLine(xbase,ybase,xbase+size,ybase+size);
                ip.drawLine(xbase+size,ybase,xbase,ybase+size);
                break;
            case BOX:
                ip.drawLine(xbase,ybase,xbase+size,ybase);
                ip.drawLine(xbase+size,ybase,xbase+size,ybase+size);
                ip.drawLine(xbase+size,ybase+size,xbase,ybase+size);
                ip.drawLine(xbase,ybase+size,xbase,ybase);
                break;
            case TRIANGLE:
                ip.drawLine(x,ybase,xbase+size,ybase+size);
                ip.drawLine(xbase+size,ybase+size,xbase,ybase+size);
                ip.drawLine(xbase,ybase+size,x,ybase);
                break;
            case CROSS:
                ip.drawLine(xbase,y,xbase+size,y);
                ip.drawLine(x,ybase,x,ybase+size);
                break;
            case DOT:
                ip.drawDot(x, y);
                break;
            default: // 5x5 oval
                ip.drawLine(x-1, y-2, x+1, y-2);
                ip.drawLine(x-1, y+2, x+1, y+2);
                ip.drawLine(x+2, y+1, x+2, y-1);
                ip.drawLine(x-2, y+1, x-2, y-1);
                break;
        }
    }
   
    /** Adds error bars to the plot. */
    public void addErrorBars(float[] errorBars) {
        if (errorBars.length!=nPoints)
            throw new IllegalArgumentException("errorBars.length != npoints");
        this.errorBars = errorBars  ;
    }
   
    /** Adds error bars to the plot. */
    public void addErrorBars(double[] errorBars) {
        addErrorBars(Tools.toFloat(errorBars));
    }
   
    /** Draws text at the specified location, where (0,0)
     * is the upper left corner of the the plot frame and (1,1) is
     * the lower right corner. */
    public void addLabel(double x, double y, String label) {
        setup();
        int xt = LEFT_MARGIN + (int)(x*frameWidth);
        int yt = TOP_MARGIN + (int)(y*frameHeight);
        ip.drawString(label, xt, yt);
    }
   
        /* Draws text at the specified location, using the coordinate system defined
                by setLimits() and the justification specified by setJustification(). */
    //  public void addText(String text, double x, double y) {
    //      setup();
    //      int xt = LEFT_MARGIN + (int)((x-xMin)*xScale);
    //      int yt = TOP_MARGIN + frameHeight - (int)((y-yMin)*yScale);
    //      if (justification==CENTER)
    //          xt -= ip.getStringWidth(text)/2;
    //      else if (justification==RIGHT)
    //          xt -= ip.getStringWidth(text);
    //      ip.drawString(text, xt, yt);
    //  }
   
    /** Sets the justification used by addLabel(), where <code>justification</code>
     * is ImageProcessor.LEFT, ImageProcessor.CENTER or ImageProcessor.RIGHT. */
    public void setJustification(int justification) {
        setup();
        ip.setJustification(justification);
    }
   
    /** Changes the drawing color. For selecting the color of the data passed with the constructor,
     * use <code>setColor</code> before <code>draw</code>.
     * The frame and labels are always drawn in black. */
    public void setColor(Color c) {
        setup();
        if (!(ip instanceof ColorProcessor)) {
            ip = ip.convertToRGB();
            ip.setLineWidth(lineWidth);
            ip.setFont(font);
            ip.setAntialiasedText(true);
        }
        ip.setColor(c);
    }
   
    /** Changes the line width. */
    public void setLineWidth(int lineWidth) {
        if (lineWidth<1) lineWidth = 1;
        setup();
        ip.setLineWidth(lineWidth);
        this.lineWidth = lineWidth;
        markSize = lineWidth==1?5:7;
    }
   
    /** Changes the font. */
    public void changeFont(Font font) {
        setup();
        ip.setFont(font);
        this.font = font;
    }
   
    void setup() {
        if (initialized)
            return;
        initialized = true;
        createImage();
        ip.setColor(foregroundColor);
        if (lineWidth>3)
            lineWidth = 3;
        ip.setLineWidth(lineWidth);
        ip.setFont(font);
        ip.setAntialiasedText(true);
        if (frameWidth==0) {
            frameWidth = plotWidth;
            frameHeight = plotHeight;
        }
        frame = new Rectangle(LEFT_MARGIN, TOP_MARGIN, frameWidth, frameHeight);
        setScale();
        changeFont(labelFont);
        if (PlotWindow.noGridLines)
            drawAxisLabels();
        else
            drawTicksEtc();
    }
   
    void setScale() {
   
        if ((xMax-xMin)==0.0)
            xScale = 1.0;
        else
            xScale = frame.width/(xMax-xMin);
        if ((yMax-yMin)==0.0)
            yScale = 1.0;
        else
            yScale = frame.height/(yMax-yMin);
    }
   
    void drawAxisLabels() {
        int digits = getDigits(yMin, yMax);
        String s = IJ.d2s(yMax, digits);
        int sw = ip.getStringWidth(s);
        if ((sw+4)>LEFT_MARGIN)
            ip.drawString(s, 4, TOP_MARGIN-4);
        else
            ip.drawString(s, LEFT_MARGIN-ip.getStringWidth(s)-4, TOP_MARGIN+10);
        s = IJ.d2s(yMin, digits);
        sw = ip.getStringWidth(s);
        if ((sw+4)>LEFT_MARGIN)
            ip.drawString(s, 4, TOP_MARGIN+frame.height);
        else
            ip.drawString(s, LEFT_MARGIN-ip.getStringWidth(s)-4, TOP_MARGIN+frame.height);
        FontMetrics fm = ip.getFontMetrics();
        int x = LEFT_MARGIN;
        int y = TOP_MARGIN + frame.height + fm.getAscent() + 6;
        digits = getDigits(xMin, xMax);
        ip.drawString(IJ.d2s(xMin,digits), x, y);
        s = IJ.d2s(xMax,digits);
        ip.drawString(s, x + frame.width-ip.getStringWidth(s)+6, y);
        ip.drawString(xLabel, LEFT_MARGIN+(frame.width-ip.getStringWidth(xLabel))/2, y+3);
        //drawYLabel(yLabel,LEFT_MARGIN-4,TOP_MARGIN,frame.height, fm);
        drawYLabel(yLabel,LEFT_MARGIN-4,TOP_MARGIN,frame.height, fm);
    }
   
    void drawTicksEtc() {
        int fontAscent = ip.getFontMetrics().getAscent();
        int fontMaxAscent = ip.getFontMetrics().getMaxAscent();
        if ((flags&(X_NUMBERS + X_TICKS + X_GRID)) != 0) {
            double step = Math.abs(Math.max(frame.width/MAX_INTERVALS, MIN_X_GRIDWIDTH)/xScale); //the smallest allowable increment
            step = niceNumber(step);
            int i1, i2;
            if ((flags&X_FORCE2GRID) != 0) {
                i1 = (int)Math.floor(Math.min(xMin,xMax)/step+1.e-10);  //this also allows for inverted xMin, xMax
                i2 = (int)Math.ceil(Math.max(xMin,xMax)/step-1.e-10);
                xMin = i1*step;
                xMax = i2*step;
                xScale = frame.width/(xMax-xMin);                       //rescale to make it fit
            } else {
                i1 = (int)Math.ceil(Math.min(xMin,xMax)/step-1.e-10);
                i2 = (int)Math.floor(Math.max(xMin,xMax)/step+1.e-10);
            }
            int digits = -(int)Math.floor(Math.log(step)/Math.log(10)+1e-6);
            if (digits < 0) digits = 0;
            int y1 = TOP_MARGIN;
            int y2 = TOP_MARGIN+frame.height;
            int yNumbers = y2 + fontAscent + 7;
            if((flags&X_TICKS) !=0) yNumbers += TICK_LENGTH;
            for (int i=0; i<=(i2-i1); i++) {
                double v = (i+i1)*step;
                int x = (int)Math.round((v - xMin)*xScale) + LEFT_MARGIN;
                if ((flags&X_GRID) != 0) {
                    ip.setColor(gridColor);
                    ip.drawLine(x, y1, x, y2);
                    ip.setColor(foregroundColor);
                }
                if ((flags&X_TICKS) !=0) {
                    //ip.drawLine(x, y1, x, y1+TICK_LENGTH);
                    //ip.drawLine(x, y2, x, y2-TICK_LENGTH);
                    ip.drawLine(x, y1, x, y1-TICK_LENGTH);
                    ip.drawLine(x, y2, x, y2+TICK_LENGTH);
                }
                if ((flags&X_NUMBERS) != 0) {
                    String s = IJ.d2s(v,digits);
                    ip.drawString(s, x-ip.getStringWidth(s)/2, yNumbers);
                }
            }
        }
        int maxNumWidth = 0;
        if ((flags&(Y_NUMBERS + Y_TICKS + Y_GRID)) != 0) {
            double step = Math.abs(Math.max(frame.width/MAX_INTERVALS, MIN_Y_GRIDWIDTH)/yScale); //the smallest allowable increment
            step = niceNumber(step);
            int i1, i2;
            if ((flags&X_FORCE2GRID) != 0) {
                i1 = (int)Math.floor(Math.min(yMin,yMax)/step+1.e-10);  //this also allows for inverted xMin, xMax
                i2 = (int)Math.ceil(Math.max(yMin,yMax)/step-1.e-10);
                yMin = i1*step;
                yMax = i2*step;
                yScale = frame.height/(yMax-yMin);                      //rescale to make it fit
            } else {
                i1 = (int)Math.ceil(Math.min(yMin,yMax)/step-1.e-10);
                i2 = (int)Math.floor(Math.max(yMin,yMax)/step+1.e-10);
            }
            int digits = -(int)Math.floor(Math.log(step)/Math.log(10)+1e-6);
            if (digits < 0) digits = 0;
            int x1 = LEFT_MARGIN;
            int x2 = LEFT_MARGIN+frame.width;
            int xNumbers = LEFT_MARGIN-4;
            if((flags&Y_TICKS) !=0) xNumbers -= TICK_LENGTH;
            for (int i=0; i<=(i2-i1); i++) {
                double v = (i+i1)*step;
                int y = TOP_MARGIN + frame.height - (int)Math.round((v - yMin)*yScale);
                if ((flags&Y_GRID) != 0) {
                    ip.setColor(gridColor);
                    ip.drawLine(x1, y, x2, y);
                    ip.setColor(foregroundColor);
                }
                if ((flags&Y_TICKS) !=0) {
                    //ip.drawLine(x1, y, x1+TICK_LENGTH, y);
                    //ip.drawLine(x2, y, x2-TICK_LENGTH, y);
                    ip.drawLine(x1, y, x1-TICK_LENGTH, y);
                    ip.drawLine(x2, y, x2+TICK_LENGTH, y);
               }
                if ((flags&Y_NUMBERS) != 0) {
                    String s = IJ.d2s(v,digits);
                    int w = ip.getStringWidth(s);
                    if (w>maxNumWidth) maxNumWidth = w;
                    ip.drawString(s, xNumbers - w, y+fontMaxAscent/2+1);
                }
            }
        }
        if ((flags&Y_NUMBERS)==0) {                 //simply note y-axis min&max
            int digits = getDigits(yMin, yMax);
            String s = IJ.d2s(yMax, digits);
            int sw = ip.getStringWidth(s);
            if ((sw+4)>LEFT_MARGIN)
                ip.drawString(s, 4, TOP_MARGIN-4);
            else
                ip.drawString(s, LEFT_MARGIN-ip.getStringWidth(s)-4, TOP_MARGIN+10);
            s = IJ.d2s(yMin, digits);
            sw = ip.getStringWidth(s);
            if ((sw+4)>LEFT_MARGIN)
                ip.drawString(s, 4, TOP_MARGIN+frame.height);
            else
                ip.drawString(s, LEFT_MARGIN-ip.getStringWidth(s)-4, TOP_MARGIN+frame.height);
        }
        FontMetrics fm = ip.getFontMetrics();
        int x = LEFT_MARGIN;
        int y = y = TOP_MARGIN + frame.height + fm.getAscent() + 6;
        if ((flags&X_NUMBERS)==0) {                 //simply note x-axis min&max
            int digits = getDigits(xMin, xMax);
            ip.drawString(IJ.d2s(xMin,digits), x, y);
            String s = IJ.d2s(xMax,digits);
            ip.drawString(s, x + frame.width-ip.getStringWidth(s)+6, y);
        } else
            y += fm.getAscent();                    //space needed for x numbers
        ip.drawString(xLabel, LEFT_MARGIN+(frame.width-ip.getStringWidth(xLabel))/2, y+6+TICK_LENGTH);
        drawYLabel(yLabel,LEFT_MARGIN-maxNumWidth-4-TICK_LENGTH,TOP_MARGIN,frame.height, fm);
    }
   
    double niceNumber(double v) {   //the smallest "nice" number >= v. "Nice" numbers are .. 0.5, 1, 2, 5, 10, 20 ...
        double base = Math.pow(10,Math.floor(Math.log(v)/Math.log(10)-1.e-6));
        if (v > 5.0000001*base) return 10*base;
        else if (v > 2.0000001*base) return 5*base;
        else return 2*base;
    }

    void createImage() {
        if (ip!=null) return;
       int width = plotWidth+LEFT_MARGIN+RIGHT_MARGIN;
        int height = plotHeight+TOP_MARGIN+BOTTOM_MARGIN;
        ip = new ColorProcessor(width, height);
                ip.setColor(backgroundColor);
                ip.fill();
                ip.setColor(foregroundColor);
                ip.copyBits(ipSource.convertToRGB(),LEFT_MARGIN+frameLineWidth/2,TOP_MARGIN+frameLineWidth/2,Blitter.COPY);
                //ip.copyBits(ipSource.convertToRGB(),LEFT_MARGIN,TOP_MARGIN,Blitter.COPY);

    }
   
    int getDigits(double n1, double n2) {
        if (Math.round(n1)==n1 && Math.round(n2)==n2)
            return 0;
        else {
            n1 = Math.abs(n1);
            n2 = Math.abs(n2);
            double n = n1<n2&&n1>0.0?n1:n2;
            double diff = Math.abs(n2-n1);
            if (diff>0.0 && diff<n) n = diff;
            int digits = 1;
            if (n<10.0) digits = 2;
            if (n<0.01) digits = 3;
            if (n<0.001) digits = 4;
            if (n<0.0001) digits = 5;
            return digits;
        }
    }
   
    /** Draws the plot specified in the constructor. */
    public void draw() {
        int x, y;
        double v;
       
        if (plotDrawn)
            return;
        plotDrawn = true;
        createImage();
        setup();
       
        if (drawPending) {
            ip.setClipRect(frame);
            int xpoints[] = new int[nPoints];
            int ypoints[] = new int[nPoints];
            for (int i=0; i<nPoints; i++) {
                xpoints[i] = LEFT_MARGIN + (int)((xValues[i]-xMin)*xScale);
                ypoints[i] = TOP_MARGIN + frame.height - (int)((yValues[i]-yMin)*yScale);
            }
            drawPolyline(ip, xpoints, ypoints, nPoints);
            ip.setClipRect(null);
            if (this.errorBars != null) {
                xpoints = new int[2];
                ypoints = new int[2];
                for (int i=0; i<nPoints; i++) {
                    xpoints[0] = xpoints[1] = LEFT_MARGIN + (int)((xValues[i]-xMin)*xScale);
                    ypoints[0] = TOP_MARGIN + frame.height - (int)((yValues[i]-yMin-errorBars[i])*yScale);
                    ypoints[1] = TOP_MARGIN + frame.height - (int)((yValues[i]-yMin+errorBars[i])*yScale);
                    drawPolyline(ip, xpoints,ypoints, 2);
                }
            }
        }
       
        if (ip instanceof ColorProcessor)
            ip.setColor(foregroundColor);
        setLineWidth(frameLineWidth);
        ip.drawRect(frame.x, frame.y, frame.width+1, frame.height+1);
    }
   
    void drawPolyline(ImageProcessor ip, int[] x, int[] y, int n) {
        ip.moveTo(x[0], y[0]);
        for (int i=0; i<n; i++)
            ip.lineTo(x[i], y[i]);
    }
   
    void drawYLabel(String yLabel, int x, int y, int height, FontMetrics fm) {
        if (yLabel.equals(""))
            return;
        int w =  fm.stringWidth(yLabel) + 5;
        int h =  fm.getHeight() + 5;
        ImageProcessor label = new ColorProcessor(w, h);
        label.setColor(backgroundColor);
        label.fill();
        label.setColor(foregroundColor);
        label.setFont(font);
        label.setAntialiasedText(true);
        int descent = fm.getDescent();
        label.drawString(yLabel, 0, h-descent);
        label = label.rotateLeft();
        int y2 = y+(height-ip.getStringWidth(yLabel))/2;
        if (y2<y) y2 = y;
        int x2 = Math.max(x-h, 0);
        ip.insert(label, x2, y2);
    }
   
    ImageProcessor getBlankProcessor() {
        createImage();
        return ip;
    }
   
    String getCoordinates(int x, int y) {
        String text = "";
        if (!frame.contains(x, y))
            return text;
        if (fixedYScale || multiplePlots) { // display cursor location
            double xv = (x-LEFT_MARGIN)/xScale + xMin;
            double yv = (TOP_MARGIN+frameHeight-y)/yScale +yMin;
            text =  "X=" + IJ.d2s(xv,getDigits(xv,xv))+", Y=" + IJ.d2s(yv,getDigits(yv,yv));
        } else { // display x and f(x)
            int index = (int)((x-frame.x)/((double)frame.width/nPoints));
            if (index>0 && index<nPoints) {
                double xv = xValues[index];
                double yv = yValues[index];
                text = "X=" + IJ.d2s(xv,getDigits(xv,xv))+", Y=" + IJ.d2s(yv,getDigits(yv,yv));
            }
        }
        return text;
    }
   
    /** Returns the plot as an ImageProcessor. */
    public ImageProcessor getProcessor() {
        draw();
        return ip;
    }
   
    /** Returns the plot as an ImagePlus. */
    public ImagePlus getImagePlus() {
        draw();
        ImagePlus img = new ImagePlus(title, ip);
        Calibration cal = img.getCalibration();
        cal.xOrigin = LEFT_MARGIN;
        cal.yOrigin = TOP_MARGIN+frameHeight+yMin*yScale;
        cal.pixelWidth = 1.0/xScale;
        cal.pixelHeight = 1.0/yScale;
        cal.setInvertY(true);
        return img;
    }

    /** Displays the plot in a PlotWindow and returns a reference to the PlotWindow. */
    public void show() {
        draw();
        new ImagePlus(title,ip).show();
    }

}

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html