diff --git a/.gitignore b/.gitignore index 991feae..709b470 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,8 @@ *.m~ .git.bfg-report build +bin *.jar .*.sw? +.classpath +.project diff --git a/Makefile b/Makefile index 0cb1fa3..73a4cec 100644 --- a/Makefile +++ b/Makefile @@ -10,20 +10,11 @@ ENTRY_POINT = burstiDAtor/BurstiDAtor BUILD_DIR = build/java -SOURCE_FILES = \ -java/burstiDAtor/Burst.java \ -java/burstiDAtor/BurstWizard.java \ -java/burstiDAtor/BurstiDAtor.java \ -java/burstiDAtor/Bursts.java \ -java/burstiDAtor/Props.java \ -java/burstiDAtor/Settings.java \ -java/burstiDAtor/Spikes.java \ -java/burstiDAtor/Utils.java +SOURCE_FILES = $(wildcard java/burstiDAtor/*.java) JAVAC = javac JFLAGS = -encoding UTF-8 - vpath %.class build/java vpath %.java java @@ -37,7 +28,7 @@ Default: @echo "make run: run your app." @echo "make jar: package your project into a executable jar." -build: $(SOURCE_FILES:.java=.class) +build: ${BUILD_DIR} $(SOURCE_FILES:.java=.class) # pattern rule %.class: %.java @@ -58,7 +49,7 @@ clean: run: build java -cp build/java $(ENTRY_POINT) -jar: build +jar: clean build jar cvfe $(JAR_PKG) $(ENTRY_POINT) -C build/java . diff --git a/java/burstiDAtor/AutoCorr.java b/java/burstiDAtor/AutoCorr.java new file mode 100644 index 0000000..813fca7 --- /dev/null +++ b/java/burstiDAtor/AutoCorr.java @@ -0,0 +1,82 @@ +package burstiDAtor; + +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import javax.imageio.ImageIO; + +public class AutoCorr extends Histogram { + public AutoCorr(Spikes spikes) { + super(); + int n_spikes = spikes.length(); + + Settings settings = Settings.getInstance(); + SpikeDelta min_isi = SpikeDelta.fromString(settings.getS("autocorr_min")); + SpikeDelta max_isi = SpikeDelta.fromString(settings.getS("autocorr_max")); + SpikeDelta binwidth = SpikeDelta.fromString(settings.getS("autocorr_binwidth")); + + int n_bins = max_isi.subtract(min_isi).divideCeil(binwidth); + + for (int i = 0; i <= n_bins; i++) { + bins.add((double) i); + if (i= n_bins; + boolean keep = !(too_small || too_large); + if (keep) { + counts.set(bin, 1 + counts.get(bin)); + } + if (too_large) { + break; + } + } + } + } + + public static int getBin(SpikeDelta t_onset, SpikeDelta binwidth, SpikeDelta t) { + int bin = t.subtract(t_onset).divideFloor(binwidth); + return bin; + } + + public BufferedImage getPlot() { + return super.getPlot("time (ms)"); + } + + + public static void main(String... _) throws Exception { + String d = "/Users/nick/tmp/"; + + String[] fns = { "neuron 1 651542.txt", "neuron 2 653286.txt", "Neuron 3 653284.txt" }; + + for (int i = 0; i < fns.length; i++) { + + String fn = "/Users/nick/tmp/" + fns[i]; + File f = new File(fn); + Spikes spikes = new Spikes(f); + AutoCorr ac = new AutoCorr(spikes); + + BufferedImage img = ac.getPlot(); + + try { + // Save as PNG + File file = new File("/Users/nick/tmp/neuron" + (i + 1) + ".png"); + ImageIO.write(img, "png", file); + + } catch (IOException e) { + } + + } + } +} diff --git a/java/burstiDAtor/Burst.java b/java/burstiDAtor/Burst.java index c40a009..b1a46ee 100644 --- a/java/burstiDAtor/Burst.java +++ b/java/burstiDAtor/Burst.java @@ -4,9 +4,9 @@ /** * Contains onset information of spikes in a burst - * + * * @author nick - * + * */ public class Burst { Vector onsets; @@ -20,7 +20,7 @@ public Burst() { /** * add a spike to the burst - * + * * @param onset * time of the spike */ @@ -30,7 +30,7 @@ public void add(double onset) { /** * Compute statistics for this burst - * + * * @param fs * Optional list of property keys to return. If null or empty * then all keys are returned. diff --git a/java/burstiDAtor/BurstWizard.java b/java/burstiDAtor/BurstWizard.java index db5dc0b..da34f91 100644 --- a/java/burstiDAtor/BurstWizard.java +++ b/java/burstiDAtor/BurstWizard.java @@ -1,5 +1,6 @@ package burstiDAtor; +import java.awt.image.BufferedImage; import java.io.File; import java.text.SimpleDateFormat; import java.util.Date; @@ -9,138 +10,177 @@ import javax.swing.JOptionPane; public class BurstWizard { - public static void processDirectory(String dir) throws Exception { - processDirectory(new File(dir)); - } + /* + public static void processDirectory(String dir) throws Exception { + processDirectory(new File(dir)); + }*/ /** * Run the wizard using a previously selected directory */ - public static void processDirectory(File dir) throws Exception { - Vector files = getBurstFiles(dir); - int n = files.size(); - - if (n == 0) { - JOptionPane.showMessageDialog(null, "No files found in " + dir); - return; - } - - Settings s = Settings.getInstance(); - String path = dir.getPath(); - String parent = dir.getParent(); - - s.put("last_source_dir", parent); - - SimpleDateFormat ft = new SimpleDateFormat("yyyy-MM-dd_hh-mm-ss"); - String t = ft.format(new Date()); - String type = s.getS("neuron_type"); - - String pf = s.getS("allfilesprefix"); - String append = s.getS("summaryappend"); - String shortappend = s.getS("shortsummaryappend"); - - String prefix = String.format("%s%s%s%s_%s", path, File.separator, - pf, t, type); - String fnout = prefix + append; - String shortfnout = prefix + shortappend; - String msg = n + " files found\nOutput will be written in:\n" + fnout - + "\nContinue?"; - if (JOptionPane.showConfirmDialog(null, msg) != JOptionPane.OK_OPTION) { - return; - } - - Vector props = new Vector(); - Bursts.StatType st = Bursts.StatType.COLTABLE; - for (int i = 0; i < n; i++) { - File file = files.get(i); - Spikes sp = new Spikes(file); - String line = "[ " + (i + 1) + " / " + n + " ] "; - if (sp.length() == 0) { - line += "no spikes, skipping"; - } else { - Bursts b = new Bursts(sp); - File fileout = Bursts.getCanonicalOuputFile(file); - String report = b.getFullReport(); - Utils.writeToText(fileout, report); - - Props p = b.getStats(st); - props.add(p); - - line += sp.length() + " spikes in"; - } - line += " " + file; - System.out.println(line); - - } - - String fullsummary = Props.getFullTable(props); - Utils.writeToText(new File(fnout), fullsummary); - - final String[] shortsummaryfields = Settings.getInstance() - .getS("shortsummaryfields").split(","); - String shortsummary = Props.getFullTable(props, shortsummaryfields); - Utils.writeToText(new File(shortfnout), shortsummary); + public static void processDirectory(File dir, BurstiDAtor parent) throws Exception { + Vector files = getBurstFiles(dir); + int n = files.size(); + + if (n == 0) { + JOptionPane.showMessageDialog(null, "No files found in " + dir); + return; + } + + boolean showProgress = (parent != null); + + Settings settings = Settings.getInstance(); + + String path = dir.getPath(); + String parent_dir = dir.getParent(); + + boolean writeGraphs = settings.getS("output").equals("graphs"); + + settings.put("last_source_dir", parent_dir); + + SimpleDateFormat ft = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss"); + String t = ft.format(new Date()); + String type = settings.getS("neuron_type"); + + String pf = settings.getS("allfilesprefix"); + String append = settings.getS("summaryappend"); + String shortappend = settings.getS("shortsummaryappend"); + + String prefix = String.format("%s%s%s%s_%s", path, File.separator, pf, t, type); + String fnout = prefix + append; + String shortfnout = prefix + shortappend; + String msg = n + " files found\nOutput will be written in:\n" + fnout + "\nContinue?"; + + if (JOptionPane.showConfirmDialog(null, msg) != JOptionPane.OK_OPTION) { + return; + } + + if (showProgress) { + parent.setProgress(0, n+1); + } + + Vector props = new Vector(); + Bursts.StatType st = Bursts.StatType.COLTABLE; + for (int i = 0; i < n; i++) { + File file = files.get(i); + Spikes sp = new Spikes(file); + String line = "[ " + (i + 1) + " / " + n + " ] "; + if (sp.length() == 0) { + line += "no spikes, skipping"; + } else { + Bursts b = new Bursts(sp); + File fileout = Bursts.getCanonicalOutputFile(file); + String report = b.getFullReport(); + Utils.writeToText(fileout, report); + + Props p = b.getStats(st); + props.add(p); + + line += sp.length() + " spikes in"; + } + + if (writeGraphs) { + AutoCorr ac = new AutoCorr(sp); + File acfileout = Utils.getCanonicalOutputFile(file, "autocorrappend"); + BufferedImage imga = ac.getPlot(); + ac.writeOutputFile(acfileout, imga); + + Density density = new Density(sp); + File densityfileout = Utils.getCanonicalOutputFile(file, "densityappend"); + BufferedImage imgd = density.getPlot(); + ac.writeOutputFile(densityfileout, imgd); + } + line += " " + file; + // System.out.println(line); + + if (showProgress) { + parent.setProgress(i+1, n+1); + } + } + + String fullsummary = Props.getFullTable(props); + Utils.writeToText(new File(fnout), fullsummary); + + final String[] shortsummaryfields = Settings.getInstance().getS("shortsummaryfields").split(","); + String shortsummary = Props.getFullTable(props, shortsummaryfields); + Utils.writeToText(new File(shortfnout), shortsummary); + + if (showProgress) { + parent.setProgress(0, 0); } + } - /** + /** * Run the wizard */ - public static void burstDirectoryWizard(String rootdir, boolean showChooser) throws Exception { - File d = rootdir==null ? null : new File(rootdir); - if (showChooser) { - JFileChooser chooser = new JFileChooser(d); - chooser.setDialogTitle("Select directory with WAVMK txt files"); - chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); - - if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) { - d = chooser.getSelectedFile(); - } - } - - if (d != null) { - processDirectory(d); - } + public static void burstDirectoryWizard(String rootdir, + boolean showChooser, + BurstiDAtor parent) throws Exception { + File d = (rootdir == null) ? null : new File(rootdir); + if (showChooser) { + JFileChooser chooser = new JFileChooser(d); + chooser.setDialogTitle("Select directory with WAVMK txt files"); + chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + + if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) { + d = chooser.getSelectedFile(); + } } - public static void burstDirectoryWizard(String rootdir) throws Exception { - burstDirectoryWizard(rootdir, true); + if (d != null) { + processDirectory(d, parent); + } } - public static void burstDirectoryWizard() throws Exception { - Settings s = Settings.getInstance(); - String dir = null; - if (s.hasKey("last_source_dir")) { - dir = s.getS("last_source_dir"); - } - burstDirectoryWizard(dir); + public static void burstDirectoryWizard(String rootdir, BurstiDAtor parent) throws Exception { + burstDirectoryWizard(rootdir, true, parent); } - - - public static Vector getBurstFiles(File dir) { - if (!dir.isDirectory()) { - return null; - } - Settings settings = Settings.getInstance(); - String ext = settings.getS("inputext").toLowerCase(); - String append = settings.getS("summaryappend"); - - Vector fs = new Vector(); - String path = dir.getPath(); - for (String s : dir.list()) { - String sl = s.toLowerCase(); - - if (sl.endsWith(ext) && !(sl.endsWith(append))) { - fs.add(new File(path + File.separator + s)); - } - } - return fs; + public static void burstDirectoryWizard(BurstiDAtor parent) throws Exception { + Settings s = Settings.getInstance(); + String dir = null; + if (s.hasKey("last_source_dir")) { + dir = s.getS("last_source_dir"); } + burstDirectoryWizard(dir, parent); + } - public static void main(String... _) throws Exception { - String d = "/Users/nick/organized/201_bursts/exampledata/VTA 2 day control"; - d="/Users/nick/Downloads/Wizard test"; - // d=null; - BurstWizard.burstDirectoryWizard(d, false); + public static Vector getBurstFiles(File dir) { + if (!dir.isDirectory()) { + return null; + } + Settings settings = Settings.getInstance(); + String ext = settings.getS("inputext").toLowerCase(); + String append = settings.getS("summaryappend"); + + Vector fs = new Vector(); + String path = dir.getPath(); + for (String s : dir.list()) { + String sl = s.toLowerCase(); + + if (sl.endsWith(ext) && !(sl.endsWith(append))) { + fs.add(new File(path + File.separator + s)); + } } + return fs; + } + + public static void main(String... _) throws Exception { + String d = "/Users/nick/organized/201_bursts/exampledata/VTA 2 day control"; + d = "/Users/nick/burstidator"; + + File folder = new File(d); + File files[] = folder.listFiles(); + // Search .png + for (int i = 0; i < files.length; i++) { + File f = files[i]; + if (f.getName().endsWith(".png")) { + // and deletes + f.delete(); + } + } + + // d=null; + BurstWizard.burstDirectoryWizard(d, false, null); + } } diff --git a/java/burstiDAtor/BurstiDAtor.java b/java/burstiDAtor/BurstiDAtor.java index 61d6cc1..58f7ece 100644 --- a/java/burstiDAtor/BurstiDAtor.java +++ b/java/burstiDAtor/BurstiDAtor.java @@ -1,35 +1,37 @@ package burstiDAtor; +import java.awt.Desktop; import java.awt.FlowLayout; +import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.awt.Desktop; - import java.net.URI; import javax.swing.JButton; import javax.swing.JFrame; +import javax.swing.JPanel; import javax.swing.JOptionPane; +import javax.swing.JProgressBar; public class BurstiDAtor extends JFrame implements ActionListener { private static final long serialVersionUID = 7782961898610924142L; - final static String AUTHORS = "Oosterhof, N.N. & Oosterhof, C.A. (2012-2018)"; + final static String AUTHORS = "Oosterhof, N.N. & Oosterhof, C.A. (2012-2019)"; - final static String VERSION = "0.21"; + final static String VERSION = "0.30wo"; final static String NAME = "burstiDAtor"; - final static String DESC = "a lightweight discharge analysis program for " + final static String DESC = "a lightweight discharge analysis program for " + "neural extracellular single unit recordings"; final static String LICENSE_BODY = "Permission is hereby granted, free " + "of charge, to any person obtaining a copy of this software\n" + "and associated documentation files (the \"Software\"), to " - + "deal in the Software without restriction\n, including without " + + "deal in the Software without restriction, \nincluding without " + "limitation the rights to use, copy, modify, merge, publish, " + "distribute, sublicense,\nand/or sell copies of the Software, " + "and to permit persons to whom the Software is furnished to " - + "do so,\nsubject to the following conditions:\n\nThe above " + + "do so,\nsubject to the following two conditions:\n\n(1) The above " + "copyright notice and this permission notice shall be included " - + "in all copies or substantial portions of the Software.\n\nTHE " + + "in all copies or substantial portions of the Software.\n\n(2)THE " + "SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, " + "EXPRESS\n OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE " + "WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR\n" @@ -38,33 +40,43 @@ public class BurstiDAtor extends JFrame implements ActionListener { + "LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR " + "OTHERWISE,\nARISING FROM, OUT OF OR IN CONNECTION WITH THE " + "SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."; - final static String LICENSE = String.format("Copyright %s\n\n%s", AUTHORS, - LICENSE_BODY); + final static String LICENSE = String.format("%s version %s: copyright %s\n\n%s", + NAME, VERSION, AUTHORS, LICENSE_BODY); final static String URL = "github.com/nno/burstiDAtor"; final static String USE = String.format("If you use this program " + "for a scientific publication, please cite:\n\n" - + "\t%s %s:\n\t%s (version %s)\n\tavailable from %s", + + "\t%s %s:\n\t%s (version %s)\n\tavailable from %s", AUTHORS, NAME, DESC, VERSION, URL); - JButton runWizard, neuronType, settings, about, manual, code, quit; + + JPanel buttons; + JButton runWizard, neuronType, output, settings, about, manual, code, quit; + JProgressBar progressBar; public BurstiDAtor() { - Settings set = Settings.getInstance(); - String type = set.getS("neuron_type"); + buttons = new JPanel(new FlowLayout()); runWizard = addButton("Wizard"); neuronType = addButton(""); + output = addButton(""); settings = addButton("Settings"); about = addButton("About"); manual = addButton("Manual"); code = addButton("Code"); quit = addButton("Quit"); - setTypeCaption(); + changeNeuronTypeText(0); + changeOutputText(0); + + progressBar = new JProgressBar(); + setProgress(0, 0); + + setLayout(new GridLayout(2, 1)); + add(buttons); + add(progressBar); - setLayout(new FlowLayout()); setVisible(true); - setSize(700, 60); + setSize(800, 100); setTitle("BurstiDAtor"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } @@ -73,54 +85,83 @@ private Settings getSettings() { return Settings.getInstance(); } - private void setTypeCaption() { - neuronType.setText("type: " + getSettings().getS("neuron_type")); + public void setProgress(int p, int maximum) { + boolean visible = maximum==0; + + if (visible) { + progressBar.setMaximum(maximum); + progressBar.setValue(p); + } + + progressBar.setVisible(visible); + System.out.format("progress %d / %d\n", p, maximum ); } + private JButton addButton(String n) { JButton b = new JButton(n); - add(b); + buttons.add(b); b.addActionListener(this); return b; } - private void changeNeuronType() { - Settings set = getSettings(); - String type = set.getS("neuron_type"); - String[] supported = set.getS("supported_neuron_types").split(","); + private void setCaption(JButton src_object, String label) { + src_object.setText(label); + } + + + private void changeButtonText(JButton src_object, String prefix, + String key, String supported_key, int delta) { + Settings set = getSettings(); + String type = set.getS(key); + String[] supported = set.getS(supported_key).split(","); int n = supported.length; for (int i=0; i getBursts() { @@ -61,7 +62,7 @@ public Vector getBursts() { // traverse over spikes for (int i = 0; i < nsp; i++) { - double d = sps.get(i); + double d = sps.get(i).doubleValue(); double delta = d - prevonset; if (curburst == null && delta < spstartinterval) { @@ -153,7 +154,7 @@ public static Props individualBurstWizardProps(String rootdir) { if (fc.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) { File filein = fc.getSelectedFile(); - File fileout = getCanonicalOuputFile(filein); + File fileout = getCanonicalOutputFile(filein); props.put("filein", filein); if (fileout == null) { if (fc.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) { @@ -173,26 +174,14 @@ public static Props individualBurstWizardProps(String rootdir) { /** * Gets an output file name for a burst file */ - public static File getCanonicalOuputFile(File inputFile) { - Settings settings = Settings.getInstance(); + public static File getCanonicalOutputFile(File inputFile) { + return Utils.getCanonicalOutputFile(inputFile, "summaryappend"); - String ext = settings.getS("inputext"); - String s = inputFile.getPath(); - if (!s.toLowerCase().endsWith(ext.toLowerCase())) { - return null; - } - - int pos = s.length() - ext.length(); - String s_cut = s.substring(0, pos); - String output_ext = "_" + settings.getS("neuron_type") + settings.getS("summaryappend"); - File outputFile = new File(s_cut + output_ext); - - return outputFile; } /** * Computes - * + * * @param tp statistics type (one of Bursts.StatType. {PAIRTABLE,FULL,COLTABLE} * @return Props object with statistics of spikes and bursts */ @@ -217,9 +206,11 @@ public Props getStats(StatType tp) { return p; } - p.put("firstSp", sps.get(0)); - p.put("lastSp", sps.get(nsp - 1)); - double recdur = sps.get(nsp - 1) - sps.get(0); + double first_spike = sps.get(0).doubleValue(); + double last_spike = sps.get(nsp-1).doubleValue(); + p.put("firstSp", first_spike); + p.put("lastSp", last_spike); + double recdur = last_spike - first_spike ; p.put("recDur", recdur); double rnddur = Settings.getInstance().getD("rndupdur"); @@ -229,17 +220,17 @@ public Props getStats(StatType tp) { double recdurrnd = Math.round(recdur / rnddur + 1 / (2 * rnddur)) * rnddur; p.put("recDurRndUp", recdurrnd); p.put("nSp", nsp); - p.put("avgSpRate", recdur / ((double) nsp)); - p.put("avgSpRateRndUp", recdurrnd / ((double) nsp)); - p.put("avgSpFreq", ((double) nsp) / recdur); - p.put("avgSpFreqRndUp", ((double) nsp) / recdurrnd); + p.put("avgSpRate", recdur / (nsp-1)); + p.put("avgSpRateRndUp", recdurrnd / ((double) (nsp))); + p.put("avgSpFreq", ((double) (nsp-1)) / recdur); + p.put("avgSpFreqRndUp", ((double) (nsp)) / recdurrnd); // feature added April 2018: coefficient of variation double cvi = Double.NaN; // if less than two bursts CVI is not defined if (nsp > 1) { Vector isis = new Vector(); for (int i = 1; i < nsp; i++) { - double isi = sps.get(i) - sps.get(i - 1); + double isi = sps.get(i).doubleValue() - sps.get(i - 1).doubleValue(); isis.add(isi); } double mean_isi = Utils.getStat("mu", isis); diff --git a/java/burstiDAtor/Density.java b/java/burstiDAtor/Density.java new file mode 100644 index 0000000..96de5b3 --- /dev/null +++ b/java/burstiDAtor/Density.java @@ -0,0 +1,119 @@ +package burstiDAtor; + +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; + +import javax.imageio.ImageIO; + +public class Density extends Histogram { + public Density(Spikes spikes) { + super(); + int min_nbins = Settings.getInstance().getI("density_min_bins"); + initialize_bins(min_nbins); + + int n_spikes = spikes.length(); + if (n_spikes < 1) { + return; + } + + Spike start_spike = spikes.get(0); + Spike end_spike = spikes.get(n_spikes-1); + + String step_str = Settings.getInstance().getS("density_step"); + SpikeDelta step = SpikeDelta.fromString(step_str); + + Spike interval_start = start_spike.divideFloor(step); + Spike interval_end = end_spike.divideCeil(step); + System.out.println("" + start_spike + "/" + end_spike); + SpikeDelta full_duration = new SpikeDelta(interval_start, interval_end); + System.out.println("" + full_duration + "/" + interval_start + "/" + interval_end); + int n_intervals = getInterval(interval_start, full_duration, n_spikes, end_spike) + 1; + int[] interval_counts = new int[n_intervals]; + + + for (int i=0; i bins; + Vector counts; + + public Histogram() { + this.bins = new Vector(); + this.counts = new Vector(); + } + + public static int getMaxCount(Vector counts) { + if (counts.size()==0) { + return 0; + } + int max = counts.get(0); + for (int c : counts) { + if (c > max) { + max = c; + } + } + return max; + } + + public static BufferedImage getPlot(Vector bins, + Vector counts, + String ylabel) { + + int mx0 = 40, mx2 = 10; + int my0 = 20, my2 = 40; + + final int approx_width = 800; + final int approx_height = 400; + final int font_size = 12; + final int tickminor = 3, tickmajor = 7; + + // number of bins + int n_bins = bins.size() - 1; + + int ntick_x = 20; + if (n_bins < ntick_x) { + ntick_x = n_bins; + } + int tickx_major = (int) (n_bins / ntick_x); + + + // step in x direction + double dx = ((double) approx_width) / n_bins; + + // max y value + int max_y =(int) (getMaxCount(counts) * 1.1); + + // step in y direction + double dy = ((double) approx_height) / max_y; + + int ticky_major = (int) Math.pow(10, Math.ceil(Math.log10(max_y)) - 1); + int ticky_minor = (int) Math.pow(10, Math.ceil(Math.log10(max_y)) - 2); + + if (ticky_major<=0) { + ticky_major=1; + } + + if (ticky_minor<=0) { + ticky_minor=1; + } + + // width of plot + int mx1 = (int) dx * n_bins; + + // height of plot + int my1 = (int) (dy * max_y); + + int width = mx0 + mx1 + mx2; + int height = my0 + my1 + my2; + + BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + Graphics2D g2d = bufferedImage.createGraphics(); + + Map desktopHints = + (Map) Toolkit.getDefaultToolkit().getDesktopProperty("awt.font.desktophints"); + + + if (desktopHints != null) { + g2d.setRenderingHints(desktopHints); + } + + g2d.setColor(Color.black); + + Font font = new Font("Arial", Font.PLAIN, font_size); + g2d.setFont(font); + FontMetrics fm = g2d.getFontMetrics(); + + // plot x axis + for (int i=0; i headerfields, /** * Computes summary statistics - * + * * @param ps * Vector of properties over which summary stats are computed * @param ws diff --git a/java/burstiDAtor/Settings.java b/java/burstiDAtor/Settings.java index a9587e7..3d64934 100644 --- a/java/burstiDAtor/Settings.java +++ b/java/burstiDAtor/Settings.java @@ -1,5 +1,7 @@ package burstiDAtor; + + public class Settings extends Props { private static Settings me = null; @@ -13,7 +15,22 @@ private Settings() { put("5HT_maxburstcontinue", .02d); put("5HT_minspikesinburst", 2); - put("supported_neuron_types","DA,5HT"); + put("RTN_maxburststart", .01d); + put("RTN_maxburstcontinue", .01d); + put("RTN_minspikesinburst", 2); + + + put("autocorr_min", "0.00000"); + put("autocorr_max", "2.00000"); + put("autocorr_binwidth", "0.01000"); + + put("density_min_bins", 10); + put("density_step", "1.000000"); + + put("supported_outputs","graphs,no graphs"); + put("output", getS("supported_outputs").split(",")[0]); + + put("supported_neuron_types","DA,5HT,RTN"); put("neuron_type",getS("supported_neuron_types").split(",")[0]); put("fieldsep", "\t"); @@ -21,11 +38,15 @@ private Settings() { put("doubleformat", "%.5f"); put("rndupdur", 10d); put("shortsummaryfields", "filename,recDur,recDurRndUp,avgSpFreqRndUp," - + "nBuOrNada,avgBuFreqRndUp,avgBuFreq60RndUp," + + "nBuOrNada,avgBuFreqRndUp,avgBuFreq60RndUp,CVI," + "pctSpInBu,mu_nSp,mu_interSp"); put("inputext", ".txt"); put("summaryappend", "_summary.txt"); put("shortsummaryappend", "_short_summary.txt"); + + put("autocorrappend", "_autocorr.png"); + put("densityappend", "_density.png"); + put("allfilesprefix", "allfiles_"); put("wavemarker", "\"WAVMK\""); } @@ -39,4 +60,6 @@ public static Settings getInstance() { } return me; } + + } diff --git a/java/burstiDAtor/Spike.java b/java/burstiDAtor/Spike.java new file mode 100644 index 0000000..ec090ab --- /dev/null +++ b/java/burstiDAtor/Spike.java @@ -0,0 +1,58 @@ +package burstiDAtor; +import java.math.BigDecimal; +import java.math.MathContext; + +public class Spike { + public static int DECIMALS = 6; + public static long SCALING = (long) Math.pow(10, DECIMALS); + private long onset; + + private Spike(long onset) { + this.onset = onset; + } + + public long getUnscaledOnset() { + return onset; + } + + public double doubleValue() { + return ((double) (onset)) / SCALING; + } + + public SpikeDelta subtract(Spike other) { + return new SpikeDelta(other, this); + } + + public Spike divideFloor(SpikeDelta delta) { + long d = delta.getUnscaled(); + long count = (int) (onset / d); + return new Spike(count * d); + } + + public Spike divideCeil(SpikeDelta delta) { + long d = delta.getUnscaled(); + long count = (int) Math.ceil(((double) onset) / d); + return new Spike(count * d); + } + + + public static Spike fromString(String s) { + BigDecimal bd = new BigDecimal(s); + long onset = bd.multiply(new BigDecimal(SCALING)).longValueExact(); + return new Spike(onset); + } + + public static Spike fromDouble(Double v) { + long onset = (long) (v * SCALING); + return new Spike(onset); + } + + public String toString() { + return "Spike(" + doubleValue() + ")"; + } + + public static void main(String ... args) { + Spike s = Spike.fromString("123.456127"); + System.out.println(s + "/" + s.onset + "/" + s.SCALING); + } +} diff --git a/java/burstiDAtor/SpikeDelta.java b/java/burstiDAtor/SpikeDelta.java new file mode 100644 index 0000000..97c30d3 --- /dev/null +++ b/java/burstiDAtor/SpikeDelta.java @@ -0,0 +1,52 @@ +package burstiDAtor; + +public class SpikeDelta { + private long value; + + private SpikeDelta(long value) { + this.value = value; + } + + public SpikeDelta(Spike first, Spike last) { + this(last.getUnscaledOnset() - first.getUnscaledOnset()); + } + + public SpikeDelta subtract(SpikeDelta other) { + return new SpikeDelta(this.value - other.value); + } + + public int divideFloor(SpikeDelta other) { + return (int) Math.floor(this.value / other.value); + } + + public int divideCeil(SpikeDelta other) { + return (int) Math.ceil(this.value / other.value); + } + + public SpikeDelta multiplyBy(long v) { + return new SpikeDelta(this.value * v); + } + + public static SpikeDelta fromString(String s) { + Spike spike = Spike.fromString(s); + Spike zero = Spike.fromString("0"); + return new SpikeDelta(zero, spike); + } + + public long getUnscaled() { + return value; + } + + public String toString() { + return "SpikeDelta(" + doubleValue() + ")"; + } + + + public double doubleValue() { + return ((double) (value)) / Spike.SCALING; + } + + public double divideBy(int v) { + return ((double) value) / (v); + } +} diff --git a/java/burstiDAtor/Spikes.java b/java/burstiDAtor/Spikes.java index 9acc6ec..19a0d59 100644 --- a/java/burstiDAtor/Spikes.java +++ b/java/burstiDAtor/Spikes.java @@ -5,32 +5,36 @@ import java.io.FileReader; import java.util.Vector; + /** * Represents a set of spike onsets from a txt file - * + * * @author nick - * + * */ public class Spikes { String sourcefile; - Vector onsets; + Vector onsets; + public Spikes(File f) { this.sourcefile = f.getAbsolutePath(); + try { BufferedReader r = new BufferedReader(new FileReader(f)); String line; String wavemarker = Settings.getInstance().getS("wavemarker"); - onsets = new Vector(); + onsets = new Vector(); while ((line = r.readLine()) != null) { String[] split = line.split("\t"); if (split.length < 2) continue; if (split[0].equals(wavemarker)) { - double onset = Double.parseDouble(split[1]); + String onset_string = split[1]; + Spike onset = Spike.fromString(onset_string); onsets.add(onset); } } @@ -40,11 +44,13 @@ public Spikes(File f) { } } - public Spikes(String fn, double... os) { + + public Spikes(String fn, double ... os) { this.sourcefile = fn; - onsets = new Vector(); - for (double o : os) { - onsets.add(o); + + onsets = new Vector(); + for (Double o : os) { + onsets.add(Spike.fromDouble(o)); } } @@ -52,10 +58,21 @@ public int length() { return onsets.size(); } - public double get(int i) { + public Spike get(int i) { return onsets.get(i); } + public double recordingDuration() { + int n = length(); + if (n==0) { + return 0.0; + } + Spike first = get(0); + Spike last = get(n-1); + return last.subtract(first).doubleValue(); + } + + public Spikes(String fn) { this(new File(fn)); } @@ -71,7 +88,7 @@ public String getName() { public String toString() { StringBuffer b = new StringBuffer(); b.append(sourcefile); - for (double onset : onsets) { + for (Spike onset : onsets) { b.append("\n" + onset); } return b.toString(); diff --git a/java/burstiDAtor/Utils.java b/java/burstiDAtor/Utils.java index 2a115b3..a3497f7 100644 --- a/java/burstiDAtor/Utils.java +++ b/java/burstiDAtor/Utils.java @@ -52,4 +52,21 @@ public static void writeToText(File fileout, String s) throws Exception { w.flush(); w.close(); } + + public static File getCanonicalOutputFile(File inputFile, String output_key) { + Settings settings = Settings.getInstance(); + + String ext = settings.getS("inputext"); + String s = inputFile.getPath(); + if (!s.toLowerCase().endsWith(ext.toLowerCase())) { + return null; + } + + int pos = s.length() - ext.length(); + String s_cut = s.substring(0, pos); + String output_ext = "_" + settings.getS("neuron_type") + settings.getS(output_key); + File outputFile = new File(s_cut + output_ext); + + return outputFile; + } } diff --git a/java/tests/burstiDAtor/BurstsTest.java b/java/tests/burstiDAtor/BurstsTest.java index 7b09bf3..25fdaea 100644 --- a/java/tests/burstiDAtor/BurstsTest.java +++ b/java/tests/burstiDAtor/BurstsTest.java @@ -37,10 +37,10 @@ public void test() { for (String k : p0.keyList()) { assertAlmostEqual(p0.get(k), s0.get(k)); } - + Burst b1=bursts.get(1); Props s1=b1.getStats(); - + Props p1=new Props(); p1.put("BuDur",0.02); p1.put("SpFreq", 100.); @@ -49,22 +49,22 @@ public void test() { p1.put("interSp",0.02); p1.put("lastSp",1.44); p1.put("nSp",2); - + for (String k : p1.keyList()) { assertAlmostEqual(p1.get(k), s1.get(k)); } - + } - + public static void assertAlmostEqual(Object v, Object w) { double eps=.0000001; - + if (v instanceof Double && w instanceof Double) { assert(Math.abs(((Double) v)-((Double) w))