/webportal/src/main/java/org/ala/spatial/data/LegendEqualArea.java
Java | 151 lines | 99 code | 20 blank | 32 comment | 39 complexity | 33e1e4c29f4a5c2aa83266d2f6dd85c1 MD5 | raw file
1/* 2 * To change this template, choose Tools | Templates 3 * and open the template in the editor. 4 */ 5package org.ala.spatial.data; 6 7import java.util.ArrayList; 8 9/** 10 * generates legend using equal size of unique values in 11 * each catagory. 12 * 13 * @author Adam 14 */ 15public class LegendEqualArea extends Legend { 16 17 @Override 18 public void generate(double[] d, int divisions) { 19 init(d, divisions); 20 if (Double.isNaN(max)) { 21 return; 22 } 23 cutoffs = new double[divisions]; 24 25 double scaling = 1; 26 int direction = 0; 27 int pos = 0; 28 while (true) { 29 //calculate step based on remaining info 30 int step = (int) (Math.ceil(numberOfRecords / (double) divisions) * scaling); 31 32 //determine if any 'unique values' require their own division 33 ArrayList<Double> highFrequencyValues = getValuesByFrequency(d, step); 34 35 int count = 0; 36 pos = 0; 37 int i = 0; 38 for (i = 0; i < lastValue && pos < divisions; i++) { 39 if (count >= step 40 || (i + 1 < lastValue && highFrequencyValues.contains(d[i + 1])) 41 || highFrequencyValues.contains(d[i]) 42 || i == lastValue - 1) { 43 while (i + 1 < lastValue && d[i] == d[i + 1]) { 44 i++; 45 count++; 46 } 47 if (i < lastValue) { 48 cutoffs[pos] = d[i]; 49 } else { 50 break; 51 } 52 53 pos++; 54 55 //update step based on remaining info 56 step = (int) (Math.ceil((numberOfRecords - i) / (double) (divisions - pos)) * scaling); 57 58 count = 0; 59 } 60 61 count++; 62 } 63 64 if (i != lastValue && direction >= 0) { 65 //too many divisions, make step larger 66 scaling *= 1.2; 67 direction = 1; 68 } else if (pos < divisions && numberOfUniqueValues > divisions 69 && direction <= 0) { 70 //too few divisions, make step smaller 71 scaling /= 1.2; 72 direction = -1; 73 } else { 74 break; 75 } 76 } 77 78 stretch(cutoffs, divisions, pos); 79 80 //force top 81 cutoffs[cutoffs.length - 1] = max; 82 } 83 84 @Override 85 public String getTypeName() { 86 return "Equal Area"; 87 } 88 89 private void stretch(double[] cutoffs, int divisions, int pos) { 90 if (pos < divisions && pos > 0) { 91 //add spacing 92 double step = divisions / (divisions - pos + 1.0); 93 for (int i = 1; i < divisions - pos + 1; i++) { 94 int min = (int) Math.round(i * step); 95 for (int j = divisions - 1; j >= min; j--) { 96 cutoffs[j] = cutoffs[j - 1]; 97 } 98 } 99 100 //compensate for '<' method by halving the size of cutoff spans of the same value 101// int start = 1; 102// for (int i = 1; i < divisions; i++) { 103// if (cutoffs[i] != cutoffs[i - 1] && (i - start) > 1) { 104// int mid = (i - start) / 2 + start; 105// 106// //fill up with the lower value 107// for (int j = start; j < mid; j++) { 108// cutoffs[j] = cutoffs[j - 1]; 109// } 110// 111// start = i; 112// } 113// } 114 115 //set unqiue end 116 if (cutoffs[divisions - 1] == cutoffs[divisions - 2]) { 117 for (int i = divisions - 1; i > 0; i--) { 118 if (cutoffs[i] != cutoffs[i - 1]) { 119 for (int j = i; j < divisions - 1; j++) { 120 cutoffs[j] = cutoffs[j - 1]; 121 } 122 break; 123 } 124 } 125 } 126 } 127 } 128 129 private ArrayList<Double> getValuesByFrequency(double[] d, int step) { 130 int[] uniqueValueDistribution = new int[numberOfUniqueValues]; 131 double[] uniqueValues = new double[numberOfUniqueValues]; 132 int p = 0; 133 uniqueValues[0] = d[0]; 134 for (int i = 0; i < lastValue; i++) { 135 if (i > 0 && d[i] != d[i - 1]) { 136 p++; 137 uniqueValues[p] = d[i]; 138 } 139 uniqueValueDistribution[p]++; 140 } 141 142 ArrayList<Double> list = new ArrayList<Double>(); 143 for (int i = 0; i < numberOfUniqueValues; i++) { 144 if (uniqueValueDistribution[i] >= step) { 145 list.add(uniqueValues[i]); 146 } 147 } 148 149 return list; 150 } 151}