package org.seqcode.viz.scatter; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; import java.awt.Paint; import java.awt.geom.Ellipse2D; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Random; import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; import org.jfree.chart.annotations.XYTextAnnotation; import org.jfree.data.xy.DefaultXYDataset; import org.jfree.ui.TextAnchor; import Jama.Matrix; public class ScatterData { protected ArrayList<DefaultXYDataset> datasets = new ArrayList<DefaultXYDataset>(); protected ArrayList<AnnotatedData> data = new ArrayList<AnnotatedData>(); protected ArrayList<XYLineAndShapeRenderer> renderers = new ArrayList<XYLineAndShapeRenderer>(); protected int datasetIndex = -1; public ScatterData(){ } //Accessors public DefaultXYDataset getDataset(int i){if(datasetIndex>=0 && i>=0 && i<=datasetIndex){return datasets.get(i);}else{return null;}} public ArrayList<DefaultXYDataset> getDatasets(){return datasets;} public XYLineAndShapeRenderer getRenderer(int i){if(datasetIndex>=0 && i>=0 && i<=datasetIndex){return renderers.get(i);}else{return null;}} public ArrayList<XYLineAndShapeRenderer> getRenderers(){return renderers;} public int getDatasetIndex(){return datasetIndex;} /** * Add a dataset * @param dset * @parma drawLines: draw lines between points * @param drawShapes: draw the dots */ public void addDataset(AnnotatedData dat){ data.add(dat); DefaultXYDataset dset = new DefaultXYDataset(); dset.addSeries(dat.name, dat.values.transpose().getArray()); datasets.add(dset); XYLineAndShapeRenderer currRend = new XYLineAndShapeRenderer(false, true); currRend.setAutoPopulateSeriesFillPaint(false); renderers.add(currRend); datasetIndex++; } /** * Remove the last dataset added */ public void removeLastDataset(){ data.remove(datasetIndex); datasets.remove(datasetIndex); renderers.remove(datasetIndex); datasetIndex--; } /** * Return the minimum value in all datasets for dimension dim * @param dim * @return */ public double getMin(int dim){ double min=Double.MAX_VALUE; for(AnnotatedData d : data) for(int x=0; x<d.values.getRowDimension(); x++) if(d.values.get(x,dim) < min) min=d.values.get(x,dim); return min; } /** * Return the maximum value in all datasets for dimension dim * @param dim * @return */ public double getMax(int dim){ double max=-Double.MAX_VALUE; for(AnnotatedData d : data) for(int x=0; x<d.values.getRowDimension(); x++) if(d.values.get(x,dim) > max) max=d.values.get(x,dim); return max; } /** * Load a random dataset using createRandomDataset */ public void loadRandomDataset(String name){ addDataset(createRandomDataset(name, 1000)); } /** * Edit the parameters in the renderer * @param i * @param dotSize * @param p */ public void editRenderer(int i, int dotSize, Paint p, boolean drawLines, boolean drawShapes){ XYLineAndShapeRenderer rend = renderers.get(i); rend.setSeriesPaint(0, p); rend.setSeriesShape(0, new Ellipse2D.Double(0, 0, dotSize, dotSize)); rend.setSeriesStroke(0, new BasicStroke(2)); rend.setSeriesLinesVisible(0, drawLines); rend.setSeriesShapesVisible(0, drawShapes); } public void editRenderer(int i, int dotSize, Paint p){editRenderer(i, dotSize, p, false, true);} /** * Get annotated datapoints for a dataset * @param ID * @return */ public List<XYTextAnnotation> getAnnotations(int ID, double xshift,double yshift, TextAnchor anchor, int textSize, int style, Color c){ List<XYTextAnnotation> annot = new ArrayList<XYTextAnnotation>(); for(int i=0; i<data.get(ID).annotations.length; i++){ XYTextAnnotation a = new XYTextAnnotation(data.get(ID).annotations[i], data.get(ID).annotationCoords.get(i,0)+xshift, data.get(ID).annotationCoords.get(i,0)+yshift); a.setFont(new Font("Tahoma", style, textSize)); a.setTextAnchor(anchor); a.setPaint(c); annot.add(a); } return annot; } /** * Load a dataset from a 3-column file * @param f * @param skipLines */ public void loadFileDataset(File f, String name, int skipLines){ try{ ArrayList<String> annots = new ArrayList<String>(); ArrayList<Double> Xdata=new ArrayList<Double>(); ArrayList<Double> Ydata=new ArrayList<Double>(); ArrayList<Double> Xac=new ArrayList<Double>(); ArrayList<Double> Yac=new ArrayList<Double>(); BufferedReader reader = new BufferedReader(new FileReader(f)); String line; int count =0; while ((line = reader.readLine()) != null) { if(count>=skipLines){ line = line.trim(); String[] words = line.split("\\s+"); if(words.length>=3){ annots.add(words[0]); Xdata.add(new Double(words[1])); Ydata.add(new Double(words[2])); if(words.length>=5){ Xac.add(new Double(words[3])); Yac.add(new Double(words[4])); }else{ Xac.add(new Double(words[1])); Yac.add(new Double(words[2])); } } } count++; } int numPoints = Xdata.size(); AnnotatedData dat = new AnnotatedData(name, numPoints); for(int i=0; i<numPoints; i++){ dat.annotations[i] = annots.get(i); dat.values.set(i,0,Xdata.get(i)); dat.values.set(i,1,Ydata.get(i)); dat.annotationCoords.set(i,0,Xac.get(i)); dat.annotationCoords.set(i,1,Yac.get(i)); } addDataset(dat); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * Creates a dataset from a two dimensional array of datapoints. * Assumes that twoDimData is a 2D array (Mx2) * * @param name the series name. * */ public void loadDataset(String name, Matrix twoDimData) { int numPoints = twoDimData.getRowDimension(); AnnotatedData dat = new AnnotatedData(name, numPoints); for(int i=0; i<numPoints; i++){ double x = twoDimData.get(i, 0); double y = twoDimData.get(i, 1); dat.values.set(i,0,x); dat.values.set(i,1,y); dat.annotationCoords.set(i,0,x); dat.annotationCoords.set(i,1,y); dat.annotations[i] = ""+i; } addDataset(dat); } /** * Creates a random dataset. * * @param name the series name. * * @return The dataset. */ private AnnotatedData createRandomDataset(String name, int numPoints) { AnnotatedData dat = new AnnotatedData(name, numPoints); Random generator = new Random(); for(int i=0; i<numPoints; i++){ double x = generator.nextGaussian(); double y = generator.nextGaussian(); dat.values.set(i,0,x); dat.values.set(i,1,y); dat.annotationCoords.set(i,0,x); dat.annotationCoords.set(i,1,y); dat.annotations[i] = "Rand"+i; } return dat; } /** * AnnotatedData: datapoints with names * @author Shaun Mahony * @version %I%, %G% */ private class AnnotatedData{ public String name; public Matrix values; public String [] annotations; public Matrix annotationCoords; public AnnotatedData(String name, int numPoints){ this.name=name; this.values = new Matrix(numPoints, 2); this.annotationCoords = new Matrix(numPoints, 2); this.annotations = new String[numPoints]; } } }