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