/alaspatial/src/main/java/org/ala/spatial/analysis/legend/LegendEqualArea.java

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