http://imagej.273.s1.nabble.com/plotwindow-drawPlot-plot-incessant-resizing-tp5022995p5023036.html
callbacks into the EventQueue using EventQueue.invokeLater.
This should reduce the risk of deadlocks.
Start ImageJ from the command line.
ps -ef.
have not tried myself).
program they are stuck.
instance has registered as ImageListener. I think that such a call would
would be compromised.
clauses where you deregister when something goes wrong. Also, if the
ImageListener should detect this and deregister.
> 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>