/webportal/src/main/java/org/ala/spatial/data/LegendEqualArea.java

http://alageospatialportal.googlecode.com/ · 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. */
  5. package org.ala.spatial.data;
  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(double[] d, int divisions) {
  16. init(d, divisions);
  17. if (Double.isNaN(max)) {
  18. return;
  19. }
  20. cutoffs = new double[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<Double> 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(double[] 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. //
  90. // //fill up with the lower value
  91. // for (int j = start; j < mid; j++) {
  92. // cutoffs[j] = cutoffs[j - 1];
  93. // }
  94. //
  95. // start = i;
  96. // }
  97. // }
  98. //set unqiue end
  99. if (cutoffs[divisions - 1] == cutoffs[divisions - 2]) {
  100. for (int i = divisions - 1; i > 0; i--) {
  101. if (cutoffs[i] != cutoffs[i - 1]) {
  102. for (int j = i; j < divisions - 1; j++) {
  103. cutoffs[j] = cutoffs[j - 1];
  104. }
  105. break;
  106. }
  107. }
  108. }
  109. }
  110. }
  111. private ArrayList<Double> getValuesByFrequency(double[] d, int step) {
  112. int[] uniqueValueDistribution = new int[numberOfUniqueValues];
  113. double[] uniqueValues = new double[numberOfUniqueValues];
  114. int p = 0;
  115. uniqueValues[0] = d[0];
  116. for (int i = 0; i < lastValue; i++) {
  117. if (i > 0 && d[i] != d[i - 1]) {
  118. p++;
  119. uniqueValues[p] = d[i];
  120. }
  121. uniqueValueDistribution[p]++;
  122. }
  123. ArrayList<Double> list = new ArrayList<Double>();
  124. for (int i = 0; i < numberOfUniqueValues; i++) {
  125. if (uniqueValueDistribution[i] >= step) {
  126. list.add(uniqueValues[i]);
  127. }
  128. }
  129. return list;
  130. }
  131. }