diff --git a/.gitignore b/.gitignore index 3d47f986c41db29ec6dc0d5036bf760b3a1cf366..57f16fb67c1b1589981416b323d7a9debc728665 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,41 @@ -.idea/ +/build* +/workspace +setting.xml +release/ target/ -.settings/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ +icy.log + +### IntelliJ IDEA ### +.idea/ +*.iws *.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath .project -.classpath \ No newline at end of file +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +**/.DS_Store +Icon? \ No newline at end of file diff --git a/pom.xml b/pom.xml index 4a242f15a87a74e9b3b3f651742c5b9cdb56e66c..2d4bfe9fc380850ab032271f7183f4a62e3aaa5b 100644 --- a/pom.xml +++ b/pom.xml @@ -8,14 +8,12 @@ <parent> <artifactId>pom-icy</artifactId> <groupId>org.bioimageanalysis.icy</groupId> - <version>2.1.0</version> + <version>3.0.0-a.1</version> </parent> <!-- Project Information --> <artifactId>msd-track-processor</artifactId> - <version>1.1.4</version> - - <packaging>jar</packaging> + <version>2.0.0-a.1</version> <name>MSD Track Processor</name> <description>Track Processor computing the MSD (Mean Square Displacement).</description> @@ -53,35 +51,18 @@ </developer> </developers> - <!-- Project properties --> - <properties> - - </properties> - <!-- List of project's dependencies --> <dependencies> <dependency> <groupId>org.bioimageanalysis.icy</groupId> <artifactId>jfreechart</artifactId> </dependency> - - <dependency> - <groupId>net.sourceforge.jexcelapi</groupId> - <artifactId>jxl</artifactId> - </dependency> - <dependency> <groupId>org.bioimageanalysis.icy</groupId> <artifactId>spot-detection-utilities</artifactId> </dependency> - <dependency> <groupId>org.bioimageanalysis.icy</groupId> - <artifactId>distance-profiler</artifactId> - </dependency> - - <dependency> - <groupId>org.bioimageanalysis.icy</groupId> <artifactId>track-manager</artifactId> </dependency> </dependencies> @@ -90,8 +71,7 @@ <repositories> <repository> <id>icy</id> - <name>Icy's Nexus</name> - <url>https://icy-nexus.pasteur.fr/repository/Icy/</url> + <url>https://nexus-icy.pasteur.cloud/repository/icy/</url> </repository> </repositories> </project> diff --git a/src/main/java/plugins/fab/trackmanager/processors/TrackProcessorMSD.java b/src/main/java/plugins/fab/trackmanager/processors/TrackProcessorMSD.java index 0d469d39bea939dee1c9013a07f0e0e9950af943..c66a724b29ed5ee21111726b33cd090226babed7 100644 --- a/src/main/java/plugins/fab/trackmanager/processors/TrackProcessorMSD.java +++ b/src/main/java/plugins/fab/trackmanager/processors/TrackProcessorMSD.java @@ -1,24 +1,36 @@ -package plugins.fab.trackmanager.processors; - -import java.awt.Graphics2D; -import java.awt.Point; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.KeyEvent; -import java.awt.event.MouseEvent; -import java.awt.geom.AffineTransform; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.io.File; -import java.io.IOException; +/* + * Copyright (c) 2010-2024. Institut Pasteur. + * + * This file is part of Icy. + * Icy is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Icy is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Icy. If not, see <https://www.gnu.org/licenses/>. + */ -import javax.swing.BoxLayout; -import javax.swing.JButton; -import javax.swing.JCheckBox; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JTextField; +package plugins.fab.trackmanager.processors; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.bioimageanalysis.icy.Icy; +import org.bioimageanalysis.icy.common.string.StringUtil; +import org.bioimageanalysis.icy.extension.plugin.annotation_.IcyPluginIcon; +import org.bioimageanalysis.icy.extension.plugin.annotation_.IcyPluginName; +import org.bioimageanalysis.icy.gui.GuiUtil; +import org.bioimageanalysis.icy.gui.dialog.SaveDialog; +import org.bioimageanalysis.icy.io.xls.XLSXUtil; +import org.bioimageanalysis.icy.model.sequence.Sequence; +import org.bioimageanalysis.icy.system.logging.IcyLogger; +import org.bioimageanalysis.icy.system.preferences.GeneralPreferences; +import org.jetbrains.annotations.NotNull; import org.jfree.chart.ChartFactory; import org.jfree.chart.ChartPanel; import org.jfree.chart.JFreeChart; @@ -27,28 +39,23 @@ import org.jfree.chart.plot.XYPlot; import org.jfree.chart.renderer.xy.XYItemRenderer; import org.jfree.data.xy.XYSeries; import org.jfree.data.xy.XYSeriesCollection; - -import icy.canvas.IcyCanvas; -import icy.gui.dialog.SaveDialog; -import icy.gui.util.GuiUtil; -import icy.main.Icy; -import icy.painter.Painter; -import icy.preferences.GeneralPreferences; -import icy.sequence.Sequence; -import icy.util.StringUtil; -import icy.util.XLSUtil; -import jxl.write.WritableSheet; -import jxl.write.WritableWorkbook; -import jxl.write.WriteException; import plugins.fab.trackmanager.PluginTrackManagerProcessor; import plugins.fab.trackmanager.TrackSegment; import plugins.nchenouard.spot.Detection; +import javax.swing.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.geom.Rectangle2D; +import java.io.File; +import java.io.IOException; + /** * @author Fabrice de Chaumont */ -public class TrackProcessorMSD extends PluginTrackManagerProcessor implements ActionListener, Painter -{ +@IcyPluginName("Track Processor MSD") +@IcyPluginIcon(path = "/msd-track-processor.png") +public class TrackProcessorMSD extends PluginTrackManagerProcessor implements ActionListener { JFreeChart chart; JCheckBox displayLegendCheckBox = new JCheckBox("Display legend.", false); JCheckBox displayGraphInSequenceCheckBox = new JCheckBox("Display graph on sequence.", false); @@ -60,17 +67,14 @@ public class TrackProcessorMSD extends PluginTrackManagerProcessor implements Ac JButton exportButton = new JButton("export to console"); JButton exportExcelButton = new JButton("export to excel"); - public TrackProcessorMSD() - { + public TrackProcessorMSD() { panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS)); chartpanel.add(new ChartPanel(chart, 500, 300, 500, 300, 500, 300, false, false, true, true, true, true)); panel.add(GuiUtil.besidesPanel(chartpanel)); panel.add(GuiUtil.besidesPanel(useRealScalesBox)); - useRealScalesBox.addActionListener(new ActionListener() - { + useRealScalesBox.addActionListener(new ActionListener() { @Override - public void actionPerformed(ActionEvent e) - { + public void actionPerformed(ActionEvent e) { Compute(); } }); @@ -89,8 +93,7 @@ public class TrackProcessorMSD extends PluginTrackManagerProcessor implements Ac } @Override - public void Compute() - { + public void Compute() { if (!super.isEnabled()) return; @@ -99,10 +102,8 @@ public class TrackProcessorMSD extends PluginTrackManagerProcessor implements Ac final Sequence seq = trackPool.getDisplaySequence(); final double tScale = (seq != null) ? seq.getTimeInterval() : 1d; - if (useRealScalesBox.isSelected()) - { - for (TrackSegment ts : trackPool.getTrackSegmentList()) - { + if (useRealScalesBox.isSelected()) { + for (TrackSegment ts : trackPool.getTrackSegmentList()) { XYSeries series = new XYSeries("Track " + trackPool.getTrackIndex(ts)); // Better to allow partially clipped tracks otherwise we cannot get MSD for them (Stephane) @@ -111,8 +112,7 @@ public class TrackProcessorMSD extends PluginTrackManagerProcessor implements Ac { double[] msd = scaledMeanSquaredDisplacement(seq, ts); - if (msd.length > 0) - { + if (msd.length > 0) { for (int i = 0; i < msd.length; i++) series.add(i * tScale, msd[i]); @@ -121,10 +121,8 @@ public class TrackProcessorMSD extends PluginTrackManagerProcessor implements Ac } } } - else - { - for (TrackSegment ts : trackPool.getTrackSegmentList()) - { + else { + for (TrackSegment ts : trackPool.getTrackSegmentList()) { XYSeries series = new XYSeries("Track " + trackPool.getTrackIndex(ts)); // Better to allow partially clipped tracks otherwise we cannot get MSD for them (Stephane) @@ -133,8 +131,7 @@ public class TrackProcessorMSD extends PluginTrackManagerProcessor implements Ac { double[] msd = scaledMeanSquaredDisplacement(null, ts); - if (msd.length > 0) - { + if (msd.length > 0) { for (int i = 0; i < msd.length; i++) series.add(i, msd[i]); @@ -147,16 +144,13 @@ public class TrackProcessorMSD extends PluginTrackManagerProcessor implements Ac String TitleString2 = ""; String TitleString3 = ""; - if (displayLegendCheckBox.isSelected()) - { - if (useRealScalesBox.isSelected()) - { + if (displayLegendCheckBox.isSelected()) { + if (useRealScalesBox.isSelected()) { TitleString = "Mean Square Displacement"; TitleString2 = "Delta (s)"; TitleString3 = "MSD (um^2)"; } - else - { + else { TitleString = "Mean Square Displacement"; TitleString2 = "Delta (frame)"; TitleString3 = "MSD (pixel^2)"; @@ -172,8 +166,7 @@ public class TrackProcessorMSD extends PluginTrackManagerProcessor implements Ac false // urls ); - if (forceAllSequenceGraphWidthCheckBox.isSelected()) - { + if (forceAllSequenceGraphWidthCheckBox.isSelected()) { XYSeries series = new XYSeries(""); series.add(trackPool.getLastDetectionTimePoint(), 0); xyDataset.addSeries(series); @@ -181,8 +174,7 @@ public class TrackProcessorMSD extends PluginTrackManagerProcessor implements Ac chartpanel.removeAll(); - if (chart != null) - { + if (chart != null) { // replace default chart colors by detection colors (taken from t=0) XYItemRenderer renderer = ((XYPlot) chart.getPlot()).getRenderer(); for (TrackSegment ts : trackPool.getTrackSegmentList()) @@ -195,78 +187,77 @@ public class TrackProcessorMSD extends PluginTrackManagerProcessor implements Ac } - /** Export to console and optionaly in xls */ - private void exportMSD(boolean xlsExport) - { - WritableWorkbook workbook = null; - WritableSheet page = null; + /** + * Export to console and optionaly in xls + */ + private void exportMSD(boolean xlsExport) { + Workbook workbook = null; + Sheet page = null; + File XLSFile = null; - if (xlsExport) - { + if (xlsExport) { String outputName; - if (Icy.getMainInterface().isHeadLess()) - { + if (Icy.getMainInterface().isHeadLess()) { if ((trackPool.getDisplaySequence() == null) || StringUtil.isEmpty(trackPool.getDisplaySequence().getFilename())) outputName = GeneralPreferences.getResultFolder() + "Tracks"; else outputName = trackPool.getDisplaySequence().getFilename(); - outputName += ".msd.xls"; + outputName += ".msd.xlsx"; } else - outputName = SaveDialog.chooseFileForResult("XLS MSD export", "tracks-msd", ".xls"); + outputName = SaveDialog.chooseFileForResult("XLS MSD export", "tracks-msd", ".xlsx"); if (StringUtil.isEmpty(outputName)) return; - try - { - workbook = XLSUtil.createWorkbook(new File(outputName)); + XLSFile = new File(outputName); + + try { + if (XLSFile.exists()) + workbook = XLSXUtil.loadWorkbookForWrite(XLSFile); + else + workbook = XLSXUtil.createWorkbook(); } - catch (IOException e) - { - e.printStackTrace(); + catch (IOException e) { + IcyLogger.error(this.getClass(), e, "Could not create XLSX Workbook."); } } if (workbook != null) - page = XLSUtil.createNewPage(workbook, "results"); + page = XLSXUtil.createNewPage(workbook, "results"); final Sequence seq = trackPool.getDisplaySequence(); final double tScale = (seq != null) ? seq.getTimeInterval() : 1d; - if (useRealScalesBox.isSelected()) - { + if (useRealScalesBox.isSelected()) { int cnt = 0; int row = 1; // Start from 1 because of table head int cols = 0; - for (TrackSegment ts : trackPool.getTrackSegmentList()) - { + for (TrackSegment ts : trackPool.getTrackSegmentList()) { // Better to allow partially clipped tracks otherwise we cannot get MSD for them (Stephane) // TODO: check that it doesn't bring any regression // if (ts.isAllDetectionEnabled()) { double[] msd = scaledMeanSquaredDisplacement(seq, ts); - if (msd.length > 0) - { + if (msd.length > 0) { // Get max cols for the table if (msd.length > cols) cols = msd.length; - System.out.println("track " + cnt); + IcyLogger.trace(this.getClass(), "track " + cnt); if (page != null) - XLSUtil.setCellString(page, 0, row, "track " + cnt); + XLSXUtil.setCellString(page, 0, row, "track " + cnt); - for (int i = 0; i < msd.length; i++) - { - System.out.println((i * tScale) + "\t" + msd[i]); + for (int i = 0; i < msd.length; i++) { + IcyLogger.trace(this.getClass(), (i * tScale) + "\t" + msd[i]); // System.out.println(i + "\t" + msd[i]); if (page != null) - XLSUtil.setCellNumber(page, i + 1, row, msd[i]); + XLSXUtil.setCellNumber(page, i + 1, row, msd[i]); } cnt++; @@ -277,45 +268,41 @@ public class TrackProcessorMSD extends PluginTrackManagerProcessor implements Ac // Write table head if (page != null) { - XLSUtil.setCellString(page, 0, 0, "frame"); + XLSXUtil.setCellString(page, 0, 0, "frame"); if (cols > 0) { for (int c = 0; c < cols; c++) { - XLSUtil.setCellString(page, c+1, 0, String.valueOf(c)); + XLSXUtil.setCellString(page, c + 1, 0, String.valueOf(c)); } } } } - else - { + else { int cnt = 0; int row = 1; // Start from 1 because of table head int cols = 0; - for (TrackSegment ts : trackPool.getTrackSegmentList()) - { + for (TrackSegment ts : trackPool.getTrackSegmentList()) { // Better to allow partially clipped tracks otherwise we cannot get MSD for them (Stephane) // TODO: check that it doesn't bring any regression // if (ts.isAllDetectionEnabled()) { double[] msd = scaledMeanSquaredDisplacement(null, ts); - if (msd.length > 0) - { + if (msd.length > 0) { // Get max cols for the table if (msd.length > cols) cols = msd.length; - System.out.println("track " + cnt); + IcyLogger.trace(this.getClass(), "track " + cnt); if (page != null) - XLSUtil.setCellString(page, 0, row, "track " + cnt); + XLSXUtil.setCellString(page, 0, row, "track " + cnt); - for (int i = 0; i < msd.length; i++) - { - System.out.println(i + "\t" + msd[i]); + for (int i = 0; i < msd.length; i++) { + IcyLogger.trace(this.getClass(), i + "\t" + msd[i]); if (page != null) - XLSUtil.setCellNumber(page, i + 1, row, msd[i]); + XLSXUtil.setCellNumber(page, i + 1, row, msd[i]); } cnt++; @@ -326,28 +313,21 @@ public class TrackProcessorMSD extends PluginTrackManagerProcessor implements Ac // Write table head if (page != null) { - XLSUtil.setCellString(page, 0, 0, "frame"); + XLSXUtil.setCellString(page, 0, 0, "frame"); if (cols > 0) { for (int c = 0; c < cols; c++) { - XLSUtil.setCellString(page, c+1, 0, String.valueOf(c)); + XLSXUtil.setCellString(page, c + 1, 0, String.valueOf(c)); } } } } - if (workbook != null) - { - try - { - XLSUtil.saveAndClose(workbook); - } - catch (WriteException e) - { - e.printStackTrace(); + if (workbook != null) { + try { + XLSXUtil.saveAndClose(workbook, XLSFile); } - catch (IOException e) - { - e.printStackTrace(); + catch (IOException e) { + IcyLogger.error(this.getClass(), e, "Could not save XLSX Workbook."); } } } @@ -356,18 +336,15 @@ public class TrackProcessorMSD extends PluginTrackManagerProcessor implements Ac JLabel outLabel = new JLabel(); - private double[] scaledMeanSquaredDisplacement(Sequence seq, TrackSegment ts) - { + private double @NotNull [] scaledMeanSquaredDisplacement(Sequence seq, TrackSegment ts) { final double sx, sy, sz; - if (seq != null) - { + if (seq != null) { sx = seq.getPixelSizeX(); sy = seq.getPixelSizeY(); sz = seq.getPixelSizeZ(); } - else - { + else { sx = 1d; sy = 1d; sz = 1d; @@ -381,26 +358,21 @@ public class TrackProcessorMSD extends PluginTrackManagerProcessor implements Ac // Find partially enabled/clipped tracks otherwise we cannot get MSD for them (Stephane) // TODO: check that it doesn't bring any regression - for (int i = 0; i < numDetection; i++) - { + for (int i = 0; i < numDetection; i++) { final Detection d = ts.getDetectionAt(i); - if (d.isEnabled()) - { + if (d.isEnabled()) { // start of track - if (lastFirstEnabledDetectionIndex == -1) - { + if (lastFirstEnabledDetectionIndex == -1) { lastFirstEnabledDetectionIndex = i; lastNumEnabledDetection = 1; } else lastNumEnabledDetection++; } - else - { + else { // check if last track is the longest found - if (lastNumEnabledDetection > numEnabledDetection) - { + if (lastNumEnabledDetection > numEnabledDetection) { numEnabledDetection = lastNumEnabledDetection; firstEnabledDetectionIndex = lastFirstEnabledDetectionIndex; } @@ -412,16 +384,14 @@ public class TrackProcessorMSD extends PluginTrackManagerProcessor implements Ac } // check if last track is the longest found - if (lastNumEnabledDetection > numEnabledDetection) - { + if (lastNumEnabledDetection > numEnabledDetection) { numEnabledDetection = lastNumEnabledDetection; firstEnabledDetectionIndex = lastFirstEnabledDetectionIndex; } double[] msd = new double[numEnabledDetection]; - for (int t = 1; t < numEnabledDetection; t++) - { + for (int t = 1; t < numEnabledDetection; t++) { msd[t] = 0d; for (int j = 1; j <= t; j++) msd[t] += scaledSquaredDistance(ts.getDetectionAt(firstEnabledDetectionIndex), ts.getDetectionAt(firstEnabledDetectionIndex + j), sx, sy, sz); @@ -463,13 +433,11 @@ public class TrackProcessorMSD extends PluginTrackManagerProcessor implements Ac // // } - private static double squaredDistance(Detection d1, Detection d2) - { + private static double squaredDistance(Detection d1, Detection d2) { return scaledSquaredDistance(d1, d2, 1d, 1d, 1d); } - private static double scaledSquaredDistance(Detection d1, Detection d2, double sx, double sy, double sz) - { + private static double scaledSquaredDistance(@NotNull Detection d1, @NotNull Detection d2, double sx, double sy, double sz) { return Math.pow((d1.getX() - d2.getX()) * sx, 2) + Math.pow((d1.getY() - d2.getY()) * sy, 2) + Math.pow((d1.getZ() - d2.getZ()) * sz, 2); } @@ -489,67 +457,53 @@ public class TrackProcessorMSD extends PluginTrackManagerProcessor implements Ac // } @Override - public void Close() - { - Sequence sequence = trackPool.getDisplaySequence(); - if (sequence != null) - { - sequence.removePainter(this); - } + public void Close() { + /*Sequence sequence = trackPool.getDisplaySequence(); + if (sequence != null) { + sequence.removeOverlay(this); + }*/ } - public void actionPerformed(ActionEvent e) - { - + public void actionPerformed(@NotNull ActionEvent e) { // if ( e.getSource() == useRoiAsBoundsForChartButton ) // { // Shape shape = (Shape) trackPool.getDisplaySequence().getROIs().get( 0 ); // chartRectangleInSequence = (Rectangle2D) shape.getBounds2D().clone(); // } - if (e.getSource() == exportButton) - { + if (e.getSource() == exportButton) { exportMSD(false); } - if (e.getSource() == exportExcelButton) - { + if (e.getSource() == exportExcelButton) { exportMSD(true); } trackPool.fireTrackEditorProcessorChange(); - } - public void keyPressed(Point p, KeyEvent e) - { + /*public void keyPressed(Point p, KeyEvent e) { } - public void mouseClick(Point p, MouseEvent e) - { + public void mouseClick(Point p, MouseEvent e) { } - public void mouseDrag(Point p, MouseEvent e) - { + public void mouseDrag(Point p, MouseEvent e) { } - public void mouseMove(Point p, MouseEvent e) - { + public void mouseMove(Point p, MouseEvent e) { - } + }*/ @Override - public void displaySequenceChanged() - { + public void displaySequenceChanged() { } - @Override - public void paint(Graphics2D g, Sequence sequence, IcyCanvas canvas) - { - + /*@Override + public void paint(Graphics2D g, Sequence sequence, IcyCanvas canvas) { double scale = Double.parseDouble(scaleTextField.getText()); double minX = chartRectangleInSequence.getCenterX(); double minY = chartRectangleInSequence.getCenterY(); @@ -576,45 +530,37 @@ public class TrackProcessorMSD extends PluginTrackManagerProcessor implements Ac } @Override - public void mousePressed(MouseEvent e, Point2D imagePoint, IcyCanvas canvas) - { + public void mousePressed(MouseEvent e, Point2D imagePoint, IcyCanvas canvas) { } @Override - public void mouseReleased(MouseEvent e, Point2D imagePoint, IcyCanvas canvas) - { + public void mouseReleased(MouseEvent e, Point2D imagePoint, IcyCanvas canvas) { } @Override - public void mouseClick(MouseEvent e, Point2D imagePoint, IcyCanvas canvas) - { + public void mouseClick(MouseEvent e, Point2D imagePoint, IcyCanvas canvas) { } @Override - public void mouseMove(MouseEvent e, Point2D imagePoint, IcyCanvas canvas) - { + public void mouseMove(MouseEvent e, Point2D imagePoint, IcyCanvas canvas) { } @Override - public void mouseDrag(MouseEvent e, Point2D imagePoint, IcyCanvas canvas) - { + public void mouseDrag(MouseEvent e, Point2D imagePoint, IcyCanvas canvas) { } @Override - public void keyPressed(KeyEvent e, Point2D imagePoint, IcyCanvas canvas) - { + public void keyPressed(KeyEvent e, Point2D imagePoint, IcyCanvas canvas) { } @Override - public void keyReleased(KeyEvent e, Point2D imagePoint, IcyCanvas canvas) - { - - } + public void keyReleased(KeyEvent e, Point2D imagePoint, IcyCanvas canvas) { + }*/ } diff --git a/src/main/resources/msd-track-processor.png b/src/main/resources/msd-track-processor.png new file mode 100644 index 0000000000000000000000000000000000000000..fa3b72f6fc03d67d6a0933995ad63adf0965c753 Binary files /dev/null and b/src/main/resources/msd-track-processor.png differ