1######################################################################## 2## 3## Copyright (C) 2007-2021 The Octave Project Developers 4## 5## See the file COPYRIGHT.md in the top-level directory of this 6## distribution or <https://octave.org/copyright/>. 7## 8## This file is part of Octave. 9## 10## Octave is free software: you can redistribute it and/or modify it 11## under the terms of the GNU General Public License as published by 12## the Free Software Foundation, either version 3 of the License, or 13## (at your option) any later version. 14## 15## Octave is distributed in the hope that it will be useful, but 16## WITHOUT ANY WARRANTY; without even the implied warranty of 17## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18## GNU General Public License for more details. 19## 20## You should have received a copy of the GNU General Public License 21## along with Octave; see the file COPYING. If not, see 22## <https://www.gnu.org/licenses/>. 23## 24######################################################################## 25 26## -*- texinfo -*- 27## @deftypefn {} {} rose (@var{th}) 28## @deftypefnx {} {} rose (@var{th}, @var{nbins}) 29## @deftypefnx {} {} rose (@var{th}, @var{bins}) 30## @deftypefnx {} {} rose (@var{hax}, @dots{}) 31## @deftypefnx {} {@var{h} =} rose (@dots{}) 32## @deftypefnx {} {[@var{thout} @var{rout}] =} rose (@dots{}) 33## Plot an angular histogram. 34## 35## With one vector argument, @var{th}, plot the histogram with 20 angular bins. 36## If @var{th} is a matrix then each column of @var{th} produces a separate 37## histogram. 38## 39## If @var{nbins} is given and is a scalar, then the histogram is produced with 40## @var{nbin} bins. If @var{bins} is a vector, then the center of each bin is 41## defined by the values in @var{bins} and the number of bins is 42## given by the number of elements in @var{bins}. 43## 44## If the first argument @var{hax} is an axes handle, then plot into this axes, 45## rather than the current axes returned by @code{gca}. 46## 47## The optional return value @var{h} is a vector of graphics handles to the 48## line objects representing each histogram. 49## 50## If two output arguments are requested then no plot is made and 51## the polar vectors necessary to plot the histogram are returned instead. 52## 53## Example 54## 55## @example 56## @group 57## [th, r] = rose ([2*randn(1e5,1), pi + 2*randn(1e5,1)]); 58## polar (th, r); 59## @end group 60## @end example 61## 62## Programming Note: When specifying bin centers with the @var{bins} input, 63## the edges for bins 2 to N-1 are spaced so that @code{@var{bins}(i)} is 64## centered between the edges. The final edge is drawn halfway between bin N 65## and bin 1. This guarantees that all input @var{th} will be placed into one 66## of the bins, but also means that for some combinations bin 1 and bin N may 67## not be centered on the user's given values. 68## @seealso{hist, polar} 69## @end deftypefn 70 71function [thout, rout] = rose (varargin) 72 73 [hax, varargin, nargin] = __plt_get_axis_arg__ ("rose", varargin{:}); 74 75 if (nargin < 1) 76 print_usage (); 77 endif 78 79 th = varargin{1}; 80 ## Force theta to [0,2*pi] range 81 th = atan2 (sin (th), cos (th)); 82 th(th < 0) += 2*pi; 83 84 custom_bins = false; 85 if (nargin == 1) 86 bins = [1/40 : 1/20 : 1] * 2*pi; 87 else 88 bins = varargin{2}; 89 if (isscalar (bins)) 90 bins = [0.5/bins : 1/bins : 1] * 2*pi; 91 else 92 custom_bins = true; 93 ## Force angles to [0,2*pi] range 94 bins = atan2 (sin (bins), cos (bins)); 95 bins(bins < 0) += 2*pi; 96 bins = unique (bins); 97 endif 98 endif 99 if (numel (bins) < 3) 100 warning ("rose: bin sizes >= pi will not plot correctly"); 101 endif 102 103 [counts, binctr] = hist (th, bins); 104 binctr = binctr(:).'; # Force row vector 105 if (isvector (counts)) 106 counts = counts(:); 107 endif 108 109 binedge = binctr(1:end-1) + diff (binctr) / 2; 110 binedge = [binedge ; zeros(size(binedge)); zeros(size(binedge)); binedge]; 111 binedge = binedge(:); 112 if (! custom_bins) 113 ## Add in implicit edges at 0 and 2*pi 114 th = [0; 0; binedge; 2*pi ; 0]; 115 else 116 ## Add in final edge 117 last_bin_edge = binctr(end) + diff ([binctr(end), (2*pi+binctr(1))])/2; 118 if ((binedge(end) + last_bin_edge)/2 != binctr(end)) 119 warning ("rose: bin 1 and bin %d are not centered", numel (binctr)); 120 endif 121 th = [0; last_bin_edge; binedge; last_bin_edge; 0]; 122 endif 123 124 r = zeros (4 * rows (counts), columns (counts)); 125 r(2:4:end, :) = counts; 126 r(3:4:end, :) = counts; 127 128 if (nargout < 2) 129 oldfig = []; 130 if (! isempty (hax)) 131 oldfig = get (0, "currentfigure"); 132 endif 133 unwind_protect 134 hax = newplot (hax); 135 htmp = polar (th, r); 136 unwind_protect_cleanup 137 if (! isempty (oldfig)) 138 set (0, "currentfigure", oldfig); 139 endif 140 end_unwind_protect 141 142 if (nargout > 0) 143 thout = htmp; 144 endif 145 else 146 thout = th; 147 rout = r; 148 endif 149 150endfunction 151 152 153%!demo 154%! clf; 155%! rose (2*randn (1e5, 1), 8); 156%! title ("rose() angular histogram plot with 8 bins"); 157 158%!demo 159%! clf; 160%! rose ([2*randn(1e5, 1), pi + 2*randn(1e5, 1)]); 161%! title ("rose() angular histogram plot with 2 data series"); 162 163%!demo 164%! clf; 165%! rose ([0, 2, 3, 5], [0, pi/2, pi, 3*pi/2]); 166%! title ("rose() angular histogram plot with specified bins"); 167 168## Test input validation 169%!error rose () 170%!warning <bin sizes .= pi will not plot correctly> 171%! [th, r] = rose ([1 2 2 4 4 4], 2); 172%!warning <bin 1 and bin 3 are not centered> 173%! [th, r] = rose ([1 2 2 4 4 4], [1 2 3]); 174