package jyplot;
import java.awt.Color;
import java.awt.Rectangle;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import org.jfree.chart.ChartMouseEvent;
import org.jfree.chart.ChartMouseListener;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.ChartRenderingInfo;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.XYPlot;
import cern.colt.list.BooleanArrayList;
import cern.colt.list.IntArrayList;
/**
* Creates a series of bar charts where the bars are stacked
* by the order of present/absent. Basically, values that
* are present for the first time are stacked above the previous
* values.
* @author dion
*
*/
public class BarClusterPlot implements ChartMouseListener
{
/**
* The following are specified in the constructor
*/
boolean[][] booleanarrays;
String[] columnnames;
String[][] columnorders;
String[][] domainlabels;
String[] plottitles;
/*
* Other variables
*/
Jyplot jplot;
ArrayList charts;
HashMap chartToRectGeneMap;
/**
* The list of currently selected genes.
*/
ArrayList genelist;
/**
*
* @param booleanarrays Each column is represented as a boolean array.
* @param columnnames The names of the columns in the boolean arrays
* @param columnorders The order of the columns. The lenght of the array is the number of plots.
* @param domainlabels The labels of domains.
* @param plottitles The titles of the individual plots.
*/
public BarClusterPlot(boolean[][] booleanarrays, String[] columnnames, String[][] columnorders, String[][] domainlabels, String[] plottitles)
{
try
{
this.booleanarrays = booleanarrays;
this.columnnames = columnnames;
this.columnorders = columnorders;
this.domainlabels = domainlabels;
this.plottitles = plottitles;
jplot = new Jyplot();
/*Plotting information*/
int plotCols = columnorders.length/2;
int plotRows = 2;
int plotcount = 1;
genelist = new ArrayList(booleanarrays.length);//Assumes that all arrays are the same length
charts = new ArrayList();
chartToRectGeneMap = new HashMap();
// ArrayList listOfRectGeneListHashMaps = new ArrayList(columnorders.length);
/* Get the column indices belonging to each set of column orders. */
for (int i = 0; i < columnorders.length; i++)
{
IntArrayList booleanArrayIndices = new IntArrayList(columnorders[i].length);
for (int j = 0; j < columnorders[i].length; j++)
{
for (int k = 0; k < columnnames.length; k++)
{
if(columnorders[i][j].equalsIgnoreCase(columnnames[k]))
{
booleanArrayIndices.add(k);
break;
}
}
}
// System.out.println("booleanArrayIndices:\n " + booleanArrayIndices);
/*Then make a boolean array from those selected columns*/
boolean[][] tempBooleanArray= new boolean[booleanarrays.length][booleanArrayIndices.size()];
for (int k = 0; k < booleanarrays.length; k++)
for (int j = 0; j < booleanArrayIndices.size(); j++)
tempBooleanArray[k][j] = booleanarrays[k][booleanArrayIndices.get(j)];
HashMap rectToGeneListMap = computeRectCoords(tempBooleanArray);
jplot.subplot(plotRows, plotCols, plotcount);
plotcount++;
plotBarClusterData(rectToGeneListMap, jplot);
if(domainlabels != null )
//This should not work, its just to make the errors go away
jplot.xticks(new double[] {1,2,3}, domainlabels[i]);
if(plottitles != null )
jplot.title(plottitles[i]);
/* Add the charts and lists to useful data structures */
charts.add(jplot.getChart());
chartToRectGeneMap.put(jplot.getChart(), rectToGeneListMap);
// listOfRectGeneListHashMaps.add();
}
// computeRectCoords
/* Before showing, set the custom ChartPanels*/
HashMap chartPanelMap = jplot.getChartPanelMap();
for (Iterator iter = chartPanelMap.keySet().iterator(); iter.hasNext();)
{
JFreeChart element = (JFreeChart) iter.next();
// BarClusterPlotChartPanel panel = new BarClusterPlotChartPanel(element);
ChartPanel panel = new ChartPanel(element);
panel.addChartMouseListener(this);
chartPanelMap.put(element, panel);
}
this.jplot.connect(this);
jplot.show(500, 500);
}
catch (Exception e)
{
e.printStackTrace();
}
}
public BarClusterPlot()
{}
/**
* Each rect corresponds to a list of indices (e.g. for genes)
* This should be computed once.
* Returns a HashMap of Rectangles to IntArrayList of indices matching the
* Rectangles.
* @param data The first index is the row, second is column.
*/
public HashMap computeRectCoords(boolean[][] data)
{
/**
* Returns an arraylist with one list of rectangles and one list of indices belonging to the rectangles
*/
int rows = data.length;
int cols = data[0].length;
ArrayList indicesLists = new ArrayList();//Matches the computed rectangles
int groups = cols;
/*Create all possible binary arrays up to a given number.*/
ArrayList binArrays = generateAllBinaryArrays((int)Math.pow(2,groups));
binArrays.remove(0);//We are not interested in those with 0 for all rows
/* These are the final results */
HashMap rectangleToIndexArray = new HashMap();
/* Each binary map index corresponds to a list of booleanarrays row indices */
for (int i = 0; i < binArrays.size(); i++)
indicesLists.add( new IntArrayList());
/* Counts how many rows match the given binary array */
int[] countMatches = new int[binArrays.size()];
boolean matches = true;
/*
* Go through all the rows, matching rows with the binArrays
* Essentially this is for counting how many rows match a
* binary array, which then determines how large the rectangle
* is when plotted.
*/
for (int i = 0; i < rows; i++)/* Go through each row*/
{
/* Go though the bin arrays*/
for (int binindex = 0; binindex < binArrays.size(); binindex++)
{
/*
* Stores indices matching a binary array
*/
boolean[] binarray = (boolean[])binArrays.get(binindex);
matches = true;
/* Go through the columns*/
for (int j = 0; j < data[i].length; j++)
if(data[i][j] != binarray[j])
{
matches = false;
break;
}
if(matches)
{
countMatches[binindex]++;
((IntArrayList)indicesLists.get(binindex)).add(i);
break;
}
}
}
/*Each binary array has a pair of coords represented where it can stand in the order
Initially all can go everywhere */
int total = countMatches.length;
int[][] coords = new int[total][2];
/* This means initially all of them can go everywhere */
for (int i = 0; i < coords.length; i++)
{
coords[i][0] = 1;
coords[i][1] = total;
}
/* Start with the first column
* First sum those with 1 in the first position
*/
int totalHeight = 0;
for (int i = 0; i < binArrays.size(); i++)
{
if( ((boolean[])binArrays.get(i))[0] == true)
totalHeight++;
}
for (int i = 0; i < binArrays.size(); i++)
{
if( ((boolean[])binArrays.get(i))[0] == true)
coords[i][1] = totalHeight;
}
/*
* Determine the order of the binarrays
*/
IntArrayList binArrayOrder = new IntArrayList();
int minPositionOfSelectedArrays = 1;
/* Start by going through the columns */
for (int columnIndex = 0; columnIndex < cols; columnIndex++)
{
/* Get the arrays with [0,0...1...] */
IntArrayList localArrayIndices = new IntArrayList();
for (int binArrayIndex = 0; binArrayIndex < binArrays.size(); binArrayIndex++)
{
BooleanArrayList b = new BooleanArrayList(((boolean[])binArrays.get(binArrayIndex)));
if( ( columnIndex == 0 || b.indexOfFromTo(true, 0, columnIndex - 1) == -1 ) && b.get(columnIndex) )
binArrayOrder.add(binArrayIndex);
}
int selectedArrayCount = localArrayIndices.size();
for (int i = 0; i < localArrayIndices.size(); i++)
{
coords[i][0] = minPositionOfSelectedArrays;
coords[i][1] = minPositionOfSelectedArrays + selectedArrayCount - 1;
}
minPositionOfSelectedArrays += selectedArrayCount;
}
/* It also works to just not order the bin arrays*/
// IntArrayList temp = new IntArrayList(binArrayOrder.size());
// for (int i = binArrayOrder.size() - 1; i > -1; i--)
// temp.add(i);
// System.out.println("Before reversing: " + temp);
// binArrayOrder = temp;
/*
* Now compute the actual positions based on the counts and order of the arrays
*/
int currentHeight = 1;
for (int i = 0; i < binArrayOrder.size(); i++)
{
int binarrayindex = binArrayOrder.get(i);//Remember, not just the i as index
int height = countMatches[binarrayindex];
for (int index = 0; index < ((boolean[])binArrays.get(binarrayindex)).length; index++)
{
if( ((boolean[])binArrays.get(binarrayindex))[index] )
{
Rectangle rect = new Rectangle(index, currentHeight, 1, height);
// System.out.println(rect);
rectangleToIndexArray.put(rect, indicesLists.get(binarrayindex));
// rectangles.add(rect);
}
}
currentHeight += height;
}
return rectangleToIndexArray;
}
private ArrayList generateAllBinaryArrays(int size)
{
ArrayList results = new ArrayList(size);
int maxarraylength = denary2Binary(size - 1, 0).length;
for (int i = 0; i < size; i++)
{
results.add( denary2Binary(i, maxarraylength));
}
return results;
}
/**
* Convert denary integer decimalint to binary array
* @param decimalint
* @param maxarraylength
* @return
*/
private boolean[] denary2Binary(int decimalint, int maxarraylength)
{
BooleanArrayList result = new BooleanArrayList(maxarraylength);
if( decimalint < 0)
{
System.err.println("denary2Binary(): must be a positive integer");
return result.elements();
}
if( decimalint == 0)
{
for (int i = 0; i < maxarraylength; i++)
result.add(false);
result.trimToSize();
return result.elements();
}
while( decimalint > 0)
{
result.add((decimalint % 2) > 0);
decimalint = decimalint >> 1;
}
if( result.size() < maxarraylength)
{
for (int i = result.size(); i < maxarraylength; i++)
{
result.add(false);
}
}
result.reverse();
result.trimToSize();
return result.elements();
}
private void plotBarClusterData(HashMap rectToGeneListMap, Jyplot plotter)
{
for (Iterator iter = rectToGeneListMap.keySet().iterator(); iter.hasNext();)
{
Rectangle rect = (Rectangle) iter.next();
plotter.bar((double)rect.getX() - 0.5, rect.getHeight(), rect.getWidth(), rect.getY(), new Color(0.6F,0.6F,0.6F));
}
// String[] s = {"0.5", "1", "3", "6", "12", "24"};
// plotter.xticks(s);
}
public static void main(String[] args)
{
// BarClusterPlot b = new BarClusterPlot();
// System.out.println(Arrays.toString( b.denary2Binary(5,10)));
// ArrayList a = b.generateAllBinaryArrays(5);
// for (int i = 0; i < a.size(); i++)
// {
// System.out.println(Arrays.toString((boolean[])a.get(i)) );
// }
// boolean[][] barray = {{true, false, false}, {false, false, true},{false, true, true}};
// System.out.println("1 0 0\n0 0 1\n0 1 1");
// System.out.println(b.computeRectCoords(barray));
// String f = "/home/dion/storage/projects/plantMicroarrayProject/scripts/graphics/BarClusterPlot/data2.csv";
// NumericTable ntable = new NumericTable(f, NumericTable.BOOLEAN);
// System.out.println("table rows, cols: " + ntable.rows() + ", " + ntable.cols());
// ntable.printRows();
// String[] cols = ntable.getColumnLabels();
// System.out.println("cols:" + Arrays.toString(cols));
// String[][] columnOrders = {{"SALT_30MIN_ROOT", "SALT_1H_ROOT", "SALT_3H_ROOT", "SALT_6H_ROOT", "SALT_12H_ROOT", "SALT_24H_ROOT"}, {"SALT_30MIN_SHOOT", "SALT_1H_SHOOT", "SALT_3H_SHOOT", "SALT_6H_SHOOT", "SALT_12H_SHOOT", "SALT_24H_SHOOT"},{"OSMOTIC_30MIN_ROOT", "OSMOTIC_1H_ROOT", "OSMOTIC_3H_ROOT", "OSMOTIC_6H_ROOT", "OSMOTIC_12H_ROOT", "OSMOTIC_24H_ROOT"},{"OSMOTIC_30MIN_SHOOT", "OSMOTIC_1H_SHOOT", "OSMOTIC_3H_SHOOT", "OSMOTIC_6H_SHOOT", "OSMOTIC_12H_SHOOT", "OSMOTIC_24H_SHOOT"}};
// boolean[][] data = (boolean[][])ntable.getColsAsArray(cols);
//// System.out.println("rows again:" + data[0].length);
// String[][] domainLabels = {{"0.5", "1", "3", "6", "12", "24"}, {"0.5", "1", "3", "6", "12", "24"},{"0.5", "1", "3", "6", "12", "24"},{"0.5", "1", "3", "6", "12", "24"}};
// String[] plottitles = {"Salt Root", "Salt Shoot", "Osmotic Root", "Osmotic Shoot"};
//
// BarClusterPlot b = new BarClusterPlot(data, cols, columnOrders, domainLabels, plottitles);
}
public void chartMouseClicked(ChartMouseEvent event)
{
JFreeChart chart = event.getChart();
int x = event.getTrigger().getX();
int y = event.getTrigger().getY();
// BaseChartPanel panel = (BaseChartPanel) event.getTrigger().getComponent();
ChartPanel panel = (ChartPanel) event.getTrigger().getComponent();
// if(panel.zoomRectangle != null && (panel.zoomRectangle.getHeight() > 30 || panel.zoomRectangle.getWidth() > 30))
// {
// System.out.println(panel.zoomRectangle);
// return;
// }
// System.out.println("zoomRectangle" + panel.zoomRectangle);
/* The following translation takes account of the fact that the
* chart image may have been scaled up or down to fit the panel...
* Point2D p = this.panel.translateScreenToJava2D(new Point(x, y));
*/
/* Now convert the Java2D coordinate to axis coordinates...*/
XYPlot plot = chart.getXYPlot();
ChartRenderingInfo info = panel.getChartRenderingInfo();
Rectangle2D dataArea = info.getPlotInfo().getDataArea();
double xdata = plot.getDomainAxis().java2DToValue(x, dataArea, plot.getDomainAxisEdge());
double ydata = plot.getRangeAxis().java2DToValue(y, dataArea, plot.getRangeAxisEdge());
xdata += 0.5;/* HACK: To adjust for sliding the bars by -0.5 to make the xticks look nice*/
System.out.println(xdata + " " + ydata);
if(!this.charts.contains(chart))
{
System.out.println("Chart not contained in charts");
return;
}
//
// genelist = None
//
// rectlist = self.rectGeneData[chartindex][0]
// rectToGenelistMap = self.rectGeneData[chartindex][1]
for (Iterator iter = ((HashMap)this.chartToRectGeneMap.get(chart)).keySet().iterator(); iter.hasNext();)
{
// System.out.println(iter.next().getClass().getName());
Rectangle rect = (Rectangle) iter.next();
// Rectangle rect = new Rectangle();
// for rect in rectlist:
if(rect.contains(xdata, ydata))
{
// if rect.contains(xdata, ydata):
// if()
// if self.alreadycomputed.has_key(rect):
// self.plotOverlay(self.jfreechartlist, self.rectGeneData, genelist, datasets=self.alreadycomputed[rect])
// else:
IntArrayList genelist = (IntArrayList)this.chartToRectGeneMap.get(rect);
System.out.println("Clicked rect "+ rect);
// # print "Clicked genelist ", len(genelist)
// self.alreadycomputed[rect] = self.plotOverlay(self.jfreechartlist, self.rectGeneData, genelist)
// this.plotOverlay(self.jfreechartlist, self.rectGeneData, genelist)
break;
}
}
}
public void chartMouseMoved(ChartMouseEvent event)
{
}
}
Ads help maintain this website.