Graphics_extensions.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. /* Graphics_extensions.cpp
  2. *
  3. * Copyright (C) 2012-2018 David Weenink
  4. *
  5. * This code is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or (at
  8. * your option) any later version.
  9. *
  10. * This code is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this work. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /*
  19. djmw 20120727 latest modification
  20. */
  21. #include "NUM2.h"
  22. #include "Permutation.h"
  23. #include "Graphics_extensions.h"
  24. /*
  25. Draw a box plot of x[1..x.size]. The vertical center line of the plot
  26. is at position 'x'. The rectangle box is 2*w wide, the whisker 2*r.
  27. All drawing outside [ymin, ymax] is clipped.
  28. */
  29. void Graphics_boxAndWhiskerPlot (Graphics g, constVEC data, double x, double r, double w, double ymin, double ymax) {
  30. int lineType = Graphics_inqLineType (g);
  31. Melder_assert (r > 0.0 && w > 0.0);
  32. if (data.size < 3)
  33. return;
  34. /*
  35. Sort the data (ascending: x[1] <= ... <= x[ndata]).
  36. Get the median (q50) and the upper and lower quartile points
  37. (q25 and q75).
  38. Now q25 and q75 are the lower and upper hinges, respectively.
  39. The fances can be calcultaed from q25 and q75.
  40. The spread is defined as the interquartile range or midrange
  41. |q75 - q25|.
  42. The fences are defined as:
  43. (lower/upper) innerfence = (lower/upper) hinge +/- 1.5 hspread
  44. (lower/upper) outerfence = (lower/upper) hinge +/- 3.0 hspread
  45. */
  46. autoVEC sorted = VECcopy (data);
  47. VECsort_inplace (sorted.get());
  48. if (ymax <= ymin) {
  49. ymin = sorted [1];
  50. ymax = sorted [sorted.size];
  51. }
  52. if (sorted [1] > ymax || sorted [sorted.size] < ymin)
  53. return;
  54. double mean = NUMmean (sorted.get());
  55. double q25 = NUMquantile (sorted.get(), 0.25);
  56. double q50 = NUMquantile (sorted.get(), 0.5);
  57. double q75 = NUMquantile (sorted.get(), 0.75);
  58. double hspread = fabs (q75 - q25);
  59. double lowerOuterFence = q25 - 3.0 * hspread;
  60. double lowerInnerFence = q25 - 1.5 * hspread;
  61. double upperInnerFence = q75 + 1.5 * hspread;
  62. double upperOuterFence = q75 + 3.0 * hspread;
  63. /*
  64. Decide whether there are outliers that have to be drawn.
  65. First process sorted from below.
  66. */
  67. integer i = 1, ie = sorted.size;
  68. while (i <= ie && sorted [i] < ymin)
  69. i ++;
  70. Graphics_setTextAlignment (g, Graphics_CENTRE, Graphics_HALF);
  71. while (i <= ie && sorted [i] < lowerOuterFence) {
  72. Graphics_text (g, x, sorted [i], U"o");
  73. i ++;
  74. }
  75. while (i <= ie && sorted[i] < lowerInnerFence) {
  76. Graphics_text (g, x, sorted [i], U"*");
  77. i ++;
  78. }
  79. double lowerWhisker = sorted [i] < q25 ? sorted [i] : lowerInnerFence;
  80. if (lowerWhisker > ymax)
  81. return;
  82. // Next process data from above.
  83. i = sorted.size; ie = i;
  84. while (i >= ie && sorted [i] > ymax)
  85. i --;
  86. while (i >= ie && sorted [i] > upperOuterFence) {
  87. Graphics_text (g, x, sorted [i], U"o");
  88. i --;
  89. }
  90. while (i >= ie && sorted [i] > upperInnerFence) {
  91. Graphics_text (g, x, sorted [i], U"*");
  92. i --;
  93. }
  94. double upperWhisker = sorted [i] > q75 ? sorted [i] : upperInnerFence;
  95. if (upperWhisker < ymin)
  96. return;
  97. /*
  98. Determine what parts of the "box" have to be drawn within the
  99. range [ymin, ymax].
  100. Horizontal lines first.
  101. */
  102. double y1 = lowerWhisker;
  103. if (ymax > y1 && ymin < y1)
  104. Graphics_line (g, x - r, y1, x + r, y1);
  105. y1 = q25;
  106. if (ymax > y1 && ymin < y1)
  107. Graphics_line (g, x - w, y1, x + w, y1);
  108. y1 = q50;
  109. if (ymax > y1 && ymin < y1)
  110. Graphics_line (g, x - w, y1, x + w, y1);
  111. y1 = q75;
  112. if (ymax > y1 && ymin < y1)
  113. Graphics_line (g, x - w, y1, x + w, y1);
  114. y1 = upperWhisker;
  115. if (ymax > y1 && ymin < y1)
  116. Graphics_line (g, x - r, y1, x + r, y1);
  117. // Extension: draw the mean too.
  118. y1 = mean;
  119. if (ymax > y1 && ymin < y1) {
  120. Graphics_setLineType (g, Graphics_DOTTED);
  121. Graphics_line (g, x - w, y1, x + w, y1);
  122. Graphics_setLineType (g, lineType);
  123. }
  124. // Now process the vertical lines.
  125. y1 = lowerWhisker;
  126. double y2 = q25;
  127. if (ymax > y1 && ymin < y2) {
  128. y1 = y1 > ymin ? y1 : ymin;
  129. y2 = y2 < ymax ? y2 : ymax;
  130. Graphics_line (g, x, y1, x, y2);
  131. }
  132. y1 = q25, y2 = q75;
  133. if (ymax > y1 && ymin < y2) {
  134. y1 = y1 > ymin ? y1 : ymin;
  135. y2 = y2 < ymax ? y2 : ymax;
  136. Graphics_line (g, x - w, y1, x - w, y2);
  137. Graphics_line (g, x + w, y1, x + w, y2);
  138. }
  139. y1 = q75, y2 = upperWhisker;
  140. if (ymax > y1 && ymin < y2) {
  141. y1 = y1 > ymin ? y1 : ymin;
  142. y2 = y2 < ymax ? y2 : ymax;
  143. Graphics_line (g, x, y1, x, y2);
  144. }
  145. }
  146. void Graphics_quantileQuantilePlot (Graphics g, integer numberOfQuantiles, constVEC x, constVEC y,
  147. double xmin, double xmax, double ymin, double ymax, int labelSize, conststring32 plotLabel)
  148. {
  149. int fontSize = Graphics_inqFontSize (g);
  150. Graphics_setTextAlignment (g, Graphics_CENTRE, Graphics_HALF);
  151. Graphics_setFontSize (g, labelSize);
  152. autoVEC xsorted = VECcopy (x);
  153. VECsort_inplace (xsorted.get());
  154. autoVEC ysorted = VECcopy (y);
  155. VECsort_inplace (ysorted.get());
  156. integer numberOfData = x.size < y.size ? x.size : y.size;
  157. numberOfQuantiles = numberOfData < numberOfQuantiles ? numberOfData : numberOfQuantiles;
  158. double un = pow (0.5, 1.0 / numberOfQuantiles);
  159. double u1 = 1.0 - un;
  160. if (xmin == xmax) {
  161. xmin = NUMquantile (xsorted.get(), u1);
  162. xmax = NUMquantile (xsorted.get(), un);
  163. }
  164. if (ymin == ymax) {
  165. ymin = NUMquantile (ysorted.get(), u1);
  166. ymax = NUMquantile (ysorted.get(), un);
  167. }
  168. for (integer i = 1; i <= numberOfQuantiles; i++) {
  169. double ui = i == 1 ? u1 : (i == numberOfQuantiles ? un : (i - 0.3175) / (numberOfQuantiles + 0.365));
  170. double qx = NUMquantile (xsorted.get(), ui);
  171. double qy = NUMquantile (ysorted.get(), ui);
  172. if (qx < xmin || qx > xmax || qy < ymin || qy > ymax)
  173. continue; // outside area
  174. Graphics_text (g, qx, qy, plotLabel);
  175. }
  176. Graphics_setLineType (g, Graphics_DOTTED);
  177. Graphics_line (g, xmin, ymin, xmax, ymax);
  178. Graphics_setLineType (g, Graphics_DRAWN);
  179. Graphics_setFontSize (g, fontSize);
  180. }
  181. void Graphics_lagPlot (Graphics g, constVEC data, double xmin, double xmax, integer lag, int labelSize, conststring32 plotLabel)
  182. {
  183. if (lag < 0 || lag >= data.size)
  184. return;
  185. int fontSize = Graphics_inqFontSize (g);
  186. Graphics_setFontSize (g, labelSize);
  187. Graphics_setTextAlignment (g, Graphics_CENTRE, Graphics_HALF);
  188. // plot x[i] vertically and x[i-lag] horizontally
  189. for (integer i = 1; i <= data.size - lag; i++) {
  190. double x = data[i + lag], y = data[i];
  191. if (x >= xmin && x <= xmax && y >= xmin && y <= xmax)
  192. Graphics_text (g, x, y, plotLabel);
  193. }
  194. Graphics_setLineType (g, Graphics_DRAWN);
  195. Graphics_setFontSize (g, fontSize);
  196. }
  197. /* End of file Graphics_extensions.cpp */