#Jeff Hardin, Dept. of Integrative Biology #Univ. of Wisconsin-Madison #jdhardin@wisc.edu #Current version July 26, 2025 #This script imports data from one or more CSV files in the form x[i],y[i] as paired columns #Using JFreeChart allows export as an editable SVG file. from org.jfree.chart import ChartFactory, ChartPanel, JFreeChart from org.jfree.chart.title import LegendTitle from org.jfree.chart.annotations import XYTitleAnnotation from org.jfree.chart.plot import PlotOrientation, XYPlot from org.jfree.data.xy import XYDataset, XYSeries, XYSeriesCollection from org.jfree.chart.plot import PlotOrientation, XYPlot from org.jfree.data.xy import XYDataset, XYSeries, XYSeriesCollection from org.jfree.data.category import DefaultCategoryDataset from org.jfree.chart.ui import RectangleEdge,RectangleInsets,RectangleAnchor from javax.swing import JFrame import java.awt.Color as Color from java.awt import Dimension, BasicStroke import java.awt.Frame as Frame import java.awt.Window as Window from java.io import File as File from java.lang import System as System from ij import WindowManager as WindowManager from ij.plugin.frame import RoiManager as RoiManager from ij.process import ImageStatistics as ImageStatistics from ij.measure import Measurements as Measurements from ij import IJ as IJ from ij.measure import CurveFitter as CurveFitter from ij.gui import Plot as Plot from ij.gui import PlotWindow as PlotWindow from ij.gui import ImageWindow as ImageWindow from ij.gui import GenericDialog from ij import ImagePlus as ImagePlus from ij.io import FileInfo as FileInfo from ij.measure import ResultsTable as ResultsTable from ij import WindowManager as WindowManager import math import os from os import path, mkdir import csv #below from #https://stackoverflow.com/questions/736043/checking-if-a-string-can-be-converted-to-float-in-python def isfloat(value): try: float(value) return True except ValueError: return False def doPlot(): lineseparator = "\n" cellseparator = "," rawFRAPFile = False ## Ask for position of legend gd = GenericDialog("Options") #legendPosition = ["Jfree default", "Inside plot"] gd.addRadioButtonGroup("Legend position:", ["JFree default", "Inside plot"], 1,2,"JFree default") gd.showDialog() if gd.wasOKed(): legendPosition = gd.getNextRadioButton() else: return None #Should really only ask for a single file here, as follows: #od = OpenDialog("Choose file", None) #file_name = od.getFileName() #if None != file_name: #Call below is a feature of Fiji/IJ2 #See https://imagej.net/scripting/parameters #Opener().openImage(od.getDirectory(), file_name).show() k = len(listOfPaths) #for i in range(0, k): #print(listOfPaths[i]) for i in range(0, k): #read in FRAP curve data from CSV file #copies the whole file to an array of lines #have to type cast pathnames to Python str text_file = open(str(listOfPaths[i]), "r") #read whole file to a string data = text_file.read() #close file text_file.close() #separate into lines of text lines=data.split(lineseparator) numRows = len(lines) # recreates the columns headers labels=lines[0].split(cellseparator) #get total columns numCol = len(labels) # Check to see if this is a raw FRAP files with a column called "bleach" for l in range(0,len(labels)): #print(labels[l]) if (labels[l] == "bleach"): #print("This appears to be a raw FRAP file...") rawFRAPFile = True #declare arrays to hold data points x1=[] y1=[] x2=[] y2=[] y3=[] #we'll want xMin and xMax later xMax = float() xMin = float() xMin = 0 xMax = 0 #IJ.open(str(listOfPaths[i])) with open(str(listOfPaths[i]), 'r') as read_obj: # pass the file object to reader() to get the reader object csv_reader = csv.reader(read_obj) # Iterate over each row in the csv using reader object header = next(csv_reader) for row in csv_reader: #need to add code to check for empty cells, since ImageJ #produces CSV files in which there can be unequal numbers of rows with empty cells #Jython interpreter crashes when trying to convert to float if cell is blank #ImageJ plot functions are savvy about blank cells, but this code isn't! if (isfloat(row[0])): x1.append(float(row[0])) if (isfloat(row[1])): y1.append(float(row[1])) if (numCol == 3): if (isfloat(row[2])): y2.append(float(row[2])) if (numCol > 3) and (not rawFRAPFile): if (isfloat(row[2])): x2.append(float(row[2])) if (isfloat(row[3])): y2.append(float(row[3])) if (numCol > 3) and (rawFRAPFile): if (isfloat(row[2])): y2.append(float(row[2])) if (isfloat(row[3])): y3.append(float(row[3])) xMin = min(x1) xMax = max(x1) if (numCol > 3) and (not rawFRAPFile): if (xMax < max(x2)): xMax = max(x2) if (xMin > min(x2)): xMin = min(x2) #Plotting the XY data using ImageJ's Plot function is done as follows, for comoparison #myPlot=Plot("Sample", "X", "Y") #myPlot.setLineWidth(2) #myPlot.add("Line",x1,y1) #myPlot.show() #Now let's plot the XY data using ImageJ's Plot function #have to get arrays into a JFreeChart dataset #series1 = XYSeries("XY") series1 = XYSeries("bleach") #add XY data to series for m in range(0, len(x1)-1): series1.add(x1[m],y1[m]) if (numCol == 3): series2 = XYSeries("Fit") for m in range(0, len(x1)-1): series2.add(x1[m],y2[m]) else: if (numCol == 4) and (not rawFRAPFile): series2 = XYSeries("Fit") for m in range(0, len(x2)-1): series2.add(x2[m],y2[m]) if (numCol == 4) and (rawFRAPFile): series2 = XYSeries(labels[2]) for m in range(0, len(x1)-1): series2.add(x1[m],y2[m]) series3 = XYSeries(labels[3]) for m in range(0, len(x1)-1): series3.add(x1[m],y3[m]) dataset = XYSeriesCollection() #add series to plot dataset.addSeries(series1) if (numCol > 2): dataset.addSeries(series2) if (numCol > 3) and (rawFRAPFile): dataset.addSeries(series3) #next line didnt' work, even thought it's the approved Python method! #print(os.path.basename(listOfPaths[i])) #Use a Java method instead (need JVM 7+) file = File(str(listOfPaths[i])) #get file name using getName() filename = file.getName() chart = ChartFactory.createXYLineChart(filename, "Time (sec)", "Normalized intensity", dataset) plot = chart.getPlot() #Manually set max for X axis; default. #org.jfree.chart.axis.ValueAxis.autoAdjustRange() doesn't give #great results, as it pads the X axis to much. #Can also do this by right-clicking on graph and setting properties. domainAxis = plot.getDomainAxis() domainAxis.setRange(xMin,xMax) r = plot.getRenderer() plot.setBackgroundPaint(Color.white) myDimension = Dimension(600,400) #set title to invisible for single XY plot chart.title.setVisible(False) chartPanel = ChartPanel(chart) chartPanel.setPreferredSize(myDimension) r.setSeriesPaint(0, Color.BLACK) r.setSeriesStroke(0,BasicStroke(float(2.0))) if (numCol > 2): r.setSeriesPaint(1, Color.RED) r.setSeriesStroke(1,BasicStroke(float(2.0))) if (numCol > 3) and (rawFRAPFile): r.setSeriesPaint(2, Color.BLUE) r.setSeriesStroke(2,BasicStroke(float(2.0))) #myStroke = BasicStroke(float(2.0)) #r.setSeriesStroke(0,myStroke) #r.setSeriesStroke(0,BasicStroke(float(2.0))) legend = chart.getLegend() #next lines draw legend using defaults if (legendPosition == "JFree default"): if (numCol == 2): #for now, don't show legend for single curves legend.setVisible(False) else: legend.setPosition(RectangleEdge.TOP) legend.setBorder(1,1,1,1) else: #hide default legend legend.setVisible(False) #Draw legend inside the plot, since default position is outside the plot #from JFreeChart samp[e code lt = LegendTitle(plot) lt.setPosition(RectangleEdge.BOTTOM) lt.setBorder(1,1,1,1) lt.setBackgroundPaint(Color.WHITE) ta = XYTitleAnnotation(0.98, 0.02, lt,RectangleAnchor.BOTTOM_RIGHT) ta.setMaxWidth(0.6) plot.addAnnotation(ta) # Show the chart in an interactive window # where the right-click menu enables saving to PNG or SVG, and adjusting properties frame = JFrame(filename) frame.getContentPane().add(chartPanel) frame.pack() frame.setVisible(True) #main #@ File[] listOfPaths (label="select files", style="files") doPlot()