Author: mes Date: 2012-07-11 15:23:00 -0700 (Wed, 11 Jul 2012) New Revision: 29847
Added: csplugins/trunk/ucsd/mes/venneuler/ csplugins/trunk/ucsd/mes/venneuler/pom.xml csplugins/trunk/ucsd/mes/venneuler/src/ csplugins/trunk/ucsd/mes/venneuler/src/main/ csplugins/trunk/ucsd/mes/venneuler/src/main/java/ csplugins/trunk/ucsd/mes/venneuler/src/main/java/edu/ csplugins/trunk/ucsd/mes/venneuler/src/main/java/edu/uic/ csplugins/trunk/ucsd/mes/venneuler/src/main/java/edu/uic/ncdm/ csplugins/trunk/ucsd/mes/venneuler/src/main/java/edu/uic/ncdm/venn/ csplugins/trunk/ucsd/mes/venneuler/src/main/java/edu/uic/ncdm/venn/Eigen.java csplugins/trunk/ucsd/mes/venneuler/src/main/java/edu/uic/ncdm/venn/VennAnalytic.java csplugins/trunk/ucsd/mes/venneuler/src/main/java/edu/uic/ncdm/venn/VennData.java csplugins/trunk/ucsd/mes/venneuler/src/main/java/edu/uic/ncdm/venn/VennDiagram.java csplugins/trunk/ucsd/mes/venneuler/src/main/java/org/ csplugins/trunk/ucsd/mes/venneuler/src/main/java/org/cytoscape/ csplugins/trunk/ucsd/mes/venneuler/src/main/java/org/cytoscape/venneuler/ csplugins/trunk/ucsd/mes/venneuler/src/main/java/org/cytoscape/venneuler/VennEulerLayout.java csplugins/trunk/ucsd/mes/venneuler/src/main/java/org/cytoscape/venneuler/VennEulerLayouter.java csplugins/trunk/ucsd/mes/venneuler/src/test/ csplugins/trunk/ucsd/mes/venneuler/src/test/java/ csplugins/trunk/ucsd/mes/venneuler/src/test/java/org/ csplugins/trunk/ucsd/mes/venneuler/src/test/java/org/cytoscape/ csplugins/trunk/ucsd/mes/venneuler/src/test/java/org/cytoscape/venneuler/ csplugins/trunk/ucsd/mes/venneuler/src/test/java/org/cytoscape/venneuler/FakeVennModel.java csplugins/trunk/ucsd/mes/venneuler/src/test/java/org/cytoscape/venneuler/VennEulerLayoutTest.java csplugins/trunk/ucsd/mes/venneuler/src/test/java/org/cytoscape/venneuler/VennEulerLayouterTest.java Log: added venneuler Added: csplugins/trunk/ucsd/mes/venneuler/pom.xml =================================================================== --- csplugins/trunk/ucsd/mes/venneuler/pom.xml (rev 0) +++ csplugins/trunk/ucsd/mes/venneuler/pom.xml 2012-07-11 22:23:00 UTC (rev 29847) @@ -0,0 +1,73 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + + <modelVersion>4.0.0</modelVersion> + <groupId>org.cytoscape</groupId> + <artifactId>venneuler</artifactId> + <version>1.0.0-SNAPSHOT</version> + + <properties> + <bundle.symbolicName>org.cytoscape.venneuler</bundle.symbolicName> + <bundle.namespace>org.cytoscape.venneuler</bundle.namespace> + <private.namespace>edu.uic.ncdm.venn</private.namespace> + <maven-compiler-plugin.version>2.3.2</maven-compiler-plugin.version> + <maven-bundle-plugin.version>2.3.4</maven-bundle-plugin.version> + </properties> + + <name>${bundle.symbolicName} [${bundle.namespace}]</name> + + <packaging>bundle</packaging> + + <build> + <plugins> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <version>${maven-bundle-plugin.version}</version> + <extensions>true</extensions> + <configuration> + <instructions> + <Bundle-SymbolicName>${bundle.symbolicName}</Bundle-SymbolicName> + <Bundle-Version>${project.version}</Bundle-Version> + <Export-Package>!${private.namespace}.*,${bundle.namespace}.*;version="${project.version}"</Export-Package> + <Private-Package>${private.namespace}.*</Private-Package> + </instructions> + </configuration> + </plugin> + <plugin> + <inherited>true</inherited> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>${maven-compiler-plugin.version}</version> + <configuration> + <source>1.6</source> + <target>1.6</target> + <optimize>true</optimize> + <showWarnings>true</showWarnings> + <showDeprecation>true</showDeprecation> + <compilerArguments> + <Xmaxwarns>10000</Xmaxwarns> + <Xmaxerrs>10000</Xmaxerrs> + </compilerArguments> + </configuration> + </plugin> + </plugins> + </build> + + <dependencies> + <dependency> + <groupId>org.dishevelled</groupId> + <artifactId>dsh-venn</artifactId> + <version>1.0</version> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.8.2</version> + <scope>test</scope> + </dependency> + </dependencies> + +</project> Added: csplugins/trunk/ucsd/mes/venneuler/src/main/java/edu/uic/ncdm/venn/Eigen.java =================================================================== --- csplugins/trunk/ucsd/mes/venneuler/src/main/java/edu/uic/ncdm/venn/Eigen.java (rev 0) +++ csplugins/trunk/ucsd/mes/venneuler/src/main/java/edu/uic/ncdm/venn/Eigen.java 2012-07-11 22:23:00 UTC (rev 29847) @@ -0,0 +1,237 @@ +/* + * VennEuler -- A Venn and Euler Diagram program. + * + * Copyright 2009 by Leland Wilkinson. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License") + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + */ + +package edu.uic.ncdm.venn; + +public class Eigen { + + private Eigen() {} + + public static void eigenSymmetric(double[][] a, double[][] eigenvectors, double[] eigenvalues) { + + // eigenvalues and eigenvectors for dense system (A-lambda*I)x = 0 + // returns eigenvectors in columns + + double[] e = new double[eigenvalues.length]; + Eigen.tred2(a, eigenvectors, eigenvalues, e); + Eigen.imtql2(eigenvectors, eigenvalues, e); + Eigen.sort(eigenvalues, eigenvectors); + } + + private static void tred2(double[][] a, double[][] z, double[] d, double[] e) { + + /* Tridiagonalization of symmetric matrix. + * This generateMethod is a translation of the Algol procedure tred2(), + * Wilkinson and Reinsch, Handbook for Auto. Comp., Vol II-Linear Algebra, (1971). + * Converted to Java by Leland Wilkinson. + */ + + int i, j, jp1, k, l, n; + double f, g, h, hh, scale; + + n = d.length; + for (i = 0; i < n; i++) { + for (j = 0; j <= i; j++) + z[i][j] = a[i][j]; + } + if (n > 1) { + for (i = n - 1; i > 0; i--) { + l = i - 1; + h = 0.0; + scale = 0.0; + if (l > 0) { + for (k = 0; k <= l; k++) + scale += Math.abs(z[i][k]); + } + if (scale == 0.0) + e[i] = z[i][l]; + else { + for (k = 0; k <= l; k++) { + z[i][k] /= scale; + h += z[i][k] * z[i][k]; + } + f = z[i][l]; + g = f < 0.0 ? Math.sqrt(h) : -Math.sqrt(h); + e[i] = scale * g; + h -= f * g; + z[i][l] = f - g; + f = 0.0; + for (j = 0; j <= l; j++) { + z[j][i] = z[i][j] / (scale * h); + g = 0.0; + for (k = 0; k <= j; k++) + g += z[j][k] * z[i][k]; + jp1 = j + 1; + if (l >= jp1) { + for (k = jp1; k <= l; k++) + g += z[k][j] * z[i][k]; + } + e[j] = g / h; + f += e[j] * z[i][j]; + } + hh = f / (h + h); + for (j = 0; j <= l; j++) { + f = z[i][j]; + g = e[j] - hh * f; + e[j] = g; + for (k = 0; k <= j; k++) + z[j][k] = z[j][k] - f * e[k] - g * z[i][k]; + } + for (k = 0; k <= l; k++) + z[i][k] *= scale; + } + d[i] = h; + } + } + d[0] = 0.0; + e[0] = 0.0; + for (i = 0; i < n; i++) { + l = i - 1; + if (d[i] != 0.0) { + for (j = 0; j <= l; j++) { + g = 0.0; + for (k = 0; k <= l; k++) + g += z[i][k] * z[k][j]; + for (k = 0; k <= l; k++) + z[k][j] -= g * z[k][i]; + } + } + d[i] = z[i][i]; + z[i][i] = 1.0; + if (l >= 0) { + for (j = 0; j <= l; j++) { + z[i][j] = 0.0; + z[j][i] = 0.0; + } + } + } + } + + private static int imtql2(double[][] z, double[] d, double[] e) { + + /* Implicit QL iterations on tridiagonalized matrix. + * This generateMethod is a translation of the Algol procedure imtql2(), + * Wilkinson and Reinsch, Handbook for Auto. Comp., Vol II-Linear Algebra, (1971). + * Converted to Java by Leland Wilkinson. + */ + + int i, ii, ip1, j, k, l, lp1, m, mm, mml, n; + double b, c, f, g, p, r, s; + double EPSILON = 1.0e-15; + + n = d.length; + if (n == 1) + return 0; + for (i = 1; i < n; i++) + e[i - 1] = e[i]; + e[n - 1] = 0.0; + mm = 0; + + for (l = 0; l < n; l++) { + lp1 = l + 1; + j = 0; + for (; ;) { + for (m = l; m < n; m++) { + mm = m; + if (m == n - 1) + break; + if (Math.abs(e[m]) <= EPSILON * (Math.abs(d[m]) + Math.abs(d[m + 1]))) + break; + } + m = mm; + p = d[l]; + if (m == l) + break; + if (j == 30) + return l; + j++; + g = (d[lp1] - p) / (2.0 * e[l]); + r = Math.sqrt(g * g + 1.0); + g = d[m] - p + e[l] / (g + (g < 0.0 ? -r : r)); + s = 1.0; + c = 1.0; + p = 0.0; + mml = m - l; + for (ii = 1; ii <= mml; ii++) { + i = m - ii; + ip1 = i + 1; + f = s * e[i]; + b = c * e[i]; + if (Math.abs(f) >= Math.abs(g)) { + c = g / f; + r = Math.sqrt(c * c + 1.0); + e[ip1] = f * r; + s = 1.0 / r; + c *= s; + } else { + s = f / g; + r = Math.sqrt(s * s + 1.0); + e[ip1] = g * r; + c = 1.0 / r; + s *= c; + } + g = d[ip1] - p; + r = (d[i] - g) * s + 2.0 * c * b; + p = s * r; + d[ip1] = g + p; + g = c * r - b; + for (k = 0; k < n; k++) { + f = z[k][ip1]; + z[k][ip1] = s * z[k][i] + c * f; + z[k][i] = c * z[k][i] - s * f; + } + } + d[l] -= p; + e[l] = g; + e[m] = 0.0; + } + } + return 0; + } + + private static void sort(double[] d, double[][] z) { + int l; + int k; + int j; + int i; + int ip1; + double p; + int ii; + int n = d.length; +/* Sort by eigenvalues (descending) */ + for (l = 1; l <= n; l = 3 * l + 1) ; + while (l > 2) { + l = l / 3; + k = n - l; + for (j = 0; j < k; j++) { + i = j; + while (i >= 0) { + ip1 = i + l; + if (d[i] < d[ip1] || Double.isNaN(d[i])) { + p = d[i]; + d[i] = d[ip1]; + d[ip1] = p; + for (ii = 0; ii < n; ii++) { + p = z[ii][i]; + z[ii][i] = z[ii][ip1]; + z[ii][ip1] = p; + } + i = i - l; + } else + break; + } + } + } + } +} Added: csplugins/trunk/ucsd/mes/venneuler/src/main/java/edu/uic/ncdm/venn/VennAnalytic.java =================================================================== --- csplugins/trunk/ucsd/mes/venneuler/src/main/java/edu/uic/ncdm/venn/VennAnalytic.java (rev 0) +++ csplugins/trunk/ucsd/mes/venneuler/src/main/java/edu/uic/ncdm/venn/VennAnalytic.java 2012-07-11 22:23:00 UTC (rev 29847) @@ -0,0 +1,637 @@ +/* + * VennEuler -- A Venn and Euler Diagram program. + * + * Copyright 2009 by Leland Wilkinson. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License") + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + */ + +package edu.uic.ncdm.venn; + +import java.util.HashMap; +import java.util.Map; +import java.util.Iterator; +import java.util.Set; +import java.util.List; +import java.util.ArrayList; +import java.util.HashSet; + + +public class VennAnalytic { + private int nRows; + private int nCircles; + private int nPolygons; + private int nTot; + private double stress; + private double minStress; + private double[] intersectionCounts; + private double[] polyData; + private double[] polyAreas; + private double[] polyHats; + private double[] circleData; + private String[] circleLabels; + private double[][] centers; + private double[] diameters; + private double stepsize; + private double maxArea; + private int totalCount; + private boolean isEqualArea; + +// private static final CyLogger logger = CyLogger.getLogger(VennAnalytic.class); + + public VennAnalytic() { + stepsize = .01; + minStress = .000001; + isEqualArea = false; + } + + public VennDiagram compute(VennData vd) { + String[][] data = vd.data; + double[] areas = vd.areas; + boolean isAreas = vd.isAreas; + + if (isAreas) + processAreaData(data, areas); + else + processElementData(data); + + computeInitialConfiguration(); + scaleDiameters(); + scaleConfiguration(); + + minimizeGlobal(); + minimizeLocal(); + + return collectResults(); + } + + private VennDiagram collectResults() { + double[] colors = new double[nCircles]; + for (int j = 0; j < nCircles; j++) + colors[j] = (double) (j + 1) / (nCircles + 1); + double stress01 = 0; + double stress05 = 0; + if (nCircles > 2) { + stress01 = Math.exp(.909 * (nCircles - 6.105)) / (1 + Math.exp(.909 * (nCircles - 6.105))); + stress05 = Math.exp(.900 * (nCircles - 5.129)) / (1 + Math.exp(.900 * (nCircles - 5.129))); + } + double[] residuals = new double[nPolygons - 1]; + String[] residualLabels = new String[nPolygons - 1]; + boolean[] warnings = new boolean[nPolygons -1]; + double[][] luneCenters = new double[nPolygons -1][2]; + List<Set<String>> luneIds = new ArrayList<Set<String>>(nPolygons -1); + luneIds.add( new HashSet<String>() ); + double area = 0; + int nonZero = 0; + //System.out.println("Num polygons: " + nPolygons); + for (int i = 1; i < nPolygons; i++) { + luneIds.add( new HashSet<String>() ); + residuals[i - 1] = polyAreas[i] - polyHats[i]; + char[] c = encode(i); + //System.out.println("lune i: " + i + " encoded: " + java.util.Arrays.toString(c)); + String s = ""; + double numIntersecting = 0.0; + for (int j = 0; j < c.length; j++) { + if (c[j] == '1') { + s += (circleLabels[j] + "&"); + // record the centers of the circles + luneCenters[i-1][0] += centers[j][0]; + luneCenters[i-1][1] += centers[j][1]; + //System.out.println("luneCenter : " + (i-1) + " adding center: " + j); + numIntersecting += 1.0; + luneIds.get(i-1).add( circleLabels[j] ); + } + } + + // find the lune centers + if ( numIntersecting > 0 ) { + luneCenters[i-1][0] /= numIntersecting; + luneCenters[i-1][1] /= numIntersecting; + } + + area += polyAreas[i]; + if (residuals[i - 1] != 0) + nonZero++; + s = s.substring(0, s.length() - 1); + residualLabels[i - 1] = s; + } +// logger.info("stress = " + stress + ", stress01 = " + stress01 + ", stress05 = " + stress05); + + return new VennDiagram(centers, diameters, polyAreas, residuals, circleLabels, residualLabels, + colors, intersectionCounts, warnings, luneCenters, luneIds, stress, stress01, stress05); + } + + private void processAreaData(String[][] data, double[] areas) { + HashMap<String, Double> sets = new HashMap<String, Double>(); + for (int i = 0; i < data.length; i++) { + String[] s = data[i][0].split("&"); + for (int j = 0; j < s.length; j++) { + if (!sets.containsKey(s[j])) { + Double cat = new Double(sets.size()); + sets.put(s[j], cat); + } + } + } + circleLabels = new String[sets.size()]; + Set<String> keys = sets.keySet(); + Iterator<String> it = keys.iterator(); + while (it.hasNext()) { + String key = it.next(); + int j = sets.get(key).intValue(); + circleLabels[j] = key; + } + nRows = data.length; + nCircles = sets.size(); + nPolygons = (int) Math.pow(2, nCircles); + intersectionCounts = new double[nPolygons]; + polyData = new double[nPolygons]; + polyAreas = new double[nPolygons]; + polyHats = new double[nPolygons]; + circleData = new double[nCircles]; + centers = new double[nCircles][2]; + + double totalArea = 0.0; + for (int i = 0; i < nRows; i++) + totalArea += areas[i]; + + for (int i = 0; i < nRows; i++) { + int[] subsets = new int[nCircles]; + String[] s = data[i][0].split("&"); + for (int j = 0; j < s.length; j++) { + int jj = sets.get(s[j]).intValue(); + subsets[jj] = 1; + } + int k = decode(subsets); + polyData[k] = areas[i]; + for (int j = 0; j < nCircles; j++) { + if (subsets[j] > 0) + circleData[j] += areas[i]; + } + } + for (int i = 0; i < polyData.length; i++) { + intersectionCounts[i] = polyData[i]; + polyData[i] = polyData[i] / totalArea; + } + for (int j = 0; j < nCircles; j++) { + circleData[j] = circleData[j] / totalArea; + if (isEqualArea) + circleData[j] = 1; + } + } + + // If data is a table, then treat each row is two elements long with the + // first element being a value and the second being the set identifier. + // e.g. + // [value a][set 1] + // [value b][set 1] + // [value d][set 1] + // [value a][set 2] + // [value b][set 2] + // [value c][set 2] + // + private void processElementData(String[][] data) { + @SuppressWarnings("unchecked") + HashMap<String,Double>[] categories = new HashMap[2]; + categories[0] = new HashMap<String,Double>(); + categories[1] = new HashMap<String,Double>(); + // create counts of both keys and values + for (int i = 0; i < data.length; i++) { + // element 0 is the value, element 1 is the set key + for (int j = 0; j < 2; j++) { + if (!categories[j].containsKey(data[i][j])) { + Double cat = new Double(categories[j].size()); + categories[j].put(data[i][j], cat); + } + } + } + circleLabels = new String[categories[1].size()]; + Set<String> keys = categories[1].keySet(); + Iterator<String> it = keys.iterator(); + while (it.hasNext()) { + String key = it.next(); + int j = categories[1].get(key).intValue(); + circleLabels[j] = key; + } + nRows = data.length; + nCircles = categories[1].size(); + nPolygons = (int) Math.pow(2, nCircles); + intersectionCounts = new double[nPolygons]; + polyData = new double[nPolygons]; + polyAreas = new double[nPolygons]; + polyHats = new double[nPolygons]; + circleData = new double[nCircles]; + centers = new double[nCircles][2]; + int[][] subsets = new int[categories[0].size()][nCircles]; + for (int i = 0; i < nRows; i++) { + int i1 = categories[0].get(data[i][0]).intValue(); + int j1 = categories[1].get(data[i][1]).intValue(); + subsets[i1][j1]++; + } + for (int i = 0; i < subsets.length; i++) + updateCounts(subsets[i]); + + for (int i = 0; i < polyData.length; i++) { + intersectionCounts[i] = polyData[i]; + polyData[i] = polyData[i] / nTot; + } + for (int j = 0; j < nCircles; j++) { + circleData[j] = circleData[j] / nTot; + if (isEqualArea) + circleData[j] = 1; + } + } + + protected void updateCounts(int[] counts) { + int index = decode(counts); + polyData[index]++; + for (int j = 0; j < counts.length; j++) { + if (counts[j] > 0) + circleData[j]++; + } + nTot++; + } + + private char[] encode(int index) { + String s = Integer.toBinaryString(index); + char[] c = s.toCharArray(); + int offset = nCircles - c.length; + char[] result = new char[nCircles]; + for (int i = 0; i < offset; i++) + result[i] = '0'; + System.arraycopy(c, 0, result, offset, c.length); + return result; + } + + private int decode(int[] subsets) { + String b = ""; + for (int j = 0; j < subsets.length; j++) { + if (subsets[j] > 0) + b += '1'; + else + b += '0'; + } + return Integer.parseInt(b, 2); + } + + private void calculateAreas() { + totalCount = 0; + int size = 200; + byte[][][] bis = new byte[nCircles][size][size]; + double mins = Double.POSITIVE_INFINITY; + double maxs = Double.NEGATIVE_INFINITY; + for (int i = 0; i < nCircles; i++) { + double radius = diameters[i] / 2; + mins = Math.min(centers[i][0] - radius, mins); + mins = Math.min(centers[i][1] - radius, mins); + maxs = Math.max(centers[i][0] + radius, maxs); + maxs = Math.max(centers[i][1] + radius, maxs); + } + for (int i = 0; i < nCircles; i++) { + double xi = (centers[i][0] - mins) / (maxs - mins); + double yi = (centers[i][1] - mins) / (maxs - mins); + double di = diameters[i] / (maxs - mins); + int r = (int) (di * size / 2.); + int r2 = r * r; + int cx = (int) (xi * size); + int cy = (int) (size - yi * size); + for (int x = 0; x < size; x++) { + for (int y = 0; y < size; y++) { + if ((x - cx) * (x - cx) + (y - cy) * (y - cy) < r2) + bis[i][x][y] = 1; + } + } + } + for (int x = 0; x < size; x++) { + for (int y = 0; y < size; y++) { + int[] counts = new int[nCircles]; + int count = 0; + for (int j = 0; j < nCircles; j++) { + if (bis[j][x][y] == 1) { + counts[j]++; + count++; + } + } + if (count > 0) + updatePixels(counts); + } + } + if (totalCount == 0) + return; + for (int i = 0; i < nPolygons; i++) + polyAreas[i] = 100 * polyAreas[i] / totalCount; + } + + private void updatePixels(int[] counts) { + int index = decode(counts); + polyAreas[index]++; + totalCount++; + } + + public void computeInitialConfiguration() { + double[][] s = computeDistanceMatrix(); + if (s == null) { + fixedStart(); + return; + } + + double[] q = new double[nCircles]; + + computeScalarProducts(nCircles, s, q); + + Eigen.eigenSymmetric(s, s, q); + + double rms = Math.sqrt(q[0]) + Math.sqrt(q[1]); + if (Double.isNaN(rms) || rms < .1) { + fixedStart(); + return; + } + for (int i = 0; i < nCircles; i++) { + centers[i][0] = .5 + .25 * s[i][0] * Math.sqrt(q[0]); + centers[i][1] = .5 + .25 * s[i][1] * Math.sqrt(q[1]); + } + } + + private void fixedStart() { + double theta = Math.PI / 2; + double delta = 2 * Math.PI / nCircles; + for (int i = 0; i < nCircles; i++) { + centers[i][0] = .5 + Math.cos(theta); + centers[i][1] = .5 + Math.sin(theta); + theta -= delta; + } + } + + private double[][] computeDistanceMatrix() { + int nIntersections = 0; + double[][] s = new double[nCircles][nCircles]; + for (int i = 0; i < nPolygons; i++) { + char[] c = encode(i); + for (int j = 0; j < c.length; j++) { + if (c[j] == '0') + continue; + for (int k = j + 1; k < c.length; k++) { + if (c[k] == '0') + continue; + s[j][k] += polyData[i]; + s[k][j] = s[j][k]; + nIntersections++; + } + } + } + + for (int j = 0; j < nCircles; j++) { + s[j][j] = 0; + for (int k = 0; k < j; k++) { + s[j][k] = 1 - s[j][k] / (circleData[j] + circleData[k]); + s[k][j] = s[j][k]; + } + } + if (nIntersections < 1) + s = null; + return s; + } + + private void computeScalarProducts(int nPoints, double[][] s, double[] q) { + double rms = 0.; + for (int i = 1; i < nPoints; i++) { + for (int j = 0; j < i; j++) { + double dij = s[i][j] * s[i][j]; + rms += dij + dij; + q[i] += dij; + q[j] += dij; + } + } + + rms = rms / (nPoints * nPoints); + double dsm; + for (int i = 0; i < nPoints; i++) { + for (int j = 0; j <= i; j++) { + if (i == j) + dsm = 0.; + else + dsm = s[i][j] * s[i][j]; + s[i][j] = ((q[i] + q[j]) / nPoints - rms - dsm) / 2.; + s[j][i] = s[i][j]; + } + } + } + + private void scaleDiameters() { + diameters = new double[nCircles]; + for (int j = 0; j < nCircles; j++) + diameters[j] = 2 * Math.sqrt(circleData[j] / Math.PI / nCircles); + } + + private void rescaleDiameters(double[] realDiameters, int iteration) { + if (iteration > 5) { + return; + } else if (iteration == 0) { + double averageDiameter = 0; + for (int j = 0; j < nCircles; j++) + averageDiameter += realDiameters[j]; + averageDiameter /= nCircles; + for (int j = 0; j < nCircles; j++) + diameters[j] = averageDiameter; + } else if (iteration < 5) { + for (int j = 0; j < nCircles; j++) + diameters[j] = diameters[j] - (iteration / 5.0) * (diameters[j] - realDiameters[j]); + } else { + for (int j = 0; j < nCircles; j++) + diameters[j] = realDiameters[j]; + } + } + + private void scaleConfiguration() { + double vc = 0; + for (int j = 0; j < 2; j++) { + double mc = 0; + for (int k = 0; k < nCircles; k++) + mc += centers[k][j]; + mc /= nCircles; + for (int k = 0; k < nCircles; k++) { + centers[k][j] -= mc; + vc += centers[k][j] * centers[k][j]; + } + } + vc = 10. * Math.sqrt(vc / (2 * nCircles)); + if (vc > 0) { + for (int j = 0; j < 2; j++) { + for (int k = 0; k < nCircles; k++) + centers[k][j] /= vc; + } + } + } + + private double computeStress() { + /* regression through origin */ + calculateAreas(); + if (totalCount == 0) { + scaleConfiguration(); + calculateAreas(); + } + double xx = 0; + double xy = 0; + int n = polyData.length; + double sst = 0; + for (int i = 1; i < n; i++) { + double x = polyData[i]; + double y = polyAreas[i]; + xy += x * y; + xx += x * x; + sst += y * y; + } + double slope = xy / xx; + + double sse = 0; + for (int i = 1; i < n; i++) { + double x = polyData[i]; + double y = polyAreas[i]; + double yhat = x * slope; + polyHats[i] = yhat; + sse += (y - yhat) * (y - yhat); + } + return sse / sst; + } + + private void minimizeGlobal() { + double[] initialDiameters = new double[nCircles]; + System.arraycopy(diameters, 0, initialDiameters, 0, nCircles); + double[][] previousCenters = new double[nCircles][2]; + copyCircles(centers, previousCenters); + + double lastStress = 1; + for (int iter = 0; iter < 50; iter++) { + rescaleDiameters(initialDiameters, iter); + recenter(); + stress = computeStress(); + if (stress > lastStress) + copyCircles(previousCenters, centers); + else + copyCircles(centers, previousCenters); +// logger.info("global iteration, loss " + iter + " " + stress); + if (iter > 10 && (stress < minStress || lastStress - stress < minStress)) + break; + moveGlobal(); + lastStress = stress; + } + rescaleDiameters(initialDiameters, 50); + recenter(); + stress = computeStress(); + } + + private void minimizeLocal() { + double[] initialDiameters = new double[nCircles]; + System.arraycopy(diameters, 0, initialDiameters, 0, nCircles); + double[][] initialCenters = new double[nCircles][2]; + copyCircles(centers, initialCenters); + double[][] previousCenters = new double[nCircles][2]; + copyCircles(centers, previousCenters); + double previousStress = stress; + double lastStress = 1; + for (int iter = 0; iter < 50; iter++) { + rescaleDiameters(initialDiameters, iter); + recenter(); + stress = computeStress(); +// logger.debug("local iteration, loss " + iter + " " + stress); + if (stress > lastStress) + copyCircles(previousCenters, centers); + else + copyCircles(centers, previousCenters); + if (iter > 10 && (stress < minStress || lastStress - stress < minStress)) + break; + moveLocal(); + lastStress = stress; + } + rescaleDiameters(initialDiameters, 50); + if (previousStress < stress) + copyCircles(initialCenters, centers); + recenter(); + stress = computeStress(); + } + + private void moveGlobal() { + double[][] gradients = new double[nCircles][2]; + for (int i = 0; i < nPolygons; i++) { + String s = Integer.toBinaryString(i); + char[] c = s.toCharArray(); + int offset = nCircles - c.length; + for (int j = 0; j < c.length; j++) { + if (c[j] == '0') + continue; + int jo = j + offset; + for (int k = j + 1; k < c.length; k++) { + if (c[k] == '0') + continue; + int ko = k + offset; + double resid = polyAreas[i] - polyHats[i]; + double dx = resid * stepsize * (centers[jo][0] - centers[ko][0]); + double dy = resid * stepsize * (centers[jo][1] - centers[ko][1]); + gradients[jo][0] += dx; + gradients[jo][1] += dy; + gradients[ko][0] -= dx; + gradients[ko][1] -= dy; + } + } + } + for (int i = 0; i < nCircles; i++) { + centers[i][0] += gradients[i][0]; + centers[i][1] += gradients[i][1]; + } + } + + private void moveLocal() { + double[][] gradients = new double[nCircles][2]; + for (int i = 0; i < nCircles; i++) { + centers[i][0] += stepsize; + double xPlus = computeStress(); + centers[i][0] -= 2 * stepsize; + double xMinus = computeStress(); + centers[i][0] += stepsize; + if (xPlus < xMinus) + gradients[i][0] = stepsize; + else + gradients[i][0] = -stepsize; + + centers[i][1] += stepsize; + double yPlus = computeStress(); + centers[i][1] -= 2 * stepsize; + double yMinus = computeStress(); + centers[i][1] += stepsize; + if (yPlus < yMinus) + gradients[i][1] = stepsize; + else + gradients[i][1] = -stepsize; + } + for (int i = 0; i < nCircles; i++) { + centers[i][0] += gradients[i][0]; + centers[i][1] += gradients[i][1]; + } + } + + private void recenter() { + double cx = 0; + double cy = 0; + for (int i = 0; i < nCircles; i++) { + cx += centers[i][0]; + cy += centers[i][1]; + } + cx = cx / nCircles; + cy = cy / nCircles; + for (int i = 0; i < nCircles; i++) { + centers[i][0] = .5 + centers[i][0] - cx; + centers[i][1] = .5 + centers[i][1] - cy; + } + } + + private void copyCircles(double[][] a, double[][] b) { + for (int i = 0; i < nCircles; i++) + System.arraycopy(a[i], 0, b[i], 0, 2); + } +} + Added: csplugins/trunk/ucsd/mes/venneuler/src/main/java/edu/uic/ncdm/venn/VennData.java =================================================================== --- csplugins/trunk/ucsd/mes/venneuler/src/main/java/edu/uic/ncdm/venn/VennData.java (rev 0) +++ csplugins/trunk/ucsd/mes/venneuler/src/main/java/edu/uic/ncdm/venn/VennData.java 2012-07-11 22:23:00 UTC (rev 29847) @@ -0,0 +1,27 @@ +/* + * VennEuler -- A Venn and Euler Diagram program. + * + * Copyright 2009 by Leland Wilkinson. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License") + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + */ + +package edu.uic.ncdm.venn; + +public class VennData { + public boolean isAreas; + public double[] areas; + public String[][] data; + + public VennData(String[][] data, double[] areas, boolean isAreas) { + this.data = data; + this.areas = areas; + this.isAreas = isAreas; + } +} Added: csplugins/trunk/ucsd/mes/venneuler/src/main/java/edu/uic/ncdm/venn/VennDiagram.java =================================================================== --- csplugins/trunk/ucsd/mes/venneuler/src/main/java/edu/uic/ncdm/venn/VennDiagram.java (rev 0) +++ csplugins/trunk/ucsd/mes/venneuler/src/main/java/edu/uic/ncdm/venn/VennDiagram.java 2012-07-11 22:23:00 UTC (rev 29847) @@ -0,0 +1,57 @@ +/* + * VennEuler -- A Venn and Euler Diagram program. + * + * Copyright 2009 by Leland Wilkinson. + * + * The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License") + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the License. + */ + +package edu.uic.ncdm.venn; + +import java.util.List; +import java.util.Set; +import java.util.Map; + +public class VennDiagram { + public double[][] centers; + public double[] diameters; + public double[] areas; + public double[] residuals; + public double[] colors; + public double[] counts; + public String[] circleLabels; + public String[] residualLabels; + public boolean[] warnings; + public double[][] luneCenters; + public List<Set<String>> luneIds; + public double stress; + public double stress01; + public double stress05; + + public VennDiagram(double[][] centers, double[] diameters, double[] areas, double[] residuals, + String[] circleLabels, String[] residualLabels, double[] colors, + double[] counts, boolean[] warnings, double[][] luneCenters, + List<Set<String>> luneIds, + double stress, double stress01, double stress05) { + this.centers = centers; + this.diameters = diameters; + this.areas = areas; + this.residuals = residuals; + this.circleLabels = circleLabels; + this.residualLabels = residualLabels; + this.colors = colors; + this.counts = counts; + this.warnings = warnings; + this.luneCenters = luneCenters; + this.luneIds = luneIds; + this.stress = stress; + this.stress01 = stress01; + this.stress05 = stress05; + } +} Added: csplugins/trunk/ucsd/mes/venneuler/src/main/java/org/cytoscape/venneuler/VennEulerLayout.java =================================================================== --- csplugins/trunk/ucsd/mes/venneuler/src/main/java/org/cytoscape/venneuler/VennEulerLayout.java (rev 0) +++ csplugins/trunk/ucsd/mes/venneuler/src/main/java/org/cytoscape/venneuler/VennEulerLayout.java 2012-07-11 22:23:00 UTC (rev 29847) @@ -0,0 +1,122 @@ + +package org.cytoscape.venneuler; + +import org.dishevelled.venn.VennModel; +import org.dishevelled.venn.VennLayout; + +import edu.uic.ncdm.venn.VennDiagram; + +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.geom.Ellipse2D; +import java.awt.Shape; +import java.util.List; +import java.util.ArrayList; + +public final class VennEulerLayout implements VennLayout { + + private final VennDiagram vd; + private final List<Shape> circles; + private final List<Point2D> luneCenters; + private final int size; + private Rectangle2D boundingBox; + private final String decodeBase; + + public VennEulerLayout(VennDiagram vd, Rectangle2D boundingBox) { + this.vd = vd; + this.boundingBox = boundingBox; + this.size = vd.centers.length; + this.circles = new ArrayList<Shape>(size); + this.luneCenters = new ArrayList<Point2D>(vd.luneCenters.length); + decodeBase = calcDecodeBase(vd.centers.length); + createCircles(); + } + + private void createCircles() { + // find the bounds of the circles + double size = Math.min(boundingBox.getWidth(),boundingBox.getHeight()); + double mins = Double.POSITIVE_INFINITY; + double maxs = Double.NEGATIVE_INFINITY; + for (int i = 0; i < vd.centers.length; i++) { + double radius = vd.diameters[i] / 2; + mins = Math.min(vd.centers[i][0] - radius, mins); + mins = Math.min(vd.centers[i][1] - radius, mins); + maxs = Math.max(vd.centers[i][0] + radius, maxs); + maxs = Math.max(vd.centers[i][1] + radius, maxs); + } + + // place the circles within the bounds + for (int i = 0; i < vd.centers.length; i++) { + double xi = (vd.centers[i][0] - mins) / (maxs - mins); + double yi = (vd.centers[i][1] - mins) / (maxs - mins); + double pi = vd.diameters[i] / (maxs - mins); + double pointSize = (pi * size); + double x = (xi * size); + double y = (size - yi * size); + circles.add( new Ellipse2D.Double(x - pointSize / 2, y - pointSize / 2, pointSize, pointSize)); + } + + // this is a dummy point to offset the array indices + luneCenters.add( new Point2D.Double(0.0,0.0) ); + + // find the lune centers within the bounds + for ( int i = 0; i < vd.luneCenters.length; i++ ) { + double xi = (vd.luneCenters[i][0] - mins) / (maxs - mins); + double yi = (vd.luneCenters[i][1] - mins) / (maxs - mins); + double x = (xi * size); + double y = (size - yi * size); + luneCenters.add( new Point2D.Double(x,y) ); + } +// System.out.println("all lune centers: "); +// for ( Point2D p : luneCenters) +// System.out.println(" - " + p); + } + + public int size() { + return size; + } + + public Shape get(int index) { + try { + return circles.get(index); + } catch (Exception e) { + //e.printStackTrace(); + return null; + } + } + + public Point2D luneCenter(int index, int... additional) { + int[] indices = new int[additional.length + 1]; + indices[0] = index; + System.arraycopy(additional,0,indices,1,additional.length); + + return luneCenters.get( decodeLuneCenter(indices) ); + } + + public Rectangle2D boundingRectangle() { + return boundingBox; + } + + // Think of the index into the luneCenters list in binary, where each + // true position in the integer represents a set that should be + // intersected. This method converts an array of SET indices into + // a single integer which represents their intersection and serves + // as an index into luneCenters. + private int decodeLuneCenter(int[] indices) { + StringBuilder binary = new StringBuilder(decodeBase); + for ( int index : indices ) + binary.setCharAt(index,'1'); + String b = binary.toString(); + int x = Integer.parseInt(b,2); +// System.out.println("for indices: " + java.util.Arrays.toString(indices) + " we get: " + b + " which results in index: " + x ); + return x; + } + + private String calcDecodeBase(int num) { + StringBuilder binary = new StringBuilder(); + for ( int i = 0; i < num; i++) + binary.append("0"); + return binary.toString(); + } + +} Added: csplugins/trunk/ucsd/mes/venneuler/src/main/java/org/cytoscape/venneuler/VennEulerLayouter.java =================================================================== --- csplugins/trunk/ucsd/mes/venneuler/src/main/java/org/cytoscape/venneuler/VennEulerLayouter.java (rev 0) +++ csplugins/trunk/ucsd/mes/venneuler/src/main/java/org/cytoscape/venneuler/VennEulerLayouter.java 2012-07-11 22:23:00 UTC (rev 29847) @@ -0,0 +1,79 @@ +package org.cytoscape.venneuler; + +import org.dishevelled.venn.VennModel; +import org.dishevelled.venn.VennLayouter; +import org.dishevelled.venn.VennLayouter.PerformanceHint; +import org.dishevelled.venn.VennLayout; + +import edu.uic.ncdm.venn.VennData; +import edu.uic.ncdm.venn.VennDiagram; +import edu.uic.ncdm.venn.VennAnalytic; + +import java.util.List; +import java.util.ArrayList; +import java.util.Map; +import java.util.HashMap; +import java.awt.geom.Rectangle2D; +import java.awt.geom.Point2D; +import java.awt.Shape; + +public final class VennEulerLayouter<T> { + + private final Map<Integer,List<T>> data = new HashMap<Integer,List<T>>(); + + public VennLayout layout(VennModel<T> model, + Rectangle2D boundingBox, + PerformanceHint performanceHint) { + if ( model == null ) + throw new NullPointerException("model can't be null"); + if ( boundingBox == null ) + throw new NullPointerException("bounding rectangle can't be null"); + if ( model.size() <= 0 ) + throw new IllegalArgumentException("model size can't be 0!"); + + data.clear(); + + // populate data + for ( int i = 0; i < model.size(); i++ ) + for (T t : model.get(i)) + addElement(i,t); + + return create(boundingBox); + } + + private void addElement(int setKey, T setValue) { + if ( setValue == null ) + throw new NullPointerException("set value cannot be null"); + + List<T> values = data.get(setKey); + if ( values == null ) { + values = new ArrayList<T>(); + data.put(setKey,values); + } + values.add(setValue); + } + + private VennLayout create(Rectangle2D boundingBox) { + // convert map into VennData + int numRows = 0; + for ( Integer key : data.keySet() ) + numRows += data.get(key).size(); + + String[][] stringData = new String[numRows][2]; + int i = 0; + for ( Integer key : data.keySet() ) { + String keyString = key.toString(); + for ( T value : data.get(key) ) { + stringData[i][0] = value.toString(); + stringData[i][1] = keyString; + i++; + } + } + VennData vennData = new VennData(stringData,new double[0], false); + + // now create the diagram + VennDiagram vennDiagram = new VennAnalytic().compute(vennData); + + return new VennEulerLayout(vennDiagram,boundingBox); + } +} Added: csplugins/trunk/ucsd/mes/venneuler/src/test/java/org/cytoscape/venneuler/FakeVennModel.java =================================================================== --- csplugins/trunk/ucsd/mes/venneuler/src/test/java/org/cytoscape/venneuler/FakeVennModel.java (rev 0) +++ csplugins/trunk/ucsd/mes/venneuler/src/test/java/org/cytoscape/venneuler/FakeVennModel.java 2012-07-11 22:23:00 UTC (rev 29847) @@ -0,0 +1,53 @@ + +package org.cytoscape.venneuler; + +import org.dishevelled.venn.VennModel; +import java.util.Set; +import java.util.HashSet; +import java.util.Collections; + +public class FakeVennModel implements VennModel<Integer> { + + private final Set<Integer>[] sets; + + public FakeVennModel(Set<Integer> ... sets) { + this.sets = sets; + } + + public FakeVennModel() { + this.sets = new Set[]{}; + } + + public FakeVennModel(int[] ... arraySets) { + this.sets = new Set[arraySets.length]; + for ( int i = 0; i < arraySets.length; i++ ) + this.sets[i] = makeSet(arraySets[i]); + } + + private Set<Integer> makeSet(int[] s) { + Set<Integer> set = new HashSet<Integer>(); + for ( int i : s ) + set.add(i); + return set; + } + + public int size() { + return sets.length; + } + + public Set<Integer> get(int index) { + return sets[index]; + } + + public Set<Integer> union() { + return Collections.emptySet(); + } + + public Set<Integer> intersection() { + return Collections.emptySet(); + } + + public Set<Integer> exclusiveTo(int index, int... additional) { + return Collections.emptySet(); + } +} Added: csplugins/trunk/ucsd/mes/venneuler/src/test/java/org/cytoscape/venneuler/VennEulerLayoutTest.java =================================================================== --- csplugins/trunk/ucsd/mes/venneuler/src/test/java/org/cytoscape/venneuler/VennEulerLayoutTest.java (rev 0) +++ csplugins/trunk/ucsd/mes/venneuler/src/test/java/org/cytoscape/venneuler/VennEulerLayoutTest.java 2012-07-11 22:23:00 UTC (rev 29847) @@ -0,0 +1,213 @@ +package org.cytoscape.venneuler; + +import static org.junit.Assert.*; +import org.junit.Before; +import org.junit.Test; + +import org.dishevelled.venn.VennModel; +import org.dishevelled.venn.VennLayouter; +import org.dishevelled.venn.VennLayouter.PerformanceHint; +import static org.dishevelled.venn.VennLayouter.PerformanceHint.*; +import org.dishevelled.venn.VennLayout; + +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.geom.Point2D; + + +public class VennEulerLayoutTest { + + private VennEulerLayouter layouter; + private Rectangle rect = new Rectangle(100,100); + + @Before + public void setup() { + layouter = new VennEulerLayouter(); + } + + @Test + public void testLayoutNotNull() { + VennLayout vl = layouter.layout( new FakeVennModel( new int[]{1,2}, new int[]{2,3}), + rect, OPTIMIZE_FOR_SPEED); + + assertNotNull(vl); + } + + @Test + public void testCirclesNotNull() { + VennLayout vl = layouter.layout( new FakeVennModel( new int[]{1,2}, new int[]{2,3}), + rect, OPTIMIZE_FOR_SPEED); + + Shape s0 = vl.get(0); + assertNotNull(s0); + + Shape s1 = vl.get(1); + assertNotNull(s1); + } + + @Test + public void testSize() { + VennLayout vl; + + + vl = layouter.layout( new FakeVennModel( new int[]{1,2}), + rect, OPTIMIZE_FOR_SPEED); + assertEquals(1,vl.size()); + + + vl = layouter.layout( new FakeVennModel( new int[]{1,2}, new int[]{2,3}), + rect, OPTIMIZE_FOR_SPEED); + assertEquals(2,vl.size()); + + + vl = layouter.layout( new FakeVennModel( new int[]{1,2}, new int[]{2,3}, new int[]{1,3}), + rect, OPTIMIZE_FOR_SPEED); + assertEquals(3,vl.size()); + } + + @Test + public void testBoundingRect() { + VennLayout vl = layouter.layout( new FakeVennModel( new int[]{1,2}, new int[]{2,3}), + rect, OPTIMIZE_FOR_SPEED); + assertEquals(rect,vl.boundingRectangle()); + } + + @Test + public void testLuneCenter() { + VennLayout vl = layouter.layout( new FakeVennModel( new int[]{1,2}, new int[]{2,3,4}), + rect, OPTIMIZE_FOR_SPEED); + + Point2D p0 = vl.luneCenter(0); + assertTrue(vl.get(0).contains(p0)); + + Point2D p1 = vl.luneCenter(1); + assertTrue(vl.get(1).contains(p1)); + + Point2D p10 = vl.luneCenter(1,0); + assertTrue(vl.get(1).contains(p10)); + assertTrue(vl.get(0).contains(p10)); + } + + @Test + public void testLuneCenter2() { + VennLayout vl = layouter.layout( new FakeVennModel( new int[]{1,2}, new int[]{2,3,4}, new int[]{4,5}), + rect, OPTIMIZE_FOR_SPEED); + + Point2D p0 = vl.luneCenter(0); + assertTrue(vl.get(0).contains(p0)); + + Point2D p1 = vl.luneCenter(1); + assertTrue(vl.get(1).contains(p1)); + + Point2D p2 = vl.luneCenter(2); + assertTrue(vl.get(2).contains(p2)); + + Point2D p10 = vl.luneCenter(1,0); + assertTrue(vl.get(1).contains(p10)); + assertTrue(vl.get(0).contains(p10)); + + Point2D p12 = vl.luneCenter(1,2); + assertTrue(vl.get(1).contains(p12)); + assertTrue(vl.get(2).contains(p12)); + + Point2D p02 = vl.luneCenter(0,2); + assertTrue(vl.get(0).contains(p02)); + assertTrue(vl.get(2).contains(p02)); + + Point2D p012 = vl.luneCenter(0,1,2); + assertTrue(vl.get(0).contains(p012)); + assertTrue(vl.get(1).contains(p012)); + assertTrue(vl.get(2).contains(p012)); + } + + +// public String printShape(Shape s) { +// String x = "shape: "; +// x += "minX: " + s.getBounds2D().getMinX(); +// x += " maxX: " + s.getBounds2D().getMaxX(); +// x += " minY: " + s.getBounds2D().getMinY(); +// x += " maxY: " + s.getBounds2D().getMaxY(); +// return x; +// } + + + + // TODO is this right? Or should we throw an exception? + @Test + public void testBadCircleIndex() { + VennLayout vl = layouter.layout( new FakeVennModel( new int[]{1,2}, new int[]{2,3}), + rect, OPTIMIZE_FOR_SPEED); + Shape s5 = vl.get(5); + assertNull(s5); + } + + @Test + public void testNormalCircleScales() { + testScales(100,100); + } + + @Test + public void testTinyCircleScales() { + testScales(1,1); + } + + private void testScales(int width, int height) { + Rectangle bound = new Rectangle(width,height); + VennLayout vl = layouter.layout( new FakeVennModel( new int[]{1,2}, new int[]{2,3}), + bound, OPTIMIZE_FOR_SPEED); + + Rectangle r0 = vl.get(0).getBounds(); + assertTrue(r0.getWidth() <= bound.getWidth()); + assertTrue(r0.getHeight() <= bound.getHeight()); + + Rectangle r1 = vl.get(1).getBounds(); + assertTrue(r1.getWidth() <= bound.getWidth()); + assertTrue(r1.getHeight() <= bound.getHeight()); + } + + @Test + public void testNormalCircleBounds() { + testBounds(100,100); + } + + @Test + public void testTinyCircleBounds() { + testBounds(1,1); + } + + private void testBounds(int width, int height) { + Rectangle bound = new Rectangle(width,height); + VennLayout vl = layouter.layout( new FakeVennModel( new int[]{1,2}, new int[]{2,3}), + bound, OPTIMIZE_FOR_SPEED); + + Rectangle r0 = vl.get(0).getBounds(); + assertTrue(bound.contains(r0)); + + Rectangle r1 = vl.get(1).getBounds(); + assertTrue(bound.contains(r1)); + } + + @Test + public void testNormalCircleSizes() { + testNonZeroSize(100,100); + } + + @Test + public void testTinyCircleSizes() { + testNonZeroSize(1,1); + } + + private void testNonZeroSize(int width, int height) { + Rectangle bound = new Rectangle(width,height); + VennLayout vl = layouter.layout( new FakeVennModel( new int[]{1,2}, new int[]{2,3}), + bound, OPTIMIZE_FOR_SPEED); + + Rectangle r0 = vl.get(0).getBounds(); + assertTrue(r0.getWidth() > 0.0); + assertTrue(r0.getHeight() > 0.0 ); + + Rectangle r1 = vl.get(1).getBounds(); + assertTrue(r1.getWidth() > 0.0); + assertTrue(r1.getHeight() > 0.0); + } +} Added: csplugins/trunk/ucsd/mes/venneuler/src/test/java/org/cytoscape/venneuler/VennEulerLayouterTest.java =================================================================== --- csplugins/trunk/ucsd/mes/venneuler/src/test/java/org/cytoscape/venneuler/VennEulerLayouterTest.java (rev 0) +++ csplugins/trunk/ucsd/mes/venneuler/src/test/java/org/cytoscape/venneuler/VennEulerLayouterTest.java 2012-07-11 22:23:00 UTC (rev 29847) @@ -0,0 +1,56 @@ +package org.cytoscape.venneuler; + +import static org.junit.Assert.*; +import org.junit.Before; +import org.junit.Test; + + +import org.dishevelled.venn.VennModel; +import org.dishevelled.venn.VennLayouter; +import org.dishevelled.venn.VennLayouter.PerformanceHint; +import static org.dishevelled.venn.VennLayouter.PerformanceHint.*; +import org.dishevelled.venn.VennLayout; +import java.awt.Rectangle; + + +public class VennEulerLayouterTest { + + VennEulerLayouter layouter; + + @Before + public void setup() { + layouter = new VennEulerLayouter(); + } + + @Test(expected=NullPointerException.class) + public void testLayoutNullModel() { + VennLayout vl = layouter.layout( null, new Rectangle(100,200), OPTIMIZE_FOR_SPEED); + } + + @Test(expected=NullPointerException.class) + public void testLayoutNullRect() { + VennLayout vl = layouter.layout( new FakeVennModel( new int[]{1,2}, new int[]{2,3}), + null, OPTIMIZE_FOR_CORRECTNESS); + } + + @Test + public void testLayoutNullPerfHint() { + // we don't use performance hints, so null should be OK + VennLayout vl = layouter.layout( new FakeVennModel( new int[]{1,2}, new int[]{2,3}), + new Rectangle(100,200), null); + assertNotNull(vl); + } + + @Test + public void testLayout() { + VennLayout vl = layouter.layout( new FakeVennModel( new int[]{1,2}, new int[]{2,3}), + new Rectangle(100,200), OPTIMIZE_FOR_SPEED); + assertNotNull(vl); + } + + @Test(expected=IllegalArgumentException.class) + public void testLayoutModelTooSmall() { + VennLayout vl = layouter.layout( new FakeVennModel(), + new Rectangle(100,200), OPTIMIZE_FOR_SPEED); + } +} -- You received this message because you are subscribed to the Google Groups "cytoscape-cvs" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/cytoscape-cvs?hl=en.
