plotwindow.drawPlot(plot) incessant resizing

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

plotwindow.drawPlot(plot) incessant resizing

Fred Damen
Greetings,

I have a plugin that plots the statistics of an ROI through the frame
dimension.  And replots this information when the Roi is altered.  The
trouble is that if you resize the plotwindow and then cause the plot to be
redrawn (plotwindow.drawPlot(plot);) the plotwindow appears to insist upon
resizing the window somewhat asynchronously. Sometimes to the
interactively resized dimensions IRD, but mostly to default dimensions.
So a naive attempt was to query the plotwindow size and set it again after
the drawPlot. This results in the plotwindow more often being resized to
the IRD, alas not always...  Figuring that there was one of those race
conditions going on I put in a IJ.wait statement, then the plotwindow
mostly resizes to the IRD, albeit the plotwindow does not get updated
during this wait, and also results in massive flickering.  Moving the Roi
with the mouse shows the problem quicker than using the arrow keys, but
within less than 10 redraws the problem happens.  Is there a way to get
the plotwindow size not to change on a drawPlot?

This has been happening for the past couple of years on most of the
systems I run this on.  Look for the IJ.wait(10); in the below plugin.

Thanks in advance,

Fred

To reproduce:
imp = IJ.createImage("HyperStack", "32-bit grayscale-mode", 128, 128, 1,
1, 10);
imp.setRoi(new OvalRoi(42,52,42,33));

Run this plugin, resize the plotwindow, then move the Roi:

import ij.*;
import ij.plugin.*;
import ij.process.*;
import ij.gui.*;
import ij.util.Tools;
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import ij.measure.*;
import java.awt.Rectangle;

    /**
      This plugin continuously generates Frame-Dimension profile plots as
a selection
      is moved or resized through the XY Coordinate Plane.

      @author Fred Damen <[hidden email]>

      Version History:
      2018-04-01: Created
    */

 public class F_Profiler implements PlugIn,
                                    MouseListener,
                                    MouseMotionListener,
                                    MouseWheelListener,
                                    Measurements,
                                    KeyListener,
                                    WindowListener,
                                    ImageListener {
    ImagePlus img;
    PlotWindow pwin;
    public double[] x;
    public double[] y;
    public double[] ye;
    String xLabel;
    String yLabel;

    public void run(String arg) {
       img = IJ.getImage();
       int nf = img.getNFrames();
       if (nf<2) {
          IJ.showMessage("Dynamic F-Dimension Profiler", "This command
requires a HyperStack.");
          return;
          }

       img.getCanvas().addMouseListener(this);
       img.getCanvas().addMouseMotionListener(this);
       img.getCanvas().addKeyListener(this);
       img.getWindow().addMouseWheelListener(this);
       img.getWindow().addWindowListener(this);
       img.addImageListener(this);
       engaged = true;
       IJ.showStatus("F-Dimension Profile Engaged: "+img.getTitle());

       x  = new double[nf];
       y  = new double[nf];
       ye = new double[nf];
       String fu = img.getCalibration().getTimeUnit();
       try {
          ImageStack is = img.getStack();
          for(int f=0; f<nf; f++) {
             String[] strarr =
is.getSliceLabel(img.getStackIndex(1,1,f+1)).split(",|;",2)[0].split("
= |=| ",2);
             xLabel = strarr[0]+(fu!="" ? " ("+fu+")" : "");
             x[f] = Float.valueOf(strarr[1]).floatValue();
             //for(int ff=0; ff<f; ff++)
             //   if (x[f] == x[ff])
             //      throw new Throwable();
             //IJ.log("x["+f+"]="+x[f]);
             }
           }
       catch(Throwable e) {
           xLabel = "frame"+(fu!="" ? " ("+fu+")" : "");
           for(int f=0; f<nf; f++)
              x[f] = f;
           }

       yLabel = img.getTitle()+" ("+img.getCalibration().getValueUnit()+")";
       if (!updateProfile())
          return;
       positionPlotWindow();
       }

    boolean engaged = false;
    void disengage() {
       if (!engaged) return;
       if (img.getWindow() != null) {
          img.getCanvas().removeMouseListener(this);
          img.getCanvas().removeMouseMotionListener(this);
          img.getCanvas().removeKeyListener(this);
          img.getWindow().removeMouseWheelListener(this);
          img.getWindow().removeWindowListener(this);
          img.removeImageListener(this);
          }
       pwin = null;
       engaged = false;
       IJ.showStatus("F-Dimension Profile Disengaged");
       }


    boolean updateProfile() {
       Roi roi = img.getRoi();
       if (img == null || roi == null) {
          IJ.showStatus("Frame-Dimension Profiles running but nothing to
do");
          return true;
          }

       if ((pwin != null) && (!pwin.isVisible())) {
          IJ.log("F_Profiler: should not have reached here '"+pwin+"'");
          engaged = true;
          disengage();
          return false;
          }

       int nf = img.getNFrames();
       int cs = img.getZ();
       double[] yM = new double[nf];
       double[] ym = new double[nf];
       double[] ys = new double[nf];
       ImageStack is = img.getStack();
       Calibration cal = img.getCalibration();
       for(int f=0; f<nf; f++) {
          ImageProcessor ip = is.getProcessor(img.getStackIndex(1,cs,f+1));
          ip.setRoi(roi);
          ImageStatistics stats = ImageStatistics.getStatistics(ip,
MEAN+STD_DEV+MIN_MAX+MEDIAN, cal);
          y[f]  = stats.mean;
          ye[f] = stats.stdDev;
          yM[f] = stats.max;
          ym[f] = stats.min;
          ys[f] = stats.median;
          }

        Plot plot = new Plot("Frame Profile ("+img.getTitle()+")", xLabel, yLabel);
        plot.setFont(new Font("Comic Sans MS", Font.PLAIN, 20));
        plot.setXLabelFont(new Font("Comic Sans MS", Font.PLAIN, 24));
        plot.setYLabelFont(new Font("Comic Sans MS", Font.PLAIN, 24));

        plot.setColor(Color.blue);
        plot.setLineWidth(1);
        plot.addPoints(x,y,ye,Plot.X);
        plot.setColor(Color.red);
        plot.setLineWidth(4);
        plot.addPoints(x,y,Plot.X);

        plot.setColor(Color.green);
        plot.setLineWidth(2);
        plot.addPoints(x,ym,Plot.BOX);
        plot.addPoints(x,yM,Plot.BOX);
        plot.setColor(Color.black);
        plot.addPoints(x,ys,Plot.CIRCLE);
        plot.setLegend("stddev\nmean\nmax\nmin\nmedian",Plot.AUTO_POSITION);
        if (pwin==null) {
           pwin = plot.show();
           pwin.addWindowListener(this);
           }
        else {
           Dimension s = pwin.getSize();
           pwin.drawPlot(plot);
           pwin.setSize(s);
IJ.wait(10);
           pwin.setSize(s);
           }
        plot.setLimitsToFit(true);

        return true;
        }

   void positionPlotWindow() {
       IJ.wait(500);
       if (pwin==null || img==null) return;
       ImageWindow iwin = img.getWindow();
       if (iwin==null) return;
       Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
       Dimension plotSize = pwin.getSize();
       Dimension imageSize = iwin.getSize();
       if (plotSize.width==0 || imageSize.width==0) return;
       Point imageLoc = iwin.getLocation();
       int w = imageLoc.x+imageSize.width+10;
       if (w+plotSize.width>screen.width)
          w = screen.width-plotSize.width;
       pwin.setLocation(w, imageLoc.y);
       iwin.toFront();
       }

    public void mousePressed(MouseEvent e) {
       Roi roi = img.getRoi();
       int ix,iy;
       if (roi == null) {
          Point here = img.getCanvas().getCursorLoc();
          ix = here.x;
          iy = here.y;
          }
       else if (roi.getType() == Roi.POINT) {
          Rectangle bounds = roi.getBounds();
          ix = bounds.x;
          iy = bounds.y;
          }
       else {
          updateProfile();
          return;
          }

       int nf = img.getNFrames();
       int cs = img.getZ();
       ImageStack is = img.getStack();
       for(int f=0; f<nf; f++) {
          ImageProcessor ip = is.getProcessor(img.getStackIndex(1,cs,f+1));
          y[f]  = ip.getPixelValue(ix, iy);
          ye[f] = 0;
          }

        Plot plot = new Plot("Frame Profile ("+img.getTitle()+")", xLabel, yLabel);
        plot.setFont(new Font("Comic Sans MS", Font.PLAIN, 20));
        plot.setXLabelFont(new Font("Comic Sans MS", Font.PLAIN, 24));
        plot.setYLabelFont(new Font("Comic Sans MS", Font.PLAIN, 24));

        plot.setColor(Color.blue);
        plot.setLineWidth(4);

        Calibration cal = img.getCalibration();
        plot.setJustification(Plot.RIGHT);
        plot.addLabel(0.99,0.99,String.format("%.2f(%d), %.2f(%d), (%d)",
                      cal.getX(ix),ix,cal.getY(iy),iy,img.getT()));

        plot.addPoints(x,y,ye,Plot.X);
        if (pwin==null) {
           pwin = plot.show();
           pwin.addWindowListener(this);
           }
        else {
           Dimension s = pwin.getSize();
           pwin.drawPlot(plot);
           pwin.setSize(s);
           }
        plot.setLimitsToFit(true);;
        }

    public void mouseDragged(MouseEvent e)  { updateProfile(); }
    public void keyReleased(KeyEvent e)     { updateProfile(); }

    public void keyPressed(KeyEvent e)      {}
    public void keyTyped(KeyEvent e)        {}
    public void mouseReleased(MouseEvent e) {}
    public void mouseExited(MouseEvent e)   {}
    public void mouseClicked(MouseEvent e)  {}
    public void mouseEntered(MouseEvent e)  {}
    public void mouseMoved(MouseEvent e)    {}

    public void mouseWheelMoved(MouseWheelEvent e) { /* updateProfile(); */ }

    public void windowActivated(WindowEvent e)   {}
    public void windowClosed(WindowEvent e)      { disengage();}
    public void windowClosing(WindowEvent e)     { disengage();}
    public void windowDeactivated(WindowEvent e) {}
    public void windowDeiconified(WindowEvent e) {}
    public void windowIconified(WindowEvent e)   {}
    public void windowOpened(WindowEvent e)      {}

    public void imageClosed(ImagePlus imp) {}
    public void imageOpened(ImagePlus imp) {}
    public void imageUpdated(ImagePlus imp) { /* if (imp==img)
updateProfile(); */}
}

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

Re: plotwindow.drawPlot(plot) incessant resizing

Michael Schmid
Hi Fred,

there was no problem when I tried it, it works also after resizing the plot.
Nevertheless, there is an elegant way to make the plot inherit the size
of the previous one shown in the same PlotWindow:

   plot.useTemplate(previousPlot, Plot.COPY_SIZE);

You can also have it inherit other properties, such as the legend, axis
labels, style, or curves added by the user (who had used the buttons at
the bottom of the plot).
Just use a bitwise OR or the sum of the following flags:

COPY_SIZE    Flag for copying from a template: copy plot size
COPY_LABELS  Flag for copying from a template: copy style & text of axis
COPY_LEGEND  Flag for copying from a template: copy legend
COPY_AXIS_STYLE  Flag for copying from a template: copy axis style
COPY_CONTENTS_STYLE  Flag for copying from a template: copy contents
COPY_EXTRA_OBJECTS Flag for copying PlotObjects (curves...) from a
template if the template has more PlotObjects than the Plot to copy to.


In your case (I did not really try to understand your plugin), it seems
that the plot is supposed to react on changes of the Roi? Then there
might be an easier option, just implement the PlotMaker Interface.
The first 40 lines of the Profiler provide an example how to do this:

   https://github.com/imagej/imagej1/blob/master/ij/plugin/Profiler.java

If a PlotMaker is no option for you, there is also a RoiListener
interface, which tells you when a Roi has changed, so you don't need the
keyListener & MouseListener, and it will also detect changes of the Roi
caused by, e.g., menu commands.

   https://github.com/imagej/imagej1/blob/master/ij/gui/RoiListener.java



[BTW, I did not understand your other post on CTRL-SHIFT under Fedora;
is this about using the text tool on an image? Can you supply a
screenshot to explain (Plugins>Utilities>Capture Delayed)? Replies in
that thread, please]

Michael
________________________________________________________________
On 01.03.20 07:10, Fred Damen wrote:

> Greetings,
>
> I have a plugin that plots the statistics of an ROI through the frame
> dimension.  And replots this information when the Roi is altered.  The
> trouble is that if you resize the plotwindow and then cause the plot to be
> redrawn (plotwindow.drawPlot(plot);) the plotwindow appears to insist upon
> resizing the window somewhat asynchronously. Sometimes to the
> interactively resized dimensions IRD, but mostly to default dimensions.
> So a naive attempt was to query the plotwindow size and set it again after
> the drawPlot. This results in the plotwindow more often being resized to
> the IRD, alas not always...  Figuring that there was one of those race
> conditions going on I put in a IJ.wait statement, then the plotwindow
> mostly resizes to the IRD, albeit the plotwindow does not get updated
> during this wait, and also results in massive flickering.  Moving the Roi
> with the mouse shows the problem quicker than using the arrow keys, but
> within less than 10 redraws the problem happens.  Is there a way to get
> the plotwindow size not to change on a drawPlot?
>
> This has been happening for the past couple of years on most of the
> systems I run this on.  Look for the IJ.wait(10); in the below plugin.
>
> Thanks in advance,
>
> Fred
>
> To reproduce:
> imp = IJ.createImage("HyperStack", "32-bit grayscale-mode", 128, 128, 1,
> 1, 10);
> imp.setRoi(new OvalRoi(42,52,42,33));
>
> Run this plugin, resize the plotwindow, then move the Roi:
>
> import ij.*;
> import ij.plugin.*;
> import ij.process.*;
> import ij.gui.*;
> import ij.util.Tools;
> import java.io.*;
> import java.awt.*;
> import java.awt.event.*;
> import java.util.*;
> import ij.measure.*;
> import java.awt.Rectangle;
>
>      /**
>        This plugin continuously generates Frame-Dimension profile plots as
> a selection
>        is moved or resized through the XY Coordinate Plane.
>
>        @author Fred Damen <[hidden email]>
>
>        Version History:
>        2018-04-01: Created
>      */
>
>   public class F_Profiler implements PlugIn,
>                                      MouseListener,
>                                      MouseMotionListener,
>                                      MouseWheelListener,
>                                      Measurements,
>                                      KeyListener,
>                                      WindowListener,
>                                      ImageListener {
>      ImagePlus img;
>      PlotWindow pwin;
>      public double[] x;
>      public double[] y;
>      public double[] ye;
>      String xLabel;
>      String yLabel;
>
>      public void run(String arg) {
>         img = IJ.getImage();
>         int nf = img.getNFrames();
>         if (nf<2) {
>            IJ.showMessage("Dynamic F-Dimension Profiler", "This command
> requires a HyperStack.");
>            return;
>            }
>
>         img.getCanvas().addMouseListener(this);
>         img.getCanvas().addMouseMotionListener(this);
>         img.getCanvas().addKeyListener(this);
>         img.getWindow().addMouseWheelListener(this);
>         img.getWindow().addWindowListener(this);
>         img.addImageListener(this);
>         engaged = true;
>         IJ.showStatus("F-Dimension Profile Engaged: "+img.getTitle());
>
>         x  = new double[nf];
>         y  = new double[nf];
>         ye = new double[nf];
>         String fu = img.getCalibration().getTimeUnit();
>         try {
>            ImageStack is = img.getStack();
>            for(int f=0; f<nf; f++) {
>               String[] strarr =
> is.getSliceLabel(img.getStackIndex(1,1,f+1)).split(",|;",2)[0].split("
> = |=| ",2);
>               xLabel = strarr[0]+(fu!="" ? " ("+fu+")" : "");
>               x[f] = Float.valueOf(strarr[1]).floatValue();
>               //for(int ff=0; ff<f; ff++)
>               //   if (x[f] == x[ff])
>               //      throw new Throwable();
>               //IJ.log("x["+f+"]="+x[f]);
>               }
>             }
>         catch(Throwable e) {
>             xLabel = "frame"+(fu!="" ? " ("+fu+")" : "");
>             for(int f=0; f<nf; f++)
>                x[f] = f;
>             }
>
>         yLabel = img.getTitle()+" ("+img.getCalibration().getValueUnit()+")";
>         if (!updateProfile())
>            return;
>         positionPlotWindow();
>         }
>
>      boolean engaged = false;
>      void disengage() {
>         if (!engaged) return;
>         if (img.getWindow() != null) {
>            img.getCanvas().removeMouseListener(this);
>            img.getCanvas().removeMouseMotionListener(this);
>            img.getCanvas().removeKeyListener(this);
>            img.getWindow().removeMouseWheelListener(this);
>            img.getWindow().removeWindowListener(this);
>            img.removeImageListener(this);
>            }
>         pwin = null;
>         engaged = false;
>         IJ.showStatus("F-Dimension Profile Disengaged");
>         }
>
>
>      boolean updateProfile() {
>         Roi roi = img.getRoi();
>         if (img == null || roi == null) {
>            IJ.showStatus("Frame-Dimension Profiles running but nothing to
> do");
>            return true;
>            }
>
>         if ((pwin != null) && (!pwin.isVisible())) {
>            IJ.log("F_Profiler: should not have reached here '"+pwin+"'");
>            engaged = true;
>            disengage();
>            return false;
>            }
>
>         int nf = img.getNFrames();
>         int cs = img.getZ();
>         double[] yM = new double[nf];
>         double[] ym = new double[nf];
>         double[] ys = new double[nf];
>         ImageStack is = img.getStack();
>         Calibration cal = img.getCalibration();
>         for(int f=0; f<nf; f++) {
>            ImageProcessor ip = is.getProcessor(img.getStackIndex(1,cs,f+1));
>            ip.setRoi(roi);
>            ImageStatistics stats = ImageStatistics.getStatistics(ip,
> MEAN+STD_DEV+MIN_MAX+MEDIAN, cal);
>            y[f]  = stats.mean;
>            ye[f] = stats.stdDev;
>            yM[f] = stats.max;
>            ym[f] = stats.min;
>            ys[f] = stats.median;
>            }
>
> Plot plot = new Plot("Frame Profile ("+img.getTitle()+")", xLabel, yLabel);
>          plot.setFont(new Font("Comic Sans MS", Font.PLAIN, 20));
>          plot.setXLabelFont(new Font("Comic Sans MS", Font.PLAIN, 24));
>          plot.setYLabelFont(new Font("Comic Sans MS", Font.PLAIN, 24));
>
>          plot.setColor(Color.blue);
>          plot.setLineWidth(1);
>          plot.addPoints(x,y,ye,Plot.X);
>          plot.setColor(Color.red);
>          plot.setLineWidth(4);
>          plot.addPoints(x,y,Plot.X);
>
>          plot.setColor(Color.green);
>          plot.setLineWidth(2);
>          plot.addPoints(x,ym,Plot.BOX);
>          plot.addPoints(x,yM,Plot.BOX);
>          plot.setColor(Color.black);
>          plot.addPoints(x,ys,Plot.CIRCLE);
>          plot.setLegend("stddev\nmean\nmax\nmin\nmedian",Plot.AUTO_POSITION);
> if (pwin==null) {
>             pwin = plot.show();
>             pwin.addWindowListener(this);
>             }
>          else {
>             Dimension s = pwin.getSize();
>             pwin.drawPlot(plot);
>             pwin.setSize(s);
> IJ.wait(10);
>             pwin.setSize(s);
>             }
>          plot.setLimitsToFit(true);
>
>          return true;
>          }
>
>     void positionPlotWindow() {
>         IJ.wait(500);
>         if (pwin==null || img==null) return;
>         ImageWindow iwin = img.getWindow();
>         if (iwin==null) return;
>         Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
>         Dimension plotSize = pwin.getSize();
>         Dimension imageSize = iwin.getSize();
>         if (plotSize.width==0 || imageSize.width==0) return;
>         Point imageLoc = iwin.getLocation();
>         int w = imageLoc.x+imageSize.width+10;
>         if (w+plotSize.width>screen.width)
>            w = screen.width-plotSize.width;
>         pwin.setLocation(w, imageLoc.y);
>         iwin.toFront();
>         }
>
>      public void mousePressed(MouseEvent e) {
>         Roi roi = img.getRoi();
>         int ix,iy;
>         if (roi == null) {
>            Point here = img.getCanvas().getCursorLoc();
>            ix = here.x;
>            iy = here.y;
>            }
>         else if (roi.getType() == Roi.POINT) {
>            Rectangle bounds = roi.getBounds();
>            ix = bounds.x;
>            iy = bounds.y;
>            }
>         else {
>            updateProfile();
>            return;
>            }
>
>         int nf = img.getNFrames();
>         int cs = img.getZ();
>         ImageStack is = img.getStack();
>         for(int f=0; f<nf; f++) {
>            ImageProcessor ip = is.getProcessor(img.getStackIndex(1,cs,f+1));
>            y[f]  = ip.getPixelValue(ix, iy);
>            ye[f] = 0;
>            }
>
> Plot plot = new Plot("Frame Profile ("+img.getTitle()+")", xLabel, yLabel);
>          plot.setFont(new Font("Comic Sans MS", Font.PLAIN, 20));
>          plot.setXLabelFont(new Font("Comic Sans MS", Font.PLAIN, 24));
>          plot.setYLabelFont(new Font("Comic Sans MS", Font.PLAIN, 24));
>
>          plot.setColor(Color.blue);
>          plot.setLineWidth(4);
>
>          Calibration cal = img.getCalibration();
>          plot.setJustification(Plot.RIGHT);
>          plot.addLabel(0.99,0.99,String.format("%.2f(%d), %.2f(%d), (%d)",
>                        cal.getX(ix),ix,cal.getY(iy),iy,img.getT()));
>
>          plot.addPoints(x,y,ye,Plot.X);
> if (pwin==null) {
>             pwin = plot.show();
>             pwin.addWindowListener(this);
>             }
>          else {
>             Dimension s = pwin.getSize();
>             pwin.drawPlot(plot);
>             pwin.setSize(s);
>             }
>          plot.setLimitsToFit(true);;
>          }
>
>      public void mouseDragged(MouseEvent e)  { updateProfile(); }
>      public void keyReleased(KeyEvent e)     { updateProfile(); }
>
>      public void keyPressed(KeyEvent e)      {}
>      public void keyTyped(KeyEvent e)        {}
>      public void mouseReleased(MouseEvent e) {}
>      public void mouseExited(MouseEvent e)   {}
>      public void mouseClicked(MouseEvent e)  {}
>      public void mouseEntered(MouseEvent e)  {}
>      public void mouseMoved(MouseEvent e)    {}
>
>      public void mouseWheelMoved(MouseWheelEvent e) { /* updateProfile(); */ }
>
>      public void windowActivated(WindowEvent e)   {}
>      public void windowClosed(WindowEvent e)      { disengage();}
>      public void windowClosing(WindowEvent e)     { disengage();}
>      public void windowDeactivated(WindowEvent e) {}
>      public void windowDeiconified(WindowEvent e) {}
>      public void windowIconified(WindowEvent e)   {}
>      public void windowOpened(WindowEvent e)      {}
>
>      public void imageClosed(ImagePlus imp) {}
>      public void imageOpened(ImagePlus imp) {}
>      public void imageUpdated(ImagePlus imp) { /* if (imp==img)
> updateProfile(); */}
> }
>
> --
> 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: plotwindow.drawPlot(plot) incessant resizing

Fred Damen
Greetings Michael,

A mute point now, but, to reproduce, create hyperstack, create roi, start
plugin, resize plotwindow, move the roi a dozen times.

The plot.userTemplate works great; aggravation level plummets...

For the PlotMaker example that you gave, what instigates the drawing of
the next plot. I assume that getPlot is called by PlotWindow, but how to
setup the trigger?

For the RoiListener, who calls roiModified, i.e., static or instance?  I
found out the hard way that the ImageListener methods were called when any
/ all imageplus objects were affected; ugly race conditions when trying to
close a list of images... use WindowListener instead...

The attached plugin serves the same general purpose as the ProfilePlot,
albeit in the frame direction.  If you collected the same volume (stack of
slices) repeatedly and you wanted to know if / how the signal changes
through the repeats.

Thanks,

Fred

On Mon, March 2, 2020 4:32 am, Michael Schmid wrote:

> Hi Fred,
>
> there was no problem when I tried it, it works also after resizing the
> plot.
> Nevertheless, there is an elegant way to make the plot inherit the size
> of the previous one shown in the same PlotWindow:
>
>    plot.useTemplate(previousPlot, Plot.COPY_SIZE);
>
> You can also have it inherit other properties, such as the legend, axis
> labels, style, or curves added by the user (who had used the buttons at
> the bottom of the plot).
> Just use a bitwise OR or the sum of the following flags:
>
> COPY_SIZE    Flag for copying from a template: copy plot size
> COPY_LABELS  Flag for copying from a template: copy style & text of axis
> COPY_LEGEND  Flag for copying from a template: copy legend
> COPY_AXIS_STYLE  Flag for copying from a template: copy axis style
> COPY_CONTENTS_STYLE  Flag for copying from a template: copy contents
> COPY_EXTRA_OBJECTS Flag for copying PlotObjects (curves...) from a
> template if the template has more PlotObjects than the Plot to copy to.
>
>
> In your case (I did not really try to understand your plugin), it seems
> that the plot is supposed to react on changes of the Roi? Then there
> might be an easier option, just implement the PlotMaker Interface.
> The first 40 lines of the Profiler provide an example how to do this:
>
>    https://github.com/imagej/imagej1/blob/master/ij/plugin/Profiler.java
>
> If a PlotMaker is no option for you, there is also a RoiListener
> interface, which tells you when a Roi has changed, so you don't need the
> keyListener & MouseListener, and it will also detect changes of the Roi
> caused by, e.g., menu commands.
>
>    https://github.com/imagej/imagej1/blob/master/ij/gui/RoiListener.java
>
>
>
> [BTW, I did not understand your other post on CTRL-SHIFT under Fedora;
> is this about using the text tool on an image? Can you supply a
> screenshot to explain (Plugins>Utilities>Capture Delayed)? Replies in
> that thread, please]
>
> Michael
> ________________________________________________________________
> On 01.03.20 07:10, Fred Damen wrote:
>> Greetings,
>>
>> I have a plugin that plots the statistics of an ROI through the frame
>> dimension.  And replots this information when the Roi is altered.  The
>> trouble is that if you resize the plotwindow and then cause the plot to
>> be
>> redrawn (plotwindow.drawPlot(plot);) the plotwindow appears to insist
>> upon
>> resizing the window somewhat asynchronously. Sometimes to the
>> interactively resized dimensions IRD, but mostly to default dimensions.
>> So a naive attempt was to query the plotwindow size and set it again
>> after
>> the drawPlot. This results in the plotwindow more often being resized to
>> the IRD, alas not always...  Figuring that there was one of those race
>> conditions going on I put in a IJ.wait statement, then the plotwindow
>> mostly resizes to the IRD, albeit the plotwindow does not get updated
>> during this wait, and also results in massive flickering.  Moving the
>> Roi
>> with the mouse shows the problem quicker than using the arrow keys, but
>> within less than 10 redraws the problem happens.  Is there a way to get
>> the plotwindow size not to change on a drawPlot?
>>
>> This has been happening for the past couple of years on most of the
>> systems I run this on.  Look for the IJ.wait(10); in the below plugin.
>>
>> Thanks in advance,
>>
>> Fred
>>
>> To reproduce:
>> imp = IJ.createImage("HyperStack", "32-bit grayscale-mode", 128, 128, 1,
>> 1, 10);
>> imp.setRoi(new OvalRoi(42,52,42,33));
>>
>> Run this plugin, resize the plotwindow, then move the Roi:
>>
>> import ij.*;
>> import ij.plugin.*;
>> import ij.process.*;
>> import ij.gui.*;
>> import ij.util.Tools;
>> import java.io.*;
>> import java.awt.*;
>> import java.awt.event.*;
>> import java.util.*;
>> import ij.measure.*;
>> import java.awt.Rectangle;
>>
>>      /**
>>        This plugin continuously generates Frame-Dimension profile plots
>> as
>> a selection
>>        is moved or resized through the XY Coordinate Plane.
>>
>>        @author Fred Damen <[hidden email]>
>>
>>        Version History:
>>        2018-04-01: Created
>>      */
>>
>>   public class F_Profiler implements PlugIn,
>>                                      MouseListener,
>>                                      MouseMotionListener,
>>                                      MouseWheelListener,
>>                                      Measurements,
>>                                      KeyListener,
>>                                      WindowListener,
>>                                      ImageListener {
>>      ImagePlus img;
>>      PlotWindow pwin;
>>      public double[] x;
>>      public double[] y;
>>      public double[] ye;
>>      String xLabel;
>>      String yLabel;
>>
>>      public void run(String arg) {
>>         img = IJ.getImage();
>>         int nf = img.getNFrames();
>>         if (nf<2) {
>>            IJ.showMessage("Dynamic F-Dimension Profiler", "This command
>> requires a HyperStack.");
>>            return;
>>            }
>>
>>         img.getCanvas().addMouseListener(this);
>>         img.getCanvas().addMouseMotionListener(this);
>>         img.getCanvas().addKeyListener(this);
>>         img.getWindow().addMouseWheelListener(this);
>>         img.getWindow().addWindowListener(this);
>>         img.addImageListener(this);
>>         engaged = true;
>>         IJ.showStatus("F-Dimension Profile Engaged: "+img.getTitle());
>>
>>         x  = new double[nf];
>>         y  = new double[nf];
>>         ye = new double[nf];
>>         String fu = img.getCalibration().getTimeUnit();
>>         try {
>>            ImageStack is = img.getStack();
>>            for(int f=0; f<nf; f++) {
>>               String[] strarr =
>> is.getSliceLabel(img.getStackIndex(1,1,f+1)).split(",|;",2)[0].split("
>> = |=| ",2);
>>               xLabel = strarr[0]+(fu!="" ? " ("+fu+")" : "");
>>               x[f] = Float.valueOf(strarr[1]).floatValue();
>>               //for(int ff=0; ff<f; ff++)
>>               //   if (x[f] == x[ff])
>>               //      throw new Throwable();
>>               //IJ.log("x["+f+"]="+x[f]);
>>               }
>>             }
>>         catch(Throwable e) {
>>             xLabel = "frame"+(fu!="" ? " ("+fu+")" : "");
>>             for(int f=0; f<nf; f++)
>>                x[f] = f;
>>             }
>>
>>         yLabel = img.getTitle()+"
>> ("+img.getCalibration().getValueUnit()+")";
>>         if (!updateProfile())
>>            return;
>>         positionPlotWindow();
>>         }
>>
>>      boolean engaged = false;
>>      void disengage() {
>>         if (!engaged) return;
>>         if (img.getWindow() != null) {
>>            img.getCanvas().removeMouseListener(this);
>>            img.getCanvas().removeMouseMotionListener(this);
>>            img.getCanvas().removeKeyListener(this);
>>            img.getWindow().removeMouseWheelListener(this);
>>            img.getWindow().removeWindowListener(this);
>>            img.removeImageListener(this);
>>            }
>>         pwin = null;
>>         engaged = false;
>>         IJ.showStatus("F-Dimension Profile Disengaged");
>>         }
>>
>>
>>      boolean updateProfile() {
>>         Roi roi = img.getRoi();
>>         if (img == null || roi == null) {
>>            IJ.showStatus("Frame-Dimension Profiles running but nothing
>> to
>> do");
>>            return true;
>>            }
>>
>>         if ((pwin != null) && (!pwin.isVisible())) {
>>            IJ.log("F_Profiler: should not have reached here
>> '"+pwin+"'");
>>            engaged = true;
>>            disengage();
>>            return false;
>>            }
>>
>>         int nf = img.getNFrames();
>>         int cs = img.getZ();
>>         double[] yM = new double[nf];
>>         double[] ym = new double[nf];
>>         double[] ys = new double[nf];
>>         ImageStack is = img.getStack();
>>         Calibration cal = img.getCalibration();
>>         for(int f=0; f<nf; f++) {
>>            ImageProcessor ip =
>> is.getProcessor(img.getStackIndex(1,cs,f+1));
>>            ip.setRoi(roi);
>>            ImageStatistics stats = ImageStatistics.getStatistics(ip,
>> MEAN+STD_DEV+MIN_MAX+MEDIAN, cal);
>>            y[f]  = stats.mean;
>>            ye[f] = stats.stdDev;
>>            yM[f] = stats.max;
>>            ym[f] = stats.min;
>>            ys[f] = stats.median;
>>            }
>>
>> Plot plot = new Plot("Frame Profile ("+img.getTitle()+")", xLabel,
>> yLabel);
>>          plot.setFont(new Font("Comic Sans MS", Font.PLAIN, 20));
>>          plot.setXLabelFont(new Font("Comic Sans MS", Font.PLAIN, 24));
>>          plot.setYLabelFont(new Font("Comic Sans MS", Font.PLAIN, 24));
>>
>>          plot.setColor(Color.blue);
>>          plot.setLineWidth(1);
>>          plot.addPoints(x,y,ye,Plot.X);
>>          plot.setColor(Color.red);
>>          plot.setLineWidth(4);
>>          plot.addPoints(x,y,Plot.X);
>>
>>          plot.setColor(Color.green);
>>          plot.setLineWidth(2);
>>          plot.addPoints(x,ym,Plot.BOX);
>>          plot.addPoints(x,yM,Plot.BOX);
>>          plot.setColor(Color.black);
>>          plot.addPoints(x,ys,Plot.CIRCLE);
>>          plot.setLegend("stddev\nmean\nmax\nmin\nmedian",Plot.AUTO_POSITION);
>> if (pwin==null) {
>>             pwin = plot.show();
>>             pwin.addWindowListener(this);
>>             }
>>          else {
>>             Dimension s = pwin.getSize();
>>             pwin.drawPlot(plot);
>>             pwin.setSize(s);
>> IJ.wait(10);
>>             pwin.setSize(s);
>>             }
>>          plot.setLimitsToFit(true);
>>
>>          return true;
>>          }
>>
>>     void positionPlotWindow() {
>>         IJ.wait(500);
>>         if (pwin==null || img==null) return;
>>         ImageWindow iwin = img.getWindow();
>>         if (iwin==null) return;
>>         Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
>>         Dimension plotSize = pwin.getSize();
>>         Dimension imageSize = iwin.getSize();
>>         if (plotSize.width==0 || imageSize.width==0) return;
>>         Point imageLoc = iwin.getLocation();
>>         int w = imageLoc.x+imageSize.width+10;
>>         if (w+plotSize.width>screen.width)
>>            w = screen.width-plotSize.width;
>>         pwin.setLocation(w, imageLoc.y);
>>         iwin.toFront();
>>         }
>>
>>      public void mousePressed(MouseEvent e) {
>>         Roi roi = img.getRoi();
>>         int ix,iy;
>>         if (roi == null) {
>>            Point here = img.getCanvas().getCursorLoc();
>>            ix = here.x;
>>            iy = here.y;
>>            }
>>         else if (roi.getType() == Roi.POINT) {
>>            Rectangle bounds = roi.getBounds();
>>            ix = bounds.x;
>>            iy = bounds.y;
>>            }
>>         else {
>>            updateProfile();
>>            return;
>>            }
>>
>>         int nf = img.getNFrames();
>>         int cs = img.getZ();
>>         ImageStack is = img.getStack();
>>         for(int f=0; f<nf; f++) {
>>            ImageProcessor ip =
>> is.getProcessor(img.getStackIndex(1,cs,f+1));
>>            y[f]  = ip.getPixelValue(ix, iy);
>>            ye[f] = 0;
>>            }
>>
>> Plot plot = new Plot("Frame Profile ("+img.getTitle()+")", xLabel,
>> yLabel);
>>          plot.setFont(new Font("Comic Sans MS", Font.PLAIN, 20));
>>          plot.setXLabelFont(new Font("Comic Sans MS", Font.PLAIN, 24));
>>          plot.setYLabelFont(new Font("Comic Sans MS", Font.PLAIN, 24));
>>
>>          plot.setColor(Color.blue);
>>          plot.setLineWidth(4);
>>
>>          Calibration cal = img.getCalibration();
>>          plot.setJustification(Plot.RIGHT);
>>          plot.addLabel(0.99,0.99,String.format("%.2f(%d), %.2f(%d),
>> (%d)",
>>                        cal.getX(ix),ix,cal.getY(iy),iy,img.getT()));
>>
>>          plot.addPoints(x,y,ye,Plot.X);
>> if (pwin==null) {
>>             pwin = plot.show();
>>             pwin.addWindowListener(this);
>>             }
>>          else {
>>             Dimension s = pwin.getSize();
>>             pwin.drawPlot(plot);
>>             pwin.setSize(s);
>>             }
>>          plot.setLimitsToFit(true);;
>>          }
>>
>>      public void mouseDragged(MouseEvent e)  { updateProfile(); }
>>      public void keyReleased(KeyEvent e)     { updateProfile(); }
>>
>>      public void keyPressed(KeyEvent e)      {}
>>      public void keyTyped(KeyEvent e)        {}
>>      public void mouseReleased(MouseEvent e) {}
>>      public void mouseExited(MouseEvent e)   {}
>>      public void mouseClicked(MouseEvent e)  {}
>>      public void mouseEntered(MouseEvent e)  {}
>>      public void mouseMoved(MouseEvent e)    {}
>>
>>      public void mouseWheelMoved(MouseWheelEvent e) { /*
>> updateProfile(); */ }
>>
>>      public void windowActivated(WindowEvent e)   {}
>>      public void windowClosed(WindowEvent e)      { disengage();}
>>      public void windowClosing(WindowEvent e)     { disengage();}
>>      public void windowDeactivated(WindowEvent e) {}
>>      public void windowDeiconified(WindowEvent e) {}
>>      public void windowIconified(WindowEvent e)   {}
>>      public void windowOpened(WindowEvent e)      {}
>>
>>      public void imageClosed(ImagePlus imp) {}
>>      public void imageOpened(ImagePlus imp) {}
>>      public void imageUpdated(ImagePlus imp) { /* if (imp==img)
>> updateProfile(); */}
>> }
>>
>> --
>> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>>
>
> --
> 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: plotwindow.drawPlot(plot) incessant resizing

Michael Schmid
Hi Fred,

concerning the PlotMaker interface: Whenever the contents or the Roi of
the source image is updated, the
   public Plot getPlot()
method of the PlotMaker is called.
It automatically specifies the following 'useTemplate' flags (in
addition to any other defined by the plot):
   Plot.COPY_SIZE | Plot.COPY_LABELS | Plot.COPY_AXIS_STYLE |
   Plot.COPY_CONTENTS_STYLE | Plot.COPY_LEGEND | Plot.COPY_EXTRA_OBJECTS

The 'source image' is the one that the user plugin defines in
   public ImagePlus getSourceImage()

The plot.setPlotMaker(this) is not static, i.e., you have to call it
with the first plot that you create and show. Currently, I think there
is no simple way to start live plotting of a PlotMaker from java; the
plot is 'live' only if the user presses the 'live' button. If live
plotting from the start is desired, we would need a small modification
of ImageJ.


Concerning the RoiListener: The method
   Roi.addRoiListener(this)
is static, so a RoiListener's roiModified gets calls from all Rois,
whatever image they belong to. The image is passed with
   roiModified(ImagePlus img, int id)
Based on the imp, you can select whether the event is of interest for
your plugin or not. That's the same as for an ImageListener, where you
should also which ImagePlus was affected (closed/opened/updated).

Therfore, for both, the ImageListener and RoiListener interfaces, make
sure to de-register with the corresponding
   Roi.removeRoiListener(this);
   ImagePlus.removeImageListener(this);
Otherwise, your plugin will remain active in the background forever
(until ImageJ closes) and receive the events, even if you thought it has
ended all activity. In case of doubt, it does not hurt to call a
remove...Listener too often (You can also call it without having
registered with add...Listener).

For the ImageListener interface, in the 1.52u daily build, the static method
   ImagePlus.logImageListeners()
can be used to check for plugins that have forgotten to de-register. You
can easily call it from Javascript. There is no such method for
RoiListeners (yet?).


Best,

Michael
________________________________________________________________
On 03.03.20 05:26, Fred Damen wrote:

> Greetings Michael,
>
> A mute point now, but, to reproduce, create hyperstack, create roi, start
> plugin, resize plotwindow, move the roi a dozen times.
>
> The plot.userTemplate works great; aggravation level plummets...
>
> For the PlotMaker example that you gave, what instigates the drawing of
> the next plot. I assume that getPlot is called by PlotWindow, but how to
> setup the trigger?
>
> For the RoiListener, who calls roiModified, i.e., static or instance?  I
> found out the hard way that the ImageListener methods were called when any
> / all imageplus objects were affected; ugly race conditions when trying to
> close a list of images... use WindowListener instead...
>
> The attached plugin serves the same general purpose as the ProfilePlot,
> albeit in the frame direction.  If you collected the same volume (stack of
> slices) repeatedly and you wanted to know if / how the signal changes
> through the repeats.
>
> Thanks,
>
> Fred
>
> On Mon, March 2, 2020 4:32 am, Michael Schmid wrote:
>> Hi Fred,
>>
>> there was no problem when I tried it, it works also after resizing the
>> plot.
>> Nevertheless, there is an elegant way to make the plot inherit the size
>> of the previous one shown in the same PlotWindow:
>>
>>     plot.useTemplate(previousPlot, Plot.COPY_SIZE);
>>
>> You can also have it inherit other properties, such as the legend, axis
>> labels, style, or curves added by the user (who had used the buttons at
>> the bottom of the plot).
>> Just use a bitwise OR or the sum of the following flags:
>>
>> COPY_SIZE    Flag for copying from a template: copy plot size
>> COPY_LABELS  Flag for copying from a template: copy style & text of axis
>> COPY_LEGEND  Flag for copying from a template: copy legend
>> COPY_AXIS_STYLE  Flag for copying from a template: copy axis style
>> COPY_CONTENTS_STYLE  Flag for copying from a template: copy contents
>> COPY_EXTRA_OBJECTS Flag for copying PlotObjects (curves...) from a
>> template if the template has more PlotObjects than the Plot to copy to.
>>
>>
>> In your case (I did not really try to understand your plugin), it seems
>> that the plot is supposed to react on changes of the Roi? Then there
>> might be an easier option, just implement the PlotMaker Interface.
>> The first 40 lines of the Profiler provide an example how to do this:
>>
>>     https://github.com/imagej/imagej1/blob/master/ij/plugin/Profiler.java
>>
>> If a PlotMaker is no option for you, there is also a RoiListener
>> interface, which tells you when a Roi has changed, so you don't need the
>> keyListener & MouseListener, and it will also detect changes of the Roi
>> caused by, e.g., menu commands.
>>
>>     https://github.com/imagej/imagej1/blob/master/ij/gui/RoiListener.java
>>
>>
>>
>> [BTW, I did not understand your other post on CTRL-SHIFT under Fedora;
>> is this about using the text tool on an image? Can you supply a
>> screenshot to explain (Plugins>Utilities>Capture Delayed)? Replies in
>> that thread, please]
>>
>> Michael
>> ________________________________________________________________
>> On 01.03.20 07:10, Fred Damen wrote:
>>> Greetings,
>>>
>>> I have a plugin that plots the statistics of an ROI through the frame
>>> dimension.  And replots this information when the Roi is altered.  The
>>> trouble is that if you resize the plotwindow and then cause the plot to
>>> be
>>> redrawn (plotwindow.drawPlot(plot);) the plotwindow appears to insist
>>> upon
>>> resizing the window somewhat asynchronously. Sometimes to the
>>> interactively resized dimensions IRD, but mostly to default dimensions.
>>> So a naive attempt was to query the plotwindow size and set it again
>>> after
>>> the drawPlot. This results in the plotwindow more often being resized to
>>> the IRD, alas not always...  Figuring that there was one of those race
>>> conditions going on I put in a IJ.wait statement, then the plotwindow
>>> mostly resizes to the IRD, albeit the plotwindow does not get updated
>>> during this wait, and also results in massive flickering.  Moving the
>>> Roi
>>> with the mouse shows the problem quicker than using the arrow keys, but
>>> within less than 10 redraws the problem happens.  Is there a way to get
>>> the plotwindow size not to change on a drawPlot?
>>>
>>> This has been happening for the past couple of years on most of the
>>> systems I run this on.  Look for the IJ.wait(10); in the below plugin.
>>>
>>> Thanks in advance,
>>>
>>> Fred
>>>
>>> To reproduce:
>>> imp = IJ.createImage("HyperStack", "32-bit grayscale-mode", 128, 128, 1,
>>> 1, 10);
>>> imp.setRoi(new OvalRoi(42,52,42,33));
>>>
>>> Run this plugin, resize the plotwindow, then move the Roi:
>>>
>>> import ij.*;
>>> import ij.plugin.*;
>>> import ij.process.*;
>>> import ij.gui.*;
>>> import ij.util.Tools;
>>> import java.io.*;
>>> import java.awt.*;
>>> import java.awt.event.*;
>>> import java.util.*;
>>> import ij.measure.*;
>>> import java.awt.Rectangle;
>>>
>>>       /**
>>>         This plugin continuously generates Frame-Dimension profile plots
>>> as
>>> a selection
>>>         is moved or resized through the XY Coordinate Plane.
>>>
>>>         @author Fred Damen <[hidden email]>
>>>
>>>         Version History:
>>>         2018-04-01: Created
>>>       */
>>>
>>>    public class F_Profiler implements PlugIn,
>>>                                       MouseListener,
>>>                                       MouseMotionListener,
>>>                                       MouseWheelListener,
>>>                                       Measurements,
>>>                                       KeyListener,
>>>                                       WindowListener,
>>>                                       ImageListener {
>>>       ImagePlus img;
>>>       PlotWindow pwin;
>>>       public double[] x;
>>>       public double[] y;
>>>       public double[] ye;
>>>       String xLabel;
>>>       String yLabel;
>>>
>>>       public void run(String arg) {
>>>          img = IJ.getImage();
>>>          int nf = img.getNFrames();
>>>          if (nf<2) {
>>>             IJ.showMessage("Dynamic F-Dimension Profiler", "This command
>>> requires a HyperStack.");
>>>             return;
>>>             }
>>>
>>>          img.getCanvas().addMouseListener(this);
>>>          img.getCanvas().addMouseMotionListener(this);
>>>          img.getCanvas().addKeyListener(this);
>>>          img.getWindow().addMouseWheelListener(this);
>>>          img.getWindow().addWindowListener(this);
>>>          img.addImageListener(this);
>>>          engaged = true;
>>>          IJ.showStatus("F-Dimension Profile Engaged: "+img.getTitle());
>>>
>>>          x  = new double[nf];
>>>          y  = new double[nf];
>>>          ye = new double[nf];
>>>          String fu = img.getCalibration().getTimeUnit();
>>>          try {
>>>             ImageStack is = img.getStack();
>>>             for(int f=0; f<nf; f++) {
>>>                String[] strarr =
>>> is.getSliceLabel(img.getStackIndex(1,1,f+1)).split(",|;",2)[0].split("
>>> = |=| ",2);
>>>                xLabel = strarr[0]+(fu!="" ? " ("+fu+")" : "");
>>>                x[f] = Float.valueOf(strarr[1]).floatValue();
>>>                //for(int ff=0; ff<f; ff++)
>>>                //   if (x[f] == x[ff])
>>>                //      throw new Throwable();
>>>                //IJ.log("x["+f+"]="+x[f]);
>>>                }
>>>              }
>>>          catch(Throwable e) {
>>>              xLabel = "frame"+(fu!="" ? " ("+fu+")" : "");
>>>              for(int f=0; f<nf; f++)
>>>                 x[f] = f;
>>>              }
>>>
>>>          yLabel = img.getTitle()+"
>>> ("+img.getCalibration().getValueUnit()+")";
>>>          if (!updateProfile())
>>>             return;
>>>          positionPlotWindow();
>>>          }
>>>
>>>       boolean engaged = false;
>>>       void disengage() {
>>>          if (!engaged) return;
>>>          if (img.getWindow() != null) {
>>>             img.getCanvas().removeMouseListener(this);
>>>             img.getCanvas().removeMouseMotionListener(this);
>>>             img.getCanvas().removeKeyListener(this);
>>>             img.getWindow().removeMouseWheelListener(this);
>>>             img.getWindow().removeWindowListener(this);
>>>             img.removeImageListener(this);
>>>             }
>>>          pwin = null;
>>>          engaged = false;
>>>          IJ.showStatus("F-Dimension Profile Disengaged");
>>>          }
>>>
>>>
>>>       boolean updateProfile() {
>>>          Roi roi = img.getRoi();
>>>          if (img == null || roi == null) {
>>>             IJ.showStatus("Frame-Dimension Profiles running but nothing
>>> to
>>> do");
>>>             return true;
>>>             }
>>>
>>>          if ((pwin != null) && (!pwin.isVisible())) {
>>>             IJ.log("F_Profiler: should not have reached here
>>> '"+pwin+"'");
>>>             engaged = true;
>>>             disengage();
>>>             return false;
>>>             }
>>>
>>>          int nf = img.getNFrames();
>>>          int cs = img.getZ();
>>>          double[] yM = new double[nf];
>>>          double[] ym = new double[nf];
>>>          double[] ys = new double[nf];
>>>          ImageStack is = img.getStack();
>>>          Calibration cal = img.getCalibration();
>>>          for(int f=0; f<nf; f++) {
>>>             ImageProcessor ip =
>>> is.getProcessor(img.getStackIndex(1,cs,f+1));
>>>             ip.setRoi(roi);
>>>             ImageStatistics stats = ImageStatistics.getStatistics(ip,
>>> MEAN+STD_DEV+MIN_MAX+MEDIAN, cal);
>>>             y[f]  = stats.mean;
>>>             ye[f] = stats.stdDev;
>>>             yM[f] = stats.max;
>>>             ym[f] = stats.min;
>>>             ys[f] = stats.median;
>>>             }
>>>
>>> Plot plot = new Plot("Frame Profile ("+img.getTitle()+")", xLabel,
>>> yLabel);
>>>           plot.setFont(new Font("Comic Sans MS", Font.PLAIN, 20));
>>>           plot.setXLabelFont(new Font("Comic Sans MS", Font.PLAIN, 24));
>>>           plot.setYLabelFont(new Font("Comic Sans MS", Font.PLAIN, 24));
>>>
>>>           plot.setColor(Color.blue);
>>>           plot.setLineWidth(1);
>>>           plot.addPoints(x,y,ye,Plot.X);
>>>           plot.setColor(Color.red);
>>>           plot.setLineWidth(4);
>>>           plot.addPoints(x,y,Plot.X);
>>>
>>>           plot.setColor(Color.green);
>>>           plot.setLineWidth(2);
>>>           plot.addPoints(x,ym,Plot.BOX);
>>>           plot.addPoints(x,yM,Plot.BOX);
>>>           plot.setColor(Color.black);
>>>           plot.addPoints(x,ys,Plot.CIRCLE);
>>>           plot.setLegend("stddev\nmean\nmax\nmin\nmedian",Plot.AUTO_POSITION);
>>> if (pwin==null) {
>>>              pwin = plot.show();
>>>              pwin.addWindowListener(this);
>>>              }
>>>           else {
>>>              Dimension s = pwin.getSize();
>>>              pwin.drawPlot(plot);
>>>              pwin.setSize(s);
>>> IJ.wait(10);
>>>              pwin.setSize(s);
>>>              }
>>>           plot.setLimitsToFit(true);
>>>
>>>           return true;
>>>           }
>>>
>>>      void positionPlotWindow() {
>>>          IJ.wait(500);
>>>          if (pwin==null || img==null) return;
>>>          ImageWindow iwin = img.getWindow();
>>>          if (iwin==null) return;
>>>          Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
>>>          Dimension plotSize = pwin.getSize();
>>>          Dimension imageSize = iwin.getSize();
>>>          if (plotSize.width==0 || imageSize.width==0) return;
>>>          Point imageLoc = iwin.getLocation();
>>>          int w = imageLoc.x+imageSize.width+10;
>>>          if (w+plotSize.width>screen.width)
>>>             w = screen.width-plotSize.width;
>>>          pwin.setLocation(w, imageLoc.y);
>>>          iwin.toFront();
>>>          }
>>>
>>>       public void mousePressed(MouseEvent e) {
>>>          Roi roi = img.getRoi();
>>>          int ix,iy;
>>>          if (roi == null) {
>>>             Point here = img.getCanvas().getCursorLoc();
>>>             ix = here.x;
>>>             iy = here.y;
>>>             }
>>>          else if (roi.getType() == Roi.POINT) {
>>>             Rectangle bounds = roi.getBounds();
>>>             ix = bounds.x;
>>>             iy = bounds.y;
>>>             }
>>>          else {
>>>             updateProfile();
>>>             return;
>>>             }
>>>
>>>          int nf = img.getNFrames();
>>>          int cs = img.getZ();
>>>          ImageStack is = img.getStack();
>>>          for(int f=0; f<nf; f++) {
>>>             ImageProcessor ip =
>>> is.getProcessor(img.getStackIndex(1,cs,f+1));
>>>             y[f]  = ip.getPixelValue(ix, iy);
>>>             ye[f] = 0;
>>>             }
>>>
>>> Plot plot = new Plot("Frame Profile ("+img.getTitle()+")", xLabel,
>>> yLabel);
>>>           plot.setFont(new Font("Comic Sans MS", Font.PLAIN, 20));
>>>           plot.setXLabelFont(new Font("Comic Sans MS", Font.PLAIN, 24));
>>>           plot.setYLabelFont(new Font("Comic Sans MS", Font.PLAIN, 24));
>>>
>>>           plot.setColor(Color.blue);
>>>           plot.setLineWidth(4);
>>>
>>>           Calibration cal = img.getCalibration();
>>>           plot.setJustification(Plot.RIGHT);
>>>           plot.addLabel(0.99,0.99,String.format("%.2f(%d), %.2f(%d),
>>> (%d)",
>>>                         cal.getX(ix),ix,cal.getY(iy),iy,img.getT()));
>>>
>>>           plot.addPoints(x,y,ye,Plot.X);
>>> if (pwin==null) {
>>>              pwin = plot.show();
>>>              pwin.addWindowListener(this);
>>>              }
>>>           else {
>>>              Dimension s = pwin.getSize();
>>>              pwin.drawPlot(plot);
>>>              pwin.setSize(s);
>>>              }
>>>           plot.setLimitsToFit(true);;
>>>           }
>>>
>>>       public void mouseDragged(MouseEvent e)  { updateProfile(); }
>>>       public void keyReleased(KeyEvent e)     { updateProfile(); }
>>>
>>>       public void keyPressed(KeyEvent e)      {}
>>>       public void keyTyped(KeyEvent e)        {}
>>>       public void mouseReleased(MouseEvent e) {}
>>>       public void mouseExited(MouseEvent e)   {}
>>>       public void mouseClicked(MouseEvent e)  {}
>>>       public void mouseEntered(MouseEvent e)  {}
>>>       public void mouseMoved(MouseEvent e)    {}
>>>
>>>       public void mouseWheelMoved(MouseWheelEvent e) { /*
>>> updateProfile(); */ }
>>>
>>>       public void windowActivated(WindowEvent e)   {}
>>>       public void windowClosed(WindowEvent e)      { disengage();}
>>>       public void windowClosing(WindowEvent e)     { disengage();}
>>>       public void windowDeactivated(WindowEvent e) {}
>>>       public void windowDeiconified(WindowEvent e) {}
>>>       public void windowIconified(WindowEvent e)   {}
>>>       public void windowOpened(WindowEvent e)      {}
>>>
>>>       public void imageClosed(ImagePlus imp) {}
>>>       public void imageOpened(ImagePlus imp) {}
>>>       public void imageUpdated(ImagePlus imp) { /* if (imp==img)
>>> updateProfile(); */}
>>> }
>>>
>>> --
>>> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>>>
>>
>> --
>> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>>
>
> --
> 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: plotwindow.drawPlot(plot) incessant resizing

Fred Damen
Greetings Michael,

What I discovered the hard way was that if you create, and keep a list of,
many ImagePlus(s), with the ImageListener set, and then at a later time
try and delete the imageplus(s) on the list from within a ImageListener
callback, about 10-20% of the time ImageJ will lockup solid. This is
independent of removing the ______Listener(s), or not, before close()ing
the imageplus(s) within the ImageListener callback.  This never happened
with using only the WindowListener interface for this purpose as it seems
to only call the callback when a pre-identified imagewindow instance has
been effected.

lockups are a real joy to debug...

Is there a
ImagePlus.removeImageListener(n);
to go with the
ImagePlus.logImageListeners();
?

Enjoy,

Fred


On Thu, March 5, 2020 10:11 am, Michael Schmid wrote:

> Hi Fred,
>
> concerning the PlotMaker interface: Whenever the contents or the Roi of
> the source image is updated, the
>    public Plot getPlot()
> method of the PlotMaker is called.
> It automatically specifies the following 'useTemplate' flags (in
> addition to any other defined by the plot):
>    Plot.COPY_SIZE | Plot.COPY_LABELS | Plot.COPY_AXIS_STYLE |
>    Plot.COPY_CONTENTS_STYLE | Plot.COPY_LEGEND | Plot.COPY_EXTRA_OBJECTS
>
> The 'source image' is the one that the user plugin defines in
>    public ImagePlus getSourceImage()
>
> The plot.setPlotMaker(this) is not static, i.e., you have to call it
> with the first plot that you create and show. Currently, I think there
> is no simple way to start live plotting of a PlotMaker from java; the
> plot is 'live' only if the user presses the 'live' button. If live
> plotting from the start is desired, we would need a small modification
> of ImageJ.
>
>
> Concerning the RoiListener: The method
>    Roi.addRoiListener(this)
> is static, so a RoiListener's roiModified gets calls from all Rois,
> whatever image they belong to. The image is passed with
>    roiModified(ImagePlus img, int id)
> Based on the imp, you can select whether the event is of interest for
> your plugin or not. That's the same as for an ImageListener, where you
> should also which ImagePlus was affected (closed/opened/updated).
>
> Therfore, for both, the ImageListener and RoiListener interfaces, make
> sure to de-register with the corresponding
>    Roi.removeRoiListener(this);
>    ImagePlus.removeImageListener(this);
> Otherwise, your plugin will remain active in the background forever
> (until ImageJ closes) and receive the events, even if you thought it has
> ended all activity. In case of doubt, it does not hurt to call a
> remove...Listener too often (You can also call it without having
> registered with add...Listener).
>
> For the ImageListener interface, in the 1.52u daily build, the static
> method
>    ImagePlus.logImageListeners()
> can be used to check for plugins that have forgotten to de-register. You
> can easily call it from Javascript. There is no such method for
> RoiListeners (yet?).
>
>
> Best,
>
> Michael
> ________________________________________________________________
> On 03.03.20 05:26, Fred Damen wrote:
>> Greetings Michael,
>>
>> A mute point now, but, to reproduce, create hyperstack, create roi,
>> start
>> plugin, resize plotwindow, move the roi a dozen times.
>>
>> The plot.userTemplate works great; aggravation level plummets...
>>
>> For the PlotMaker example that you gave, what instigates the drawing of
>> the next plot. I assume that getPlot is called by PlotWindow, but how to
>> setup the trigger?
>>
>> For the RoiListener, who calls roiModified, i.e., static or instance?  I
>> found out the hard way that the ImageListener methods were called when
>> any
>> / all imageplus objects were affected; ugly race conditions when trying
>> to
>> close a list of images... use WindowListener instead...
>>
>> The attached plugin serves the same general purpose as the ProfilePlot,
>> albeit in the frame direction.  If you collected the same volume (stack
>> of
>> slices) repeatedly and you wanted to know if / how the signal changes
>> through the repeats.
>>
>> Thanks,
>>
>> Fred
>>
>> On Mon, March 2, 2020 4:32 am, Michael Schmid wrote:
>>> Hi Fred,
>>>
>>> there was no problem when I tried it, it works also after resizing the
>>> plot.
>>> Nevertheless, there is an elegant way to make the plot inherit the size
>>> of the previous one shown in the same PlotWindow:
>>>
>>>     plot.useTemplate(previousPlot, Plot.COPY_SIZE);
>>>
>>> You can also have it inherit other properties, such as the legend, axis
>>> labels, style, or curves added by the user (who had used the buttons at
>>> the bottom of the plot).
>>> Just use a bitwise OR or the sum of the following flags:
>>>
>>> COPY_SIZE    Flag for copying from a template: copy plot size
>>> COPY_LABELS  Flag for copying from a template: copy style & text of
>>> axis
>>> COPY_LEGEND  Flag for copying from a template: copy legend
>>> COPY_AXIS_STYLE  Flag for copying from a template: copy axis style
>>> COPY_CONTENTS_STYLE  Flag for copying from a template: copy contents
>>> COPY_EXTRA_OBJECTS Flag for copying PlotObjects (curves...) from a
>>> template if the template has more PlotObjects than the Plot to copy to.
>>>
>>>
>>> In your case (I did not really try to understand your plugin), it seems
>>> that the plot is supposed to react on changes of the Roi? Then there
>>> might be an easier option, just implement the PlotMaker Interface.
>>> The first 40 lines of the Profiler provide an example how to do this:
>>>
>>>     https://github.com/imagej/imagej1/blob/master/ij/plugin/Profiler.java
>>>
>>> If a PlotMaker is no option for you, there is also a RoiListener
>>> interface, which tells you when a Roi has changed, so you don't need
>>> the
>>> keyListener & MouseListener, and it will also detect changes of the Roi
>>> caused by, e.g., menu commands.
>>>
>>>     https://github.com/imagej/imagej1/blob/master/ij/gui/RoiListener.java
>>>
>>>
>>>
>>> [BTW, I did not understand your other post on CTRL-SHIFT under Fedora;
>>> is this about using the text tool on an image? Can you supply a
>>> screenshot to explain (Plugins>Utilities>Capture Delayed)? Replies in
>>> that thread, please]
>>>
>>> Michael
>>> ________________________________________________________________
>>> On 01.03.20 07:10, Fred Damen wrote:
>>>> Greetings,
>>>>
>>>> I have a plugin that plots the statistics of an ROI through the frame
>>>> dimension.  And replots this information when the Roi is altered.  The
>>>> trouble is that if you resize the plotwindow and then cause the plot
>>>> to
>>>> be
>>>> redrawn (plotwindow.drawPlot(plot);) the plotwindow appears to insist
>>>> upon
>>>> resizing the window somewhat asynchronously. Sometimes to the
>>>> interactively resized dimensions IRD, but mostly to default
>>>> dimensions.
>>>> So a naive attempt was to query the plotwindow size and set it again
>>>> after
>>>> the drawPlot. This results in the plotwindow more often being resized
>>>> to
>>>> the IRD, alas not always...  Figuring that there was one of those race
>>>> conditions going on I put in a IJ.wait statement, then the plotwindow
>>>> mostly resizes to the IRD, albeit the plotwindow does not get updated
>>>> during this wait, and also results in massive flickering.  Moving the
>>>> Roi
>>>> with the mouse shows the problem quicker than using the arrow keys,
>>>> but
>>>> within less than 10 redraws the problem happens.  Is there a way to
>>>> get
>>>> the plotwindow size not to change on a drawPlot?
>>>>
>>>> This has been happening for the past couple of years on most of the
>>>> systems I run this on.  Look for the IJ.wait(10); in the below plugin.
>>>>
>>>> Thanks in advance,
>>>>
>>>> Fred
>>>>
>>>> To reproduce:
>>>> imp = IJ.createImage("HyperStack", "32-bit grayscale-mode", 128, 128,
>>>> 1,
>>>> 1, 10);
>>>> imp.setRoi(new OvalRoi(42,52,42,33));
>>>>
>>>> Run this plugin, resize the plotwindow, then move the Roi:
>>>>
>>>> import ij.*;
>>>> import ij.plugin.*;
>>>> import ij.process.*;
>>>> import ij.gui.*;
>>>> import ij.util.Tools;
>>>> import java.io.*;
>>>> import java.awt.*;
>>>> import java.awt.event.*;
>>>> import java.util.*;
>>>> import ij.measure.*;
>>>> import java.awt.Rectangle;
>>>>
>>>>       /**
>>>>         This plugin continuously generates Frame-Dimension profile
>>>> plots
>>>> as
>>>> a selection
>>>>         is moved or resized through the XY Coordinate Plane.
>>>>
>>>>         @author Fred Damen <[hidden email]>
>>>>
>>>>         Version History:
>>>>         2018-04-01: Created
>>>>       */
>>>>
>>>>    public class F_Profiler implements PlugIn,
>>>>                                       MouseListener,
>>>>                                       MouseMotionListener,
>>>>                                       MouseWheelListener,
>>>>                                       Measurements,
>>>>                                       KeyListener,
>>>>                                       WindowListener,
>>>>                                       ImageListener {
>>>>       ImagePlus img;
>>>>       PlotWindow pwin;
>>>>       public double[] x;
>>>>       public double[] y;
>>>>       public double[] ye;
>>>>       String xLabel;
>>>>       String yLabel;
>>>>
>>>>       public void run(String arg) {
>>>>          img = IJ.getImage();
>>>>          int nf = img.getNFrames();
>>>>          if (nf<2) {
>>>>             IJ.showMessage("Dynamic F-Dimension Profiler", "This
>>>> command
>>>> requires a HyperStack.");
>>>>             return;
>>>>             }
>>>>
>>>>          img.getCanvas().addMouseListener(this);
>>>>          img.getCanvas().addMouseMotionListener(this);
>>>>          img.getCanvas().addKeyListener(this);
>>>>          img.getWindow().addMouseWheelListener(this);
>>>>          img.getWindow().addWindowListener(this);
>>>>          img.addImageListener(this);
>>>>          engaged = true;
>>>>          IJ.showStatus("F-Dimension Profile Engaged:
>>>> "+img.getTitle());
>>>>
>>>>          x  = new double[nf];
>>>>          y  = new double[nf];
>>>>          ye = new double[nf];
>>>>          String fu = img.getCalibration().getTimeUnit();
>>>>          try {
>>>>             ImageStack is = img.getStack();
>>>>             for(int f=0; f<nf; f++) {
>>>>                String[] strarr =
>>>> is.getSliceLabel(img.getStackIndex(1,1,f+1)).split(",|;",2)[0].split("
>>>> = |=| ",2);
>>>>                xLabel = strarr[0]+(fu!="" ? " ("+fu+")" : "");
>>>>                x[f] = Float.valueOf(strarr[1]).floatValue();
>>>>                //for(int ff=0; ff<f; ff++)
>>>>                //   if (x[f] == x[ff])
>>>>                //      throw new Throwable();
>>>>                //IJ.log("x["+f+"]="+x[f]);
>>>>                }
>>>>              }
>>>>          catch(Throwable e) {
>>>>              xLabel = "frame"+(fu!="" ? " ("+fu+")" : "");
>>>>              for(int f=0; f<nf; f++)
>>>>                 x[f] = f;
>>>>              }
>>>>
>>>>          yLabel = img.getTitle()+"
>>>> ("+img.getCalibration().getValueUnit()+")";
>>>>          if (!updateProfile())
>>>>             return;
>>>>          positionPlotWindow();
>>>>          }
>>>>
>>>>       boolean engaged = false;
>>>>       void disengage() {
>>>>          if (!engaged) return;
>>>>          if (img.getWindow() != null) {
>>>>             img.getCanvas().removeMouseListener(this);
>>>>             img.getCanvas().removeMouseMotionListener(this);
>>>>             img.getCanvas().removeKeyListener(this);
>>>>             img.getWindow().removeMouseWheelListener(this);
>>>>             img.getWindow().removeWindowListener(this);
>>>>             img.removeImageListener(this);
>>>>             }
>>>>          pwin = null;
>>>>          engaged = false;
>>>>          IJ.showStatus("F-Dimension Profile Disengaged");
>>>>          }
>>>>
>>>>
>>>>       boolean updateProfile() {
>>>>          Roi roi = img.getRoi();
>>>>          if (img == null || roi == null) {
>>>>             IJ.showStatus("Frame-Dimension Profiles running but
>>>> nothing
>>>> to
>>>> do");
>>>>             return true;
>>>>             }
>>>>
>>>>          if ((pwin != null) && (!pwin.isVisible())) {
>>>>             IJ.log("F_Profiler: should not have reached here
>>>> '"+pwin+"'");
>>>>             engaged = true;
>>>>             disengage();
>>>>             return false;
>>>>             }
>>>>
>>>>          int nf = img.getNFrames();
>>>>          int cs = img.getZ();
>>>>          double[] yM = new double[nf];
>>>>          double[] ym = new double[nf];
>>>>          double[] ys = new double[nf];
>>>>          ImageStack is = img.getStack();
>>>>          Calibration cal = img.getCalibration();
>>>>          for(int f=0; f<nf; f++) {
>>>>             ImageProcessor ip =
>>>> is.getProcessor(img.getStackIndex(1,cs,f+1));
>>>>             ip.setRoi(roi);
>>>>             ImageStatistics stats = ImageStatistics.getStatistics(ip,
>>>> MEAN+STD_DEV+MIN_MAX+MEDIAN, cal);
>>>>             y[f]  = stats.mean;
>>>>             ye[f] = stats.stdDev;
>>>>             yM[f] = stats.max;
>>>>             ym[f] = stats.min;
>>>>             ys[f] = stats.median;
>>>>             }
>>>>
>>>> Plot plot = new Plot("Frame Profile ("+img.getTitle()+")", xLabel,
>>>> yLabel);
>>>>           plot.setFont(new Font("Comic Sans MS", Font.PLAIN, 20));
>>>>           plot.setXLabelFont(new Font("Comic Sans MS", Font.PLAIN,
>>>> 24));
>>>>           plot.setYLabelFont(new Font("Comic Sans MS", Font.PLAIN,
>>>> 24));
>>>>
>>>>           plot.setColor(Color.blue);
>>>>           plot.setLineWidth(1);
>>>>           plot.addPoints(x,y,ye,Plot.X);
>>>>           plot.setColor(Color.red);
>>>>           plot.setLineWidth(4);
>>>>           plot.addPoints(x,y,Plot.X);
>>>>
>>>>           plot.setColor(Color.green);
>>>>           plot.setLineWidth(2);
>>>>           plot.addPoints(x,ym,Plot.BOX);
>>>>           plot.addPoints(x,yM,Plot.BOX);
>>>>           plot.setColor(Color.black);
>>>>           plot.addPoints(x,ys,Plot.CIRCLE);
>>>>           plot.setLegend("stddev\nmean\nmax\nmin\nmedian",Plot.AUTO_POSITION);
>>>> if (pwin==null) {
>>>>              pwin = plot.show();
>>>>              pwin.addWindowListener(this);
>>>>              }
>>>>           else {
>>>>              Dimension s = pwin.getSize();
>>>>              pwin.drawPlot(plot);
>>>>              pwin.setSize(s);
>>>> IJ.wait(10);
>>>>              pwin.setSize(s);
>>>>              }
>>>>           plot.setLimitsToFit(true);
>>>>
>>>>           return true;
>>>>           }
>>>>
>>>>      void positionPlotWindow() {
>>>>          IJ.wait(500);
>>>>          if (pwin==null || img==null) return;
>>>>          ImageWindow iwin = img.getWindow();
>>>>          if (iwin==null) return;
>>>>          Dimension screen =
>>>> Toolkit.getDefaultToolkit().getScreenSize();
>>>>          Dimension plotSize = pwin.getSize();
>>>>          Dimension imageSize = iwin.getSize();
>>>>          if (plotSize.width==0 || imageSize.width==0) return;
>>>>          Point imageLoc = iwin.getLocation();
>>>>          int w = imageLoc.x+imageSize.width+10;
>>>>          if (w+plotSize.width>screen.width)
>>>>             w = screen.width-plotSize.width;
>>>>          pwin.setLocation(w, imageLoc.y);
>>>>          iwin.toFront();
>>>>          }
>>>>
>>>>       public void mousePressed(MouseEvent e) {
>>>>          Roi roi = img.getRoi();
>>>>          int ix,iy;
>>>>          if (roi == null) {
>>>>             Point here = img.getCanvas().getCursorLoc();
>>>>             ix = here.x;
>>>>             iy = here.y;
>>>>             }
>>>>          else if (roi.getType() == Roi.POINT) {
>>>>             Rectangle bounds = roi.getBounds();
>>>>             ix = bounds.x;
>>>>             iy = bounds.y;
>>>>             }
>>>>          else {
>>>>             updateProfile();
>>>>             return;
>>>>             }
>>>>
>>>>          int nf = img.getNFrames();
>>>>          int cs = img.getZ();
>>>>          ImageStack is = img.getStack();
>>>>          for(int f=0; f<nf; f++) {
>>>>             ImageProcessor ip =
>>>> is.getProcessor(img.getStackIndex(1,cs,f+1));
>>>>             y[f]  = ip.getPixelValue(ix, iy);
>>>>             ye[f] = 0;
>>>>             }
>>>>
>>>> Plot plot = new Plot("Frame Profile ("+img.getTitle()+")", xLabel,
>>>> yLabel);
>>>>           plot.setFont(new Font("Comic Sans MS", Font.PLAIN, 20));
>>>>           plot.setXLabelFont(new Font("Comic Sans MS", Font.PLAIN,
>>>> 24));
>>>>           plot.setYLabelFont(new Font("Comic Sans MS", Font.PLAIN,
>>>> 24));
>>>>
>>>>           plot.setColor(Color.blue);
>>>>           plot.setLineWidth(4);
>>>>
>>>>           Calibration cal = img.getCalibration();
>>>>           plot.setJustification(Plot.RIGHT);
>>>>           plot.addLabel(0.99,0.99,String.format("%.2f(%d), %.2f(%d),
>>>> (%d)",
>>>>                         cal.getX(ix),ix,cal.getY(iy),iy,img.getT()));
>>>>
>>>>           plot.addPoints(x,y,ye,Plot.X);
>>>> if (pwin==null) {
>>>>              pwin = plot.show();
>>>>              pwin.addWindowListener(this);
>>>>              }
>>>>           else {
>>>>              Dimension s = pwin.getSize();
>>>>              pwin.drawPlot(plot);
>>>>              pwin.setSize(s);
>>>>              }
>>>>           plot.setLimitsToFit(true);;
>>>>           }
>>>>
>>>>       public void mouseDragged(MouseEvent e)  { updateProfile(); }
>>>>       public void keyReleased(KeyEvent e)     { updateProfile(); }
>>>>
>>>>       public void keyPressed(KeyEvent e)      {}
>>>>       public void keyTyped(KeyEvent e)        {}
>>>>       public void mouseReleased(MouseEvent e) {}
>>>>       public void mouseExited(MouseEvent e)   {}
>>>>       public void mouseClicked(MouseEvent e)  {}
>>>>       public void mouseEntered(MouseEvent e)  {}
>>>>       public void mouseMoved(MouseEvent e)    {}
>>>>
>>>>       public void mouseWheelMoved(MouseWheelEvent e) { /*
>>>> updateProfile(); */ }
>>>>
>>>>       public void windowActivated(WindowEvent e)   {}
>>>>       public void windowClosed(WindowEvent e)      { disengage();}
>>>>       public void windowClosing(WindowEvent e)     { disengage();}
>>>>       public void windowDeactivated(WindowEvent e) {}
>>>>       public void windowDeiconified(WindowEvent e) {}
>>>>       public void windowIconified(WindowEvent e)   {}
>>>>       public void windowOpened(WindowEvent e)      {}
>>>>
>>>>       public void imageClosed(ImagePlus imp) {}
>>>>       public void imageOpened(ImagePlus imp) {}
>>>>       public void imageUpdated(ImagePlus imp) { /* if (imp==img)
>>>> updateProfile(); */}
>>>> }
>>>>
>>>> --
>>>> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>>>>
>>>
>>> --
>>> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>>>
>>
>> --
>> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>>
>
> --
> 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: plotwindow.drawPlot(plot) incessant resizing

Michael Schmid
Hi Fred,

in the latest daily build (1.52u37), Wayne has put the ImageListener
callbacks into the EventQueue using EventQueue.invokeLater.
This should reduce the risk of deadlocks.

---
How to diagnose deadlocks:

Start ImageJ from the command line.

On Linux, type (in another terminal)
   kill -3 <pid>
where <pid> is the process ID of ImageJ as you get it, e.g., with
   ps -ef.

On windows, you may try to type ctrl-\ or ctrl-<break> in the terminal
where you have started ImageJ (I have no Windows computer here, so I
have not tried myself).

This gives you a thread dump, which tells you whether a deadlock has
been detected, which threads are involved and in which line of the
program they are stuck.

---
There is no way to remove ImageListeners if you don't know which class
instance has registered as ImageListener. I think that such a call would
be undesirable since it could lead to a bad programming habit of simply
deleting all ImageListeners, and then some other plugin still running
would be compromised.

So it is the responsibility of each plugin to de-register as
ImageListener; in case of doubt wrap everything into try-catch(-finally)
clauses where you deregister when something goes wrong. Also, if the
plugin has a "main" image that it works on and this one gets closed, the
ImageListener should detect this and deregister.


Michael
________________________________________________________________
On 08.03.20 20:51, Fred Damen wrote:

> Greetings Michael,
>
> What I discovered the hard way was that if you create, and keep a list of,
> many ImagePlus(s), with the ImageListener set, and then at a later time
> try and delete the imageplus(s) on the list from within a ImageListener
> callback, about 10-20% of the time ImageJ will lockup solid. This is
> independent of removing the ______Listener(s), or not, before close()ing
> the imageplus(s) within the ImageListener callback.  This never happened
> with using only the WindowListener interface for this purpose as it seems
> to only call the callback when a pre-identified imagewindow instance has
> been effected.
>
> lockups are a real joy to debug...
>
> Is there a
> ImagePlus.removeImageListener(n);
> to go with the
> ImagePlus.logImageListeners();
> ?
>
> Enjoy,
>
> Fred
>
>
> On Thu, March 5, 2020 10:11 am, Michael Schmid wrote:
>> Hi Fred,
>>
>> concerning the PlotMaker interface: Whenever the contents or the Roi of
>> the source image is updated, the
>>     public Plot getPlot()
>> method of the PlotMaker is called.
>> It automatically specifies the following 'useTemplate' flags (in
>> addition to any other defined by the plot):
>>     Plot.COPY_SIZE | Plot.COPY_LABELS | Plot.COPY_AXIS_STYLE |
>>     Plot.COPY_CONTENTS_STYLE | Plot.COPY_LEGEND | Plot.COPY_EXTRA_OBJECTS
>>
>> The 'source image' is the one that the user plugin defines in
>>     public ImagePlus getSourceImage()
>>
>> The plot.setPlotMaker(this) is not static, i.e., you have to call it
>> with the first plot that you create and show. Currently, I think there
>> is no simple way to start live plotting of a PlotMaker from java; the
>> plot is 'live' only if the user presses the 'live' button. If live
>> plotting from the start is desired, we would need a small modification
>> of ImageJ.
>>
>>
>> Concerning the RoiListener: The method
>>     Roi.addRoiListener(this)
>> is static, so a RoiListener's roiModified gets calls from all Rois,
>> whatever image they belong to. The image is passed with
>>     roiModified(ImagePlus img, int id)
>> Based on the imp, you can select whether the event is of interest for
>> your plugin or not. That's the same as for an ImageListener, where you
>> should also which ImagePlus was affected (closed/opened/updated).
>>
>> Therfore, for both, the ImageListener and RoiListener interfaces, make
>> sure to de-register with the corresponding
>>     Roi.removeRoiListener(this);
>>     ImagePlus.removeImageListener(this);
>> Otherwise, your plugin will remain active in the background forever
>> (until ImageJ closes) and receive the events, even if you thought it has
>> ended all activity. In case of doubt, it does not hurt to call a
>> remove...Listener too often (You can also call it without having
>> registered with add...Listener).
>>
>> For the ImageListener interface, in the 1.52u daily build, the static
>> method
>>     ImagePlus.logImageListeners()
>> can be used to check for plugins that have forgotten to de-register. You
>> can easily call it from Javascript. There is no such method for
>> RoiListeners (yet?).
>>
>>
>> Best,
>>
>> Michael
>> ________________________________________________________________
>> On 03.03.20 05:26, Fred Damen wrote:
>>> Greetings Michael,
>>>
>>> A mute point now, but, to reproduce, create hyperstack, create roi,
>>> start
>>> plugin, resize plotwindow, move the roi a dozen times.
>>>
>>> The plot.userTemplate works great; aggravation level plummets...
>>>
>>> For the PlotMaker example that you gave, what instigates the drawing of
>>> the next plot. I assume that getPlot is called by PlotWindow, but how to
>>> setup the trigger?
>>>
>>> For the RoiListener, who calls roiModified, i.e., static or instance?  I
>>> found out the hard way that the ImageListener methods were called when
>>> any
>>> / all imageplus objects were affected; ugly race conditions when trying
>>> to
>>> close a list of images... use WindowListener instead...
>>>
>>> The attached plugin serves the same general purpose as the ProfilePlot,
>>> albeit in the frame direction.  If you collected the same volume (stack
>>> of
>>> slices) repeatedly and you wanted to know if / how the signal changes
>>> through the repeats.
>>>
>>> Thanks,
>>>
>>> Fred
>>>
>>> On Mon, March 2, 2020 4:32 am, Michael Schmid wrote:
>>>> Hi Fred,
>>>>
>>>> there was no problem when I tried it, it works also after resizing the
>>>> plot.
>>>> Nevertheless, there is an elegant way to make the plot inherit the size
>>>> of the previous one shown in the same PlotWindow:
>>>>
>>>>      plot.useTemplate(previousPlot, Plot.COPY_SIZE);
>>>>
>>>> You can also have it inherit other properties, such as the legend, axis
>>>> labels, style, or curves added by the user (who had used the buttons at
>>>> the bottom of the plot).
>>>> Just use a bitwise OR or the sum of the following flags:
>>>>
>>>> COPY_SIZE    Flag for copying from a template: copy plot size
>>>> COPY_LABELS  Flag for copying from a template: copy style & text of
>>>> axis
>>>> COPY_LEGEND  Flag for copying from a template: copy legend
>>>> COPY_AXIS_STYLE  Flag for copying from a template: copy axis style
>>>> COPY_CONTENTS_STYLE  Flag for copying from a template: copy contents
>>>> COPY_EXTRA_OBJECTS Flag for copying PlotObjects (curves...) from a
>>>> template if the template has more PlotObjects than the Plot to copy to.
>>>>
>>>>
>>>> In your case (I did not really try to understand your plugin), it seems
>>>> that the plot is supposed to react on changes of the Roi? Then there
>>>> might be an easier option, just implement the PlotMaker Interface.
>>>> The first 40 lines of the Profiler provide an example how to do this:
>>>>
>>>>      https://github.com/imagej/imagej1/blob/master/ij/plugin/Profiler.java
>>>>
>>>> If a PlotMaker is no option for you, there is also a RoiListener
>>>> interface, which tells you when a Roi has changed, so you don't need
>>>> the
>>>> keyListener & MouseListener, and it will also detect changes of the Roi
>>>> caused by, e.g., menu commands.
>>>>
>>>>      https://github.com/imagej/imagej1/blob/master/ij/gui/RoiListener.java
>>>>
>>>>
>>>>
>>>> [BTW, I did not understand your other post on CTRL-SHIFT under Fedora;
>>>> is this about using the text tool on an image? Can you supply a
>>>> screenshot to explain (Plugins>Utilities>Capture Delayed)? Replies in
>>>> that thread, please]
>>>>
>>>> Michael
>>>> ________________________________________________________________
>>>> On 01.03.20 07:10, Fred Damen wrote:
>>>>> Greetings,
>>>>>
>>>>> I have a plugin that plots the statistics of an ROI through the frame
>>>>> dimension.  And replots this information when the Roi is altered.  The
>>>>> trouble is that if you resize the plotwindow and then cause the plot
>>>>> to
>>>>> be
>>>>> redrawn (plotwindow.drawPlot(plot);) the plotwindow appears to insist
>>>>> upon
>>>>> resizing the window somewhat asynchronously. Sometimes to the
>>>>> interactively resized dimensions IRD, but mostly to default
>>>>> dimensions.
>>>>> So a naive attempt was to query the plotwindow size and set it again
>>>>> after
>>>>> the drawPlot. This results in the plotwindow more often being resized
>>>>> to
>>>>> the IRD, alas not always...  Figuring that there was one of those race
>>>>> conditions going on I put in a IJ.wait statement, then the plotwindow
>>>>> mostly resizes to the IRD, albeit the plotwindow does not get updated
>>>>> during this wait, and also results in massive flickering.  Moving the
>>>>> Roi
>>>>> with the mouse shows the problem quicker than using the arrow keys,
>>>>> but
>>>>> within less than 10 redraws the problem happens.  Is there a way to
>>>>> get
>>>>> the plotwindow size not to change on a drawPlot?
>>>>>
>>>>> This has been happening for the past couple of years on most of the
>>>>> systems I run this on.  Look for the IJ.wait(10); in the below plugin.
>>>>>
>>>>> Thanks in advance,
>>>>>
>>>>> Fred
>>>>>
>>>>> To reproduce:
>>>>> imp = IJ.createImage("HyperStack", "32-bit grayscale-mode", 128, 128,
>>>>> 1,
>>>>> 1, 10);
>>>>> imp.setRoi(new OvalRoi(42,52,42,33));
>>>>>
>>>>> Run this plugin, resize the plotwindow, then move the Roi:
>>>>>
>>>>> import ij.*;
>>>>> import ij.plugin.*;
>>>>> import ij.process.*;
>>>>> import ij.gui.*;
>>>>> import ij.util.Tools;
>>>>> import java.io.*;
>>>>> import java.awt.*;
>>>>> import java.awt.event.*;
>>>>> import java.util.*;
>>>>> import ij.measure.*;
>>>>> import java.awt.Rectangle;
>>>>>
>>>>>        /**
>>>>>          This plugin continuously generates Frame-Dimension profile
>>>>> plots
>>>>> as
>>>>> a selection
>>>>>          is moved or resized through the XY Coordinate Plane.
>>>>>
>>>>>          @author Fred Damen <[hidden email]>
>>>>>
>>>>>          Version History:
>>>>>          2018-04-01: Created
>>>>>        */
>>>>>
>>>>>     public class F_Profiler implements PlugIn,
>>>>>                                        MouseListener,
>>>>>                                        MouseMotionListener,
>>>>>                                        MouseWheelListener,
>>>>>                                        Measurements,
>>>>>                                        KeyListener,
>>>>>                                        WindowListener,
>>>>>                                        ImageListener {
>>>>>        ImagePlus img;
>>>>>        PlotWindow pwin;
>>>>>        public double[] x;
>>>>>        public double[] y;
>>>>>        public double[] ye;
>>>>>        String xLabel;
>>>>>        String yLabel;
>>>>>
>>>>>        public void run(String arg) {
>>>>>           img = IJ.getImage();
>>>>>           int nf = img.getNFrames();
>>>>>           if (nf<2) {
>>>>>              IJ.showMessage("Dynamic F-Dimension Profiler", "This
>>>>> command
>>>>> requires a HyperStack.");
>>>>>              return;
>>>>>              }
>>>>>
>>>>>           img.getCanvas().addMouseListener(this);
>>>>>           img.getCanvas().addMouseMotionListener(this);
>>>>>           img.getCanvas().addKeyListener(this);
>>>>>           img.getWindow().addMouseWheelListener(this);
>>>>>           img.getWindow().addWindowListener(this);
>>>>>           img.addImageListener(this);
>>>>>           engaged = true;
>>>>>           IJ.showStatus("F-Dimension Profile Engaged:
>>>>> "+img.getTitle());
>>>>>
>>>>>           x  = new double[nf];
>>>>>           y  = new double[nf];
>>>>>           ye = new double[nf];
>>>>>           String fu = img.getCalibration().getTimeUnit();
>>>>>           try {
>>>>>              ImageStack is = img.getStack();
>>>>>              for(int f=0; f<nf; f++) {
>>>>>                 String[] strarr =
>>>>> is.getSliceLabel(img.getStackIndex(1,1,f+1)).split(",|;",2)[0].split("
>>>>> = |=| ",2);
>>>>>                 xLabel = strarr[0]+(fu!="" ? " ("+fu+")" : "");
>>>>>                 x[f] = Float.valueOf(strarr[1]).floatValue();
>>>>>                 //for(int ff=0; ff<f; ff++)
>>>>>                 //   if (x[f] == x[ff])
>>>>>                 //      throw new Throwable();
>>>>>                 //IJ.log("x["+f+"]="+x[f]);
>>>>>                 }
>>>>>               }
>>>>>           catch(Throwable e) {
>>>>>               xLabel = "frame"+(fu!="" ? " ("+fu+")" : "");
>>>>>               for(int f=0; f<nf; f++)
>>>>>                  x[f] = f;
>>>>>               }
>>>>>
>>>>>           yLabel = img.getTitle()+"
>>>>> ("+img.getCalibration().getValueUnit()+")";
>>>>>           if (!updateProfile())
>>>>>              return;
>>>>>           positionPlotWindow();
>>>>>           }
>>>>>
>>>>>        boolean engaged = false;
>>>>>        void disengage() {
>>>>>           if (!engaged) return;
>>>>>           if (img.getWindow() != null) {
>>>>>              img.getCanvas().removeMouseListener(this);
>>>>>              img.getCanvas().removeMouseMotionListener(this);
>>>>>              img.getCanvas().removeKeyListener(this);
>>>>>              img.getWindow().removeMouseWheelListener(this);
>>>>>              img.getWindow().removeWindowListener(this);
>>>>>              img.removeImageListener(this);
>>>>>              }
>>>>>           pwin = null;
>>>>>           engaged = false;
>>>>>           IJ.showStatus("F-Dimension Profile Disengaged");
>>>>>           }
>>>>>
>>>>>
>>>>>        boolean updateProfile() {
>>>>>           Roi roi = img.getRoi();
>>>>>           if (img == null || roi == null) {
>>>>>              IJ.showStatus("Frame-Dimension Profiles running but
>>>>> nothing
>>>>> to
>>>>> do");
>>>>>              return true;
>>>>>              }
>>>>>
>>>>>           if ((pwin != null) && (!pwin.isVisible())) {
>>>>>              IJ.log("F_Profiler: should not have reached here
>>>>> '"+pwin+"'");
>>>>>              engaged = true;
>>>>>              disengage();
>>>>>              return false;
>>>>>              }
>>>>>
>>>>>           int nf = img.getNFrames();
>>>>>           int cs = img.getZ();
>>>>>           double[] yM = new double[nf];
>>>>>           double[] ym = new double[nf];
>>>>>           double[] ys = new double[nf];
>>>>>           ImageStack is = img.getStack();
>>>>>           Calibration cal = img.getCalibration();
>>>>>           for(int f=0; f<nf; f++) {
>>>>>              ImageProcessor ip =
>>>>> is.getProcessor(img.getStackIndex(1,cs,f+1));
>>>>>              ip.setRoi(roi);
>>>>>              ImageStatistics stats = ImageStatistics.getStatistics(ip,
>>>>> MEAN+STD_DEV+MIN_MAX+MEDIAN, cal);
>>>>>              y[f]  = stats.mean;
>>>>>              ye[f] = stats.stdDev;
>>>>>              yM[f] = stats.max;
>>>>>              ym[f] = stats.min;
>>>>>              ys[f] = stats.median;
>>>>>              }
>>>>>
>>>>> Plot plot = new Plot("Frame Profile ("+img.getTitle()+")", xLabel,
>>>>> yLabel);
>>>>>            plot.setFont(new Font("Comic Sans MS", Font.PLAIN, 20));
>>>>>            plot.setXLabelFont(new Font("Comic Sans MS", Font.PLAIN,
>>>>> 24));
>>>>>            plot.setYLabelFont(new Font("Comic Sans MS", Font.PLAIN,
>>>>> 24));
>>>>>
>>>>>            plot.setColor(Color.blue);
>>>>>            plot.setLineWidth(1);
>>>>>            plot.addPoints(x,y,ye,Plot.X);
>>>>>            plot.setColor(Color.red);
>>>>>            plot.setLineWidth(4);
>>>>>            plot.addPoints(x,y,Plot.X);
>>>>>
>>>>>            plot.setColor(Color.green);
>>>>>            plot.setLineWidth(2);
>>>>>            plot.addPoints(x,ym,Plot.BOX);
>>>>>            plot.addPoints(x,yM,Plot.BOX);
>>>>>            plot.setColor(Color.black);
>>>>>            plot.addPoints(x,ys,Plot.CIRCLE);
>>>>>            plot.setLegend("stddev\nmean\nmax\nmin\nmedian",Plot.AUTO_POSITION);
>>>>> if (pwin==null) {
>>>>>               pwin = plot.show();
>>>>>               pwin.addWindowListener(this);
>>>>>               }
>>>>>            else {
>>>>>               Dimension s = pwin.getSize();
>>>>>               pwin.drawPlot(plot);
>>>>>               pwin.setSize(s);
>>>>> IJ.wait(10);
>>>>>               pwin.setSize(s);
>>>>>               }
>>>>>            plot.setLimitsToFit(true);
>>>>>
>>>>>            return true;
>>>>>            }
>>>>>
>>>>>       void positionPlotWindow() {
>>>>>           IJ.wait(500);
>>>>>           if (pwin==null || img==null) return;
>>>>>           ImageWindow iwin = img.getWindow();
>>>>>           if (iwin==null) return;
>>>>>           Dimension screen =
>>>>> Toolkit.getDefaultToolkit().getScreenSize();
>>>>>           Dimension plotSize = pwin.getSize();
>>>>>           Dimension imageSize = iwin.getSize();
>>>>>           if (plotSize.width==0 || imageSize.width==0) return;
>>>>>           Point imageLoc = iwin.getLocation();
>>>>>           int w = imageLoc.x+imageSize.width+10;
>>>>>           if (w+plotSize.width>screen.width)
>>>>>              w = screen.width-plotSize.width;
>>>>>           pwin.setLocation(w, imageLoc.y);
>>>>>           iwin.toFront();
>>>>>           }
>>>>>
>>>>>        public void mousePressed(MouseEvent e) {
>>>>>           Roi roi = img.getRoi();
>>>>>           int ix,iy;
>>>>>           if (roi == null) {
>>>>>              Point here = img.getCanvas().getCursorLoc();
>>>>>              ix = here.x;
>>>>>              iy = here.y;
>>>>>              }
>>>>>           else if (roi.getType() == Roi.POINT) {
>>>>>              Rectangle bounds = roi.getBounds();
>>>>>              ix = bounds.x;
>>>>>              iy = bounds.y;
>>>>>              }
>>>>>           else {
>>>>>              updateProfile();
>>>>>              return;
>>>>>              }
>>>>>
>>>>>           int nf = img.getNFrames();
>>>>>           int cs = img.getZ();
>>>>>           ImageStack is = img.getStack();
>>>>>           for(int f=0; f<nf; f++) {
>>>>>              ImageProcessor ip =
>>>>> is.getProcessor(img.getStackIndex(1,cs,f+1));
>>>>>              y[f]  = ip.getPixelValue(ix, iy);
>>>>>              ye[f] = 0;
>>>>>              }
>>>>>
>>>>> Plot plot = new Plot("Frame Profile ("+img.getTitle()+")", xLabel,
>>>>> yLabel);
>>>>>            plot.setFont(new Font("Comic Sans MS", Font.PLAIN, 20));
>>>>>            plot.setXLabelFont(new Font("Comic Sans MS", Font.PLAIN,
>>>>> 24));
>>>>>            plot.setYLabelFont(new Font("Comic Sans MS", Font.PLAIN,
>>>>> 24));
>>>>>
>>>>>            plot.setColor(Color.blue);
>>>>>            plot.setLineWidth(4);
>>>>>
>>>>>            Calibration cal = img.getCalibration();
>>>>>            plot.setJustification(Plot.RIGHT);
>>>>>            plot.addLabel(0.99,0.99,String.format("%.2f(%d), %.2f(%d),
>>>>> (%d)",
>>>>>                          cal.getX(ix),ix,cal.getY(iy),iy,img.getT()));
>>>>>
>>>>>            plot.addPoints(x,y,ye,Plot.X);
>>>>> if (pwin==null) {
>>>>>               pwin = plot.show();
>>>>>               pwin.addWindowListener(this);
>>>>>               }
>>>>>            else {
>>>>>               Dimension s = pwin.getSize();
>>>>>               pwin.drawPlot(plot);
>>>>>               pwin.setSize(s);
>>>>>               }
>>>>>            plot.setLimitsToFit(true);;
>>>>>            }
>>>>>
>>>>>        public void mouseDragged(MouseEvent e)  { updateProfile(); }
>>>>>        public void keyReleased(KeyEvent e)     { updateProfile(); }
>>>>>
>>>>>        public void keyPressed(KeyEvent e)      {}
>>>>>        public void keyTyped(KeyEvent e)        {}
>>>>>        public void mouseReleased(MouseEvent e) {}
>>>>>        public void mouseExited(MouseEvent e)   {}
>>>>>        public void mouseClicked(MouseEvent e)  {}
>>>>>        public void mouseEntered(MouseEvent e)  {}
>>>>>        public void mouseMoved(MouseEvent e)    {}
>>>>>
>>>>>        public void mouseWheelMoved(MouseWheelEvent e) { /*
>>>>> updateProfile(); */ }
>>>>>
>>>>>        public void windowActivated(WindowEvent e)   {}
>>>>>        public void windowClosed(WindowEvent e)      { disengage();}
>>>>>        public void windowClosing(WindowEvent e)     { disengage();}
>>>>>        public void windowDeactivated(WindowEvent e) {}
>>>>>        public void windowDeiconified(WindowEvent e) {}
>>>>>        public void windowIconified(WindowEvent e)   {}
>>>>>        public void windowOpened(WindowEvent e)      {}
>>>>>
>>>>>        public void imageClosed(ImagePlus imp) {}
>>>>>        public void imageOpened(ImagePlus imp) {}
>>>>>        public void imageUpdated(ImagePlus imp) { /* if (imp==img)
>>>>> updateProfile(); */}
>>>>> }
>>>>>
>>>>> --
>>>>> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>>>>>
>>>>
>>>> --
>>>> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>>>>
>>>
>>> --
>>> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>>>
>>
>> --
>> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>>
>
> --
> 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: plotwindow.drawPlot(plot) incessant resizing

Fred Damen
Greetings Michael,

Thanks, this info will make debugging the next deadlock much easier.

I agree that using an out-of-program means to muck with the innerds of a
running/dead program is a bad idea, albeit, when the need arises, ya start
wishing for stuff...  I have not yet tried logImageListeners although I
assumed that it would list the class of the pointer(s) that has been
registered for receiving the callbacks.

Using an instance based registrar for the callbacks provides the benefit
that when the instance goes away so does the registrations.

Thanks again,

Fred

On Wed, March 11, 2020 4:54 am, Michael Schmid wrote:

> Hi Fred,
>
> in the latest daily build (1.52u37), Wayne has put the ImageListener
> callbacks into the EventQueue using EventQueue.invokeLater.
> This should reduce the risk of deadlocks.
>
> ---
> How to diagnose deadlocks:
>
> Start ImageJ from the command line.
>
> On Linux, type (in another terminal)
>    kill -3 <pid>
> where <pid> is the process ID of ImageJ as you get it, e.g., with
>    ps -ef.
>
> On windows, you may try to type ctrl-\ or ctrl-<break> in the terminal
> where you have started ImageJ (I have no Windows computer here, so I
> have not tried myself).
>
> This gives you a thread dump, which tells you whether a deadlock has
> been detected, which threads are involved and in which line of the
> program they are stuck.
>
> ---
> There is no way to remove ImageListeners if you don't know which class
> instance has registered as ImageListener. I think that such a call would
> be undesirable since it could lead to a bad programming habit of simply
> deleting all ImageListeners, and then some other plugin still running
> would be compromised.
>
> So it is the responsibility of each plugin to de-register as
> ImageListener; in case of doubt wrap everything into try-catch(-finally)
> clauses where you deregister when something goes wrong. Also, if the
> plugin has a "main" image that it works on and this one gets closed, the
> ImageListener should detect this and deregister.
>
>
> Michael
> ________________________________________________________________
> On 08.03.20 20:51, Fred Damen wrote:
>> Greetings Michael,
>>
>> What I discovered the hard way was that if you create, and keep a list
>> of,
>> many ImagePlus(s), with the ImageListener set, and then at a later time
>> try and delete the imageplus(s) on the list from within a ImageListener
>> callback, about 10-20% of the time ImageJ will lockup solid. This is
>> independent of removing the ______Listener(s), or not, before close()ing
>> the imageplus(s) within the ImageListener callback.  This never happened
>> with using only the WindowListener interface for this purpose as it
>> seems
>> to only call the callback when a pre-identified imagewindow instance has
>> been effected.
>>
>> lockups are a real joy to debug...
>>
>> Is there a
>> ImagePlus.removeImageListener(n);
>> to go with the
>> ImagePlus.logImageListeners();
>> ?
>>
>> Enjoy,
>>
>> Fred
>>
>>
>> On Thu, March 5, 2020 10:11 am, Michael Schmid wrote:
>>> Hi Fred,
>>>
>>> concerning the PlotMaker interface: Whenever the contents or the Roi of
>>> the source image is updated, the
>>>     public Plot getPlot()
>>> method of the PlotMaker is called.
>>> It automatically specifies the following 'useTemplate' flags (in
>>> addition to any other defined by the plot):
>>>     Plot.COPY_SIZE | Plot.COPY_LABELS | Plot.COPY_AXIS_STYLE |
>>>     Plot.COPY_CONTENTS_STYLE | Plot.COPY_LEGEND |
>>> Plot.COPY_EXTRA_OBJECTS
>>>
>>> The 'source image' is the one that the user plugin defines in
>>>     public ImagePlus getSourceImage()
>>>
>>> The plot.setPlotMaker(this) is not static, i.e., you have to call it
>>> with the first plot that you create and show. Currently, I think there
>>> is no simple way to start live plotting of a PlotMaker from java; the
>>> plot is 'live' only if the user presses the 'live' button. If live
>>> plotting from the start is desired, we would need a small modification
>>> of ImageJ.
>>>
>>>
>>> Concerning the RoiListener: The method
>>>     Roi.addRoiListener(this)
>>> is static, so a RoiListener's roiModified gets calls from all Rois,
>>> whatever image they belong to. The image is passed with
>>>     roiModified(ImagePlus img, int id)
>>> Based on the imp, you can select whether the event is of interest for
>>> your plugin or not. That's the same as for an ImageListener, where you
>>> should also which ImagePlus was affected (closed/opened/updated).
>>>
>>> Therfore, for both, the ImageListener and RoiListener interfaces, make
>>> sure to de-register with the corresponding
>>>     Roi.removeRoiListener(this);
>>>     ImagePlus.removeImageListener(this);
>>> Otherwise, your plugin will remain active in the background forever
>>> (until ImageJ closes) and receive the events, even if you thought it
>>> has
>>> ended all activity. In case of doubt, it does not hurt to call a
>>> remove...Listener too often (You can also call it without having
>>> registered with add...Listener).
>>>
>>> For the ImageListener interface, in the 1.52u daily build, the static
>>> method
>>>     ImagePlus.logImageListeners()
>>> can be used to check for plugins that have forgotten to de-register.
>>> You
>>> can easily call it from Javascript. There is no such method for
>>> RoiListeners (yet?).
>>>
>>>
>>> Best,
>>>
>>> Michael
>>> ________________________________________________________________
>>> On 03.03.20 05:26, Fred Damen wrote:
>>>> Greetings Michael,
>>>>
>>>> A mute point now, but, to reproduce, create hyperstack, create roi,
>>>> start
>>>> plugin, resize plotwindow, move the roi a dozen times.
>>>>
>>>> The plot.userTemplate works great; aggravation level plummets...
>>>>
>>>> For the PlotMaker example that you gave, what instigates the drawing
>>>> of
>>>> the next plot. I assume that getPlot is called by PlotWindow, but how
>>>> to
>>>> setup the trigger?
>>>>
>>>> For the RoiListener, who calls roiModified, i.e., static or instance?
>>>> I
>>>> found out the hard way that the ImageListener methods were called when
>>>> any
>>>> / all imageplus objects were affected; ugly race conditions when
>>>> trying
>>>> to
>>>> close a list of images... use WindowListener instead...
>>>>
>>>> The attached plugin serves the same general purpose as the
>>>> ProfilePlot,
>>>> albeit in the frame direction.  If you collected the same volume
>>>> (stack
>>>> of
>>>> slices) repeatedly and you wanted to know if / how the signal changes
>>>> through the repeats.
>>>>
>>>> Thanks,
>>>>
>>>> Fred
>>>>
>>>> On Mon, March 2, 2020 4:32 am, Michael Schmid wrote:
>>>>> Hi Fred,
>>>>>
>>>>> there was no problem when I tried it, it works also after resizing
>>>>> the
>>>>> plot.
>>>>> Nevertheless, there is an elegant way to make the plot inherit the
>>>>> size
>>>>> of the previous one shown in the same PlotWindow:
>>>>>
>>>>>      plot.useTemplate(previousPlot, Plot.COPY_SIZE);
>>>>>
>>>>> You can also have it inherit other properties, such as the legend,
>>>>> axis
>>>>> labels, style, or curves added by the user (who had used the buttons
>>>>> at
>>>>> the bottom of the plot).
>>>>> Just use a bitwise OR or the sum of the following flags:
>>>>>
>>>>> COPY_SIZE    Flag for copying from a template: copy plot size
>>>>> COPY_LABELS  Flag for copying from a template: copy style & text of
>>>>> axis
>>>>> COPY_LEGEND  Flag for copying from a template: copy legend
>>>>> COPY_AXIS_STYLE  Flag for copying from a template: copy axis style
>>>>> COPY_CONTENTS_STYLE  Flag for copying from a template: copy contents
>>>>> COPY_EXTRA_OBJECTS Flag for copying PlotObjects (curves...) from a
>>>>> template if the template has more PlotObjects than the Plot to copy
>>>>> to.
>>>>>
>>>>>
>>>>> In your case (I did not really try to understand your plugin), it
>>>>> seems
>>>>> that the plot is supposed to react on changes of the Roi? Then there
>>>>> might be an easier option, just implement the PlotMaker Interface.
>>>>> The first 40 lines of the Profiler provide an example how to do this:
>>>>>
>>>>>      https://github.com/imagej/imagej1/blob/master/ij/plugin/Profiler.java
>>>>>
>>>>> If a PlotMaker is no option for you, there is also a RoiListener
>>>>> interface, which tells you when a Roi has changed, so you don't need
>>>>> the
>>>>> keyListener & MouseListener, and it will also detect changes of the
>>>>> Roi
>>>>> caused by, e.g., menu commands.
>>>>>
>>>>>      https://github.com/imagej/imagej1/blob/master/ij/gui/RoiListener.java
>>>>>
>>>>>
>>>>>
>>>>> [BTW, I did not understand your other post on CTRL-SHIFT under
>>>>> Fedora;
>>>>> is this about using the text tool on an image? Can you supply a
>>>>> screenshot to explain (Plugins>Utilities>Capture Delayed)? Replies in
>>>>> that thread, please]
>>>>>
>>>>> Michael
>>>>> ________________________________________________________________
>>>>> On 01.03.20 07:10, Fred Damen wrote:
>>>>>> Greetings,
>>>>>>
>>>>>> I have a plugin that plots the statistics of an ROI through the
>>>>>> frame
>>>>>> dimension.  And replots this information when the Roi is altered.
>>>>>> The
>>>>>> trouble is that if you resize the plotwindow and then cause the plot
>>>>>> to
>>>>>> be
>>>>>> redrawn (plotwindow.drawPlot(plot);) the plotwindow appears to
>>>>>> insist
>>>>>> upon
>>>>>> resizing the window somewhat asynchronously. Sometimes to the
>>>>>> interactively resized dimensions IRD, but mostly to default
>>>>>> dimensions.
>>>>>> So a naive attempt was to query the plotwindow size and set it again
>>>>>> after
>>>>>> the drawPlot. This results in the plotwindow more often being
>>>>>> resized
>>>>>> to
>>>>>> the IRD, alas not always...  Figuring that there was one of those
>>>>>> race
>>>>>> conditions going on I put in a IJ.wait statement, then the
>>>>>> plotwindow
>>>>>> mostly resizes to the IRD, albeit the plotwindow does not get
>>>>>> updated
>>>>>> during this wait, and also results in massive flickering.  Moving
>>>>>> the
>>>>>> Roi
>>>>>> with the mouse shows the problem quicker than using the arrow keys,
>>>>>> but
>>>>>> within less than 10 redraws the problem happens.  Is there a way to
>>>>>> get
>>>>>> the plotwindow size not to change on a drawPlot?
>>>>>>
>>>>>> This has been happening for the past couple of years on most of the
>>>>>> systems I run this on.  Look for the IJ.wait(10); in the below
>>>>>> plugin.
>>>>>>
>>>>>> Thanks in advance,
>>>>>>
>>>>>> Fred
>>>>>>
>>>>>> To reproduce:
>>>>>> imp = IJ.createImage("HyperStack", "32-bit grayscale-mode", 128,
>>>>>> 128,
>>>>>> 1,
>>>>>> 1, 10);
>>>>>> imp.setRoi(new OvalRoi(42,52,42,33));
>>>>>>
>>>>>> Run this plugin, resize the plotwindow, then move the Roi:
>>>>>>
>>>>>> import ij.*;
>>>>>> import ij.plugin.*;
>>>>>> import ij.process.*;
>>>>>> import ij.gui.*;
>>>>>> import ij.util.Tools;
>>>>>> import java.io.*;
>>>>>> import java.awt.*;
>>>>>> import java.awt.event.*;
>>>>>> import java.util.*;
>>>>>> import ij.measure.*;
>>>>>> import java.awt.Rectangle;
>>>>>>
>>>>>>        /**
>>>>>>          This plugin continuously generates Frame-Dimension profile
>>>>>> plots
>>>>>> as
>>>>>> a selection
>>>>>>          is moved or resized through the XY Coordinate Plane.
>>>>>>
>>>>>>          @author Fred Damen <[hidden email]>
>>>>>>
>>>>>>          Version History:
>>>>>>          2018-04-01: Created
>>>>>>        */
>>>>>>
>>>>>>     public class F_Profiler implements PlugIn,
>>>>>>                                        MouseListener,
>>>>>>                                        MouseMotionListener,
>>>>>>                                        MouseWheelListener,
>>>>>>                                        Measurements,
>>>>>>                                        KeyListener,
>>>>>>                                        WindowListener,
>>>>>>                                        ImageListener {
>>>>>>        ImagePlus img;
>>>>>>        PlotWindow pwin;
>>>>>>        public double[] x;
>>>>>>        public double[] y;
>>>>>>        public double[] ye;
>>>>>>        String xLabel;
>>>>>>        String yLabel;
>>>>>>
>>>>>>        public void run(String arg) {
>>>>>>           img = IJ.getImage();
>>>>>>           int nf = img.getNFrames();
>>>>>>           if (nf<2) {
>>>>>>              IJ.showMessage("Dynamic F-Dimension Profiler", "This
>>>>>> command
>>>>>> requires a HyperStack.");
>>>>>>              return;
>>>>>>              }
>>>>>>
>>>>>>           img.getCanvas().addMouseListener(this);
>>>>>>           img.getCanvas().addMouseMotionListener(this);
>>>>>>           img.getCanvas().addKeyListener(this);
>>>>>>           img.getWindow().addMouseWheelListener(this);
>>>>>>           img.getWindow().addWindowListener(this);
>>>>>>           img.addImageListener(this);
>>>>>>           engaged = true;
>>>>>>           IJ.showStatus("F-Dimension Profile Engaged:
>>>>>> "+img.getTitle());
>>>>>>
>>>>>>           x  = new double[nf];
>>>>>>           y  = new double[nf];
>>>>>>           ye = new double[nf];
>>>>>>           String fu = img.getCalibration().getTimeUnit();
>>>>>>           try {
>>>>>>              ImageStack is = img.getStack();
>>>>>>              for(int f=0; f<nf; f++) {
>>>>>>                 String[] strarr =
>>>>>> is.getSliceLabel(img.getStackIndex(1,1,f+1)).split(",|;",2)[0].split("
>>>>>> = |=| ",2);
>>>>>>                 xLabel = strarr[0]+(fu!="" ? " ("+fu+")" : "");
>>>>>>                 x[f] = Float.valueOf(strarr[1]).floatValue();
>>>>>>                 //for(int ff=0; ff<f; ff++)
>>>>>>                 //   if (x[f] == x[ff])
>>>>>>                 //      throw new Throwable();
>>>>>>                 //IJ.log("x["+f+"]="+x[f]);
>>>>>>                 }
>>>>>>               }
>>>>>>           catch(Throwable e) {
>>>>>>               xLabel = "frame"+(fu!="" ? " ("+fu+")" : "");
>>>>>>               for(int f=0; f<nf; f++)
>>>>>>                  x[f] = f;
>>>>>>               }
>>>>>>
>>>>>>           yLabel = img.getTitle()+"
>>>>>> ("+img.getCalibration().getValueUnit()+")";
>>>>>>           if (!updateProfile())
>>>>>>              return;
>>>>>>           positionPlotWindow();
>>>>>>           }
>>>>>>
>>>>>>        boolean engaged = false;
>>>>>>        void disengage() {
>>>>>>           if (!engaged) return;
>>>>>>           if (img.getWindow() != null) {
>>>>>>              img.getCanvas().removeMouseListener(this);
>>>>>>              img.getCanvas().removeMouseMotionListener(this);
>>>>>>              img.getCanvas().removeKeyListener(this);
>>>>>>              img.getWindow().removeMouseWheelListener(this);
>>>>>>              img.getWindow().removeWindowListener(this);
>>>>>>              img.removeImageListener(this);
>>>>>>              }
>>>>>>           pwin = null;
>>>>>>           engaged = false;
>>>>>>           IJ.showStatus("F-Dimension Profile Disengaged");
>>>>>>           }
>>>>>>
>>>>>>
>>>>>>        boolean updateProfile() {
>>>>>>           Roi roi = img.getRoi();
>>>>>>           if (img == null || roi == null) {
>>>>>>              IJ.showStatus("Frame-Dimension Profiles running but
>>>>>> nothing
>>>>>> to
>>>>>> do");
>>>>>>              return true;
>>>>>>              }
>>>>>>
>>>>>>           if ((pwin != null) && (!pwin.isVisible())) {
>>>>>>              IJ.log("F_Profiler: should not have reached here
>>>>>> '"+pwin+"'");
>>>>>>              engaged = true;
>>>>>>              disengage();
>>>>>>              return false;
>>>>>>              }
>>>>>>
>>>>>>           int nf = img.getNFrames();
>>>>>>           int cs = img.getZ();
>>>>>>           double[] yM = new double[nf];
>>>>>>           double[] ym = new double[nf];
>>>>>>           double[] ys = new double[nf];
>>>>>>           ImageStack is = img.getStack();
>>>>>>           Calibration cal = img.getCalibration();
>>>>>>           for(int f=0; f<nf; f++) {
>>>>>>              ImageProcessor ip =
>>>>>> is.getProcessor(img.getStackIndex(1,cs,f+1));
>>>>>>              ip.setRoi(roi);
>>>>>>              ImageStatistics stats =
>>>>>> ImageStatistics.getStatistics(ip,
>>>>>> MEAN+STD_DEV+MIN_MAX+MEDIAN, cal);
>>>>>>              y[f]  = stats.mean;
>>>>>>              ye[f] = stats.stdDev;
>>>>>>              yM[f] = stats.max;
>>>>>>              ym[f] = stats.min;
>>>>>>              ys[f] = stats.median;
>>>>>>              }
>>>>>>
>>>>>> Plot plot = new Plot("Frame Profile ("+img.getTitle()+")", xLabel,
>>>>>> yLabel);
>>>>>>            plot.setFont(new Font("Comic Sans MS", Font.PLAIN, 20));
>>>>>>            plot.setXLabelFont(new Font("Comic Sans MS", Font.PLAIN,
>>>>>> 24));
>>>>>>            plot.setYLabelFont(new Font("Comic Sans MS", Font.PLAIN,
>>>>>> 24));
>>>>>>
>>>>>>            plot.setColor(Color.blue);
>>>>>>            plot.setLineWidth(1);
>>>>>>            plot.addPoints(x,y,ye,Plot.X);
>>>>>>            plot.setColor(Color.red);
>>>>>>            plot.setLineWidth(4);
>>>>>>            plot.addPoints(x,y,Plot.X);
>>>>>>
>>>>>>            plot.setColor(Color.green);
>>>>>>            plot.setLineWidth(2);
>>>>>>            plot.addPoints(x,ym,Plot.BOX);
>>>>>>            plot.addPoints(x,yM,Plot.BOX);
>>>>>>            plot.setColor(Color.black);
>>>>>>            plot.addPoints(x,ys,Plot.CIRCLE);
>>>>>>            plot.setLegend("stddev\nmean\nmax\nmin\nmedian",Plot.AUTO_POSITION);
>>>>>> if (pwin==null) {
>>>>>>               pwin = plot.show();
>>>>>>               pwin.addWindowListener(this);
>>>>>>               }
>>>>>>            else {
>>>>>>               Dimension s = pwin.getSize();
>>>>>>               pwin.drawPlot(plot);
>>>>>>               pwin.setSize(s);
>>>>>> IJ.wait(10);
>>>>>>               pwin.setSize(s);
>>>>>>               }
>>>>>>            plot.setLimitsToFit(true);
>>>>>>
>>>>>>            return true;
>>>>>>            }
>>>>>>
>>>>>>       void positionPlotWindow() {
>>>>>>           IJ.wait(500);
>>>>>>           if (pwin==null || img==null) return;
>>>>>>           ImageWindow iwin = img.getWindow();
>>>>>>           if (iwin==null) return;
>>>>>>           Dimension screen =
>>>>>> Toolkit.getDefaultToolkit().getScreenSize();
>>>>>>           Dimension plotSize = pwin.getSize();
>>>>>>           Dimension imageSize = iwin.getSize();
>>>>>>           if (plotSize.width==0 || imageSize.width==0) return;
>>>>>>           Point imageLoc = iwin.getLocation();
>>>>>>           int w = imageLoc.x+imageSize.width+10;
>>>>>>           if (w+plotSize.width>screen.width)
>>>>>>              w = screen.width-plotSize.width;
>>>>>>           pwin.setLocation(w, imageLoc.y);
>>>>>>           iwin.toFront();
>>>>>>           }
>>>>>>
>>>>>>        public void mousePressed(MouseEvent e) {
>>>>>>           Roi roi = img.getRoi();
>>>>>>           int ix,iy;
>>>>>>           if (roi == null) {
>>>>>>              Point here = img.getCanvas().getCursorLoc();
>>>>>>              ix = here.x;
>>>>>>              iy = here.y;
>>>>>>              }
>>>>>>           else if (roi.getType() == Roi.POINT) {
>>>>>>              Rectangle bounds = roi.getBounds();
>>>>>>              ix = bounds.x;
>>>>>>              iy = bounds.y;
>>>>>>              }
>>>>>>           else {
>>>>>>              updateProfile();
>>>>>>              return;
>>>>>>              }
>>>>>>
>>>>>>           int nf = img.getNFrames();
>>>>>>           int cs = img.getZ();
>>>>>>           ImageStack is = img.getStack();
>>>>>>           for(int f=0; f<nf; f++) {
>>>>>>              ImageProcessor ip =
>>>>>> is.getProcessor(img.getStackIndex(1,cs,f+1));
>>>>>>              y[f]  = ip.getPixelValue(ix, iy);
>>>>>>              ye[f] = 0;
>>>>>>              }
>>>>>>
>>>>>> Plot plot = new Plot("Frame Profile ("+img.getTitle()+")", xLabel,
>>>>>> yLabel);
>>>>>>            plot.setFont(new Font("Comic Sans MS", Font.PLAIN, 20));
>>>>>>            plot.setXLabelFont(new Font("Comic Sans MS", Font.PLAIN,
>>>>>> 24));
>>>>>>            plot.setYLabelFont(new Font("Comic Sans MS", Font.PLAIN,
>>>>>> 24));
>>>>>>
>>>>>>            plot.setColor(Color.blue);
>>>>>>            plot.setLineWidth(4);
>>>>>>
>>>>>>            Calibration cal = img.getCalibration();
>>>>>>            plot.setJustification(Plot.RIGHT);
>>>>>>            plot.addLabel(0.99,0.99,String.format("%.2f(%d),
>>>>>> %.2f(%d),
>>>>>> (%d)",
>>>>>>                          cal.getX(ix),ix,cal.getY(iy),iy,img.getT()));
>>>>>>
>>>>>>            plot.addPoints(x,y,ye,Plot.X);
>>>>>> if (pwin==null) {
>>>>>>               pwin = plot.show();
>>>>>>               pwin.addWindowListener(this);
>>>>>>               }
>>>>>>            else {
>>>>>>               Dimension s = pwin.getSize();
>>>>>>               pwin.drawPlot(plot);
>>>>>>               pwin.setSize(s);
>>>>>>               }
>>>>>>            plot.setLimitsToFit(true);;
>>>>>>            }
>>>>>>
>>>>>>        public void mouseDragged(MouseEvent e)  { updateProfile(); }
>>>>>>        public void keyReleased(KeyEvent e)     { updateProfile(); }
>>>>>>
>>>>>>        public void keyPressed(KeyEvent e)      {}
>>>>>>        public void keyTyped(KeyEvent e)        {}
>>>>>>        public void mouseReleased(MouseEvent e) {}
>>>>>>        public void mouseExited(MouseEvent e)   {}
>>>>>>        public void mouseClicked(MouseEvent e)  {}
>>>>>>        public void mouseEntered(MouseEvent e)  {}
>>>>>>        public void mouseMoved(MouseEvent e)    {}
>>>>>>
>>>>>>        public void mouseWheelMoved(MouseWheelEvent e) { /*
>>>>>> updateProfile(); */ }
>>>>>>
>>>>>>        public void windowActivated(WindowEvent e)   {}
>>>>>>        public void windowClosed(WindowEvent e)      { disengage();}
>>>>>>        public void windowClosing(WindowEvent e)     { disengage();}
>>>>>>        public void windowDeactivated(WindowEvent e) {}
>>>>>>        public void windowDeiconified(WindowEvent e) {}
>>>>>>        public void windowIconified(WindowEvent e)   {}
>>>>>>        public void windowOpened(WindowEvent e)      {}
>>>>>>
>>>>>>        public void imageClosed(ImagePlus imp) {}
>>>>>>        public void imageOpened(ImagePlus imp) {}
>>>>>>        public void imageUpdated(ImagePlus imp) { /* if (imp==img)
>>>>>> updateProfile(); */}
>>>>>> }
>>>>>>
>>>>>> --
>>>>>> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>>>>>>
>>>>>
>>>>> --
>>>>> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>>>>>
>>>>
>>>> --
>>>> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>>>>
>>>
>>> --
>>> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>>>
>>
>> --
>> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>>
>
> --
> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>

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