From 6272ea40412ddbc609ff5fa0fe3e3f1ea2bfbfe5 Mon Sep 17 00:00:00 2001 From: Jan Hansen Date: Fri, 30 Oct 2020 15:32:30 +0100 Subject: [PATCH] Add output of X,Y coordinates of the flagellar track --- pom.xml | 2 +- src/main/java/spermQ/main.java | 11 ++- src/main/java/spermQ/tools2D.java | 134 +++++++++++++++++++++++++++++- src/main/resources/plugins.config | 4 +- 4 files changed, 143 insertions(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index 23cd025..87637ed 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ SpermQ_ - 0.2.1-SNAPSHOT + 0.2.2-SNAPSHOT JNH An ImageJ plugin to analyze the flagellar beat of sperm and sperm steering. Copyright (C) 2017-2020: Jan N. Hansen, Sebastian Rassmann, Jan F. Jikeli, and Dagmar Wachten; research group Biophysical Imaging, Institute of Innate Immunity, Bonn, Germany (http://www.iii.uni-bonn.de/en/wachten_lab/). Funding: DFG priority program SPP 1726 "Microswimmers". This software is part of the following publication: https://www.mdpi.com/2073-4409/8/1/10. diff --git a/src/main/java/spermQ/main.java b/src/main/java/spermQ/main.java index 3c79cb7..5f9e458 100644 --- a/src/main/java/spermQ/main.java +++ b/src/main/java/spermQ/main.java @@ -1,6 +1,6 @@ /***=============================================================================== - SpermQ_.java Version v0.2.1 + SpermQ_.java Version v0.2.2 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -39,7 +39,7 @@ For any questions please feel free to contact me (jan.hansen@uni-bonn.de). public class main implements PlugIn, Measurements{ //Name static final String PLUGINNAME = "SpermQ_"; - static final String PLUGINVERSION = "v0.2.1"; + static final String PLUGINVERSION = "v0.2.2"; static final double threshold = 0.70; //default settings loader @@ -1012,7 +1012,7 @@ public void windowClosing(WindowEvent winEvt) { System.gc(); // tools2D.saveOrientedKymograph(traces, xyCal, savePath, tools2D.NOZ, tools2D.KYMOTANGENTANGLE, 0); tools2D.saveOrientedKymographAsText(traces, xyCal, savePath, tools2D.NOZ, tools2D.KYMOTANGENTANGLE, 0); - System.gc(); + System.gc(); progress.updateBarText("save kymographs and images z ..."); @@ -1028,6 +1028,11 @@ public void windowClosing(WindowEvent winEvt) { tools2D.saveOrientedTraceImage(imp, traces, encoding, savePath, xyCal); System.gc(); + progress.updateBarText("save xy coordinates ..."); + + tools2D.saveXYCoordinates(traces, xyCal, savePath, progress); + System.gc(); + //save progress dialog log file progress.saveLog(dir [task] + saveName + System.getProperty("file.separator") +"log.txt"); diff --git a/src/main/java/spermQ/tools2D.java b/src/main/java/spermQ/tools2D.java index ed36c35..ec6aebe 100644 --- a/src/main/java/spermQ/tools2D.java +++ b/src/main/java/spermQ/tools2D.java @@ -1,6 +1,6 @@ /***=============================================================================== - SpermQ_.java Version 20190926 + SpermQ_.java This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -33,7 +33,6 @@ For any questions please feel free to contact me (jan.hansen@uni-bonn.de). import ij.gui.Roi; import ij.gui.WaitForUserDialog; import ij.process.*; -import ij.process.AutoThresholder.Method; import ij.text.TextPanel; import ij.measure.*; import ij.plugin.frame.RoiManager; @@ -41,6 +40,7 @@ For any questions please feel free to contact me (jan.hansen@uni-bonn.de). import spermQ.jnh.support.*; import spermQ.skeleton_analysis.*; import spermQ.skeletonize3D.Skeletonize3D_; + public class tools2D implements Measurements{ //encodings public static final int NOZ = 0, @@ -1746,6 +1746,136 @@ public static double getKymoTypeParameter (trackPoint2D p, int type, int encodin } } + public static void saveXYCoordinates(ArrayList traces, double calibration, String path, ProgressDialog progress){ + //get arc min max and tmax +// double arcLengthMin = Double.POSITIVE_INFINITY; + double arcLengthMax = Double.NEGATIVE_INFINITY; + int tMax = 0; + progress.notifyMessage("Create XY Coordinate lists: nr of timepoints to save: " + traces.size(), ProgressDialog.LOG); + for(int i = 0; i < traces.size(); i++){ +// if(!traces.get(i).oriented) continue; + if(traces.get(i).getTracePoints().size() <= 0){ + progress.notifyMessage("Create XY Coordinate lists: trace " + i + " harbors 0 points", ProgressDialog.LOG); + continue; + } + if(traces.get(i).getFrame() > tMax){ + tMax = traces.get(i).getFrame(); + } + + for(int j = 0; j < traces.get(i).getTracePoints().size(); j++){ + if(traces.get(i).getTracePoints().get(j).getArcLengthPos() > arcLengthMax){ + arcLengthMax = traces.get(i).getTracePoints().get(j).getArcLengthPos(); + } +// if(traces.get(i).getTracePoints().get(j).getArcLengthPos() < arcLengthMin){ +// arcLengthMin = traces.get(i).getTracePoints().get(j).getArcLengthPos(); +// } + } + } + + progress.notifyMessage("Create XY Coordinate lists: arc length maximum: " + constants.dfdialog.format(arcLengthMax), ProgressDialog.LOG); + + //save all + double values [][] = new double [(int)Math.round(arcLengthMax / calibration)+1][2]; + TextPanel tp = new TextPanel("Results"); + String appText = ""; + //save X + { + tp.clear(); + tp.append("time arc length (micron)"); + appText = ""; + for(int a = 0; a < (int)Math.round(arcLengthMax / calibration)+1; a++){ + appText += " " + constants.df3US.format(a*calibration); + } + tp.append(appText); + + for(int i = 0; i < traces.size(); i++){ + appText = "" + i; + if(traces.get(i).getTracePoints().size() <= 0){ //!traces.get(i).oriented || + tp.append(appText); + continue; + } + // && Double.isNaN(traces.get(i).getThetaDegree(encoding))==false + + for(int a = 0; a < (int)Math.round(arcLengthMax / calibration)+1; a++){ + values [a][0] = 0.0; + values [a][1] = 0.0; + } + + for(int j = 0; j < traces.get(i).getTracePoints().size(); j++){ + try{ + values[(int)Math.round(traces.get(i).getTracePoints().get(j).getArcLengthPos() / calibration)][0] + += traces.get(i).getTracePoints().get(j).getX(); + values[(int)Math.round(traces.get(i).getTracePoints().get(j).getArcLengthPos() / calibration)][1] += 1.0; + }catch (Exception e){ + IJ.log("T" + i + ": problem in kymograph generation..." + " j" + j + " - " + + (int)Math.round(traces.get(i).getTracePoints().get(j).getArcLengthPos() / calibration) + " length " + values.length); + } + } + + for(int a = 0; a < (int)Math.round(arcLengthMax / calibration)+1; a++){ +// IJ.log("j " + j + " i " + i + "xyz" + xyz + " enc " + encoding); +// IJ.log("al " + points.get(j).getArcLengthPos()); +// IJ.log("al " + (int)Math.round(points.get(j).getArcLengthPos() * resolution)); +// IJ.log("corrI " + getCorrectedIntensity8bit (points.get(j).getOrientedVector(encoding)[xyz], min, max)); + appText += " "; + if(values[a][1]>0.0){ + appText += constants.df6US.format(values[a][0]/values[a][1]); + } + } + tp.append(appText); + } + tools2D.addFooter(tp); + tp.saveAs(path + "_coordX.txt"); + } + + //save Y + { + tp.clear(); + tp.append("time arc length (micron)"); + appText = ""; + for(int a = 0; a < (int)Math.round(arcLengthMax / calibration)+1; a++){ + appText += " " + constants.df3US.format(a*calibration); + } + tp.append(appText); + + for(int i = 0; i < traces.size(); i++){ + appText = "" + i; + if(traces.get(i).getTracePoints().size() <= 0){ //!traces.get(i).oriented || + tp.append(appText); + continue; + } + // && Double.isNaN(traces.get(i).getThetaDegree(encoding))==false + + for(int a = 0; a < (int)Math.round(arcLengthMax / calibration)+1; a++){ + values [a][0] = 0.0; + values [a][1] = 0.0; + } + + for(int j = 0; j < traces.get(i).getTracePoints().size(); j++){ + try{ + values[(int)Math.round(traces.get(i).getTracePoints().get(j).getArcLengthPos() / calibration)][0] + += traces.get(i).getTracePoints().get(j).getY(); + values[(int)Math.round(traces.get(i).getTracePoints().get(j).getArcLengthPos() / calibration)][1] += 1.0; + }catch (Exception e){ + IJ.log("T" + i + ": problem in kymograph generation..." + " j" + j + " - " + + (int)Math.round(traces.get(i).getTracePoints().get(j).getArcLengthPos() / calibration) + " length " + values.length); + } + } + + for(int a = 0; a < (int)Math.round(arcLengthMax / calibration)+1; a++){ + appText += " "; + if(values[a][1]>0.0){ + appText += constants.df6US.format(values[a][0]/values[a][1]); + } + } + tp.append(appText); + } + tools2D.addFooter(tp); + tp.saveAs(path + "_coordY.txt"); + } + + } + public static void saveOrientedKymographAsText(ArrayList traces, double calibration, String path, int encoding, int kymoType, int excludeHeadPoints){ double min = getKymographMin(kymoType), max = getKymographMax(kymoType); String xyzText = getKymographTxtLabel(kymoType); diff --git a/src/main/resources/plugins.config b/src/main/resources/plugins.config index 0c88e7b..d2f521c 100644 --- a/src/main/resources/plugins.config +++ b/src/main/resources/plugins.config @@ -22,8 +22,8 @@ # Name: SpermQ # Author: Jan Niklas Hansen -# Version: 0.2.1 +# Version: 0.2.2 # Date: 2016/11/14 # Requires: ImageJ -Plugins>JNH>Analysis, "SpermQ v0.2.1", spermQ.main \ No newline at end of file +Plugins>JNH>Analysis, "SpermQ v0.2.2", spermQ.main \ No newline at end of file