[graphics] fix barhomogenize.tst & bug_13180.tst (surf)
[scilab.git] / scilab / modules / graphics / macros / bar.sci
1 // Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
2 // Copyright (C) 2005 - INRIA - Farid Belahcene
3 // Copyright (C) 2012 - Michael Baudin
4 // Copyright (C) 2012 - 2016 - Scilab Enterprises
5 // Copyright (C) 2018 - Samuel GOUGEON
6 //
7 // This file is hereby licensed under the terms of the GNU GPL v2.0,
8 // pursuant to article 5.3.4 of the CeCILL v.2.1.
9 // This file was originally licensed under the terms of the CeCILL v2.1,
10 // and continues to be available under such terms.
11 // For more information, see the COPYING file which you should have received
12 // along with this program.
13
14 function  bar(varargin)
15     // bar(y)
16     // bar(x, y)
17     // bar(x, y, width, colors, style)
18     // bar(x, y [,width] [,colors] [,style])
19     // bar(h, ..)
20     //
21     // Input :
22     // x : a real scalar or a vector
23     // y : a real scalar, or a vector or a matrix.
24     //     If it's a matrix, size(y,"r")==length(x) and size(y,"c") is the 
25     //     number of categories that can either be grouped around each x(i),
26     //     or stacked at each x(i)
27     // width : a double, the bar width, it's the percentage (0<width<1) of the
28     //         width max of one bar which is wanted (default: width=0.8)
29     // colors: scalar or vector of colors identifiers. If it's a vector, it must
30     //         has as many components as there are categories.
31     // style : a string 'grouped' or 'stacked' (default: style='grouped')
32
33     fname = "bar"
34     ListArg = varargin;
35
36     if size(varargin)<1 | size(varargin)>6  then
37         msg = gettext("%s: Wrong number of input argument(s): %d to %d expected.\n")
38         error(msprintf(msg, fname, 1, 6));
39     end
40
41     // PARSING INPUT ARGUMENTS
42     // =======================
43     // Targeted axes
44     // -------------
45     shift = 0;  // shift for argins positions
46     if type(ListArg(1)) == 9
47         hdle = ListArg(1);
48         if (hdle.type == "Axes")
49             sca(ListArg(1));
50             ListArg(1) = null(); // remove this parameter from the list
51             shift = 1;
52         else
53             msg = gettext("%s: Argument #%d: Graphic handle of type ''%s'' expected.\n")
54             error(msprintf(msg, fname, 1, "Axes"));
55         end
56     end
57     // Style
58     // -----
59     STYLE = "grouped"
60     if length(ListArg)>0 & type(ListArg($))==10 then
61         tmp = stripblanks(convstr(ListArg($)))
62         if or(tmp=="stacked" | tmp=="grouped")
63             if size(tmp,"*")>1
64                 msg = gettext("%s: Argument #%d: Scalar (1 element) expected.\n")
65                 error(msprintf(msg, fname, shift+length(ListArg)));
66             end
67             STYLE = tmp
68             ListArg($) = null()
69         end
70     end
71     // bar([h,] y,..)
72     // --------------
73     msg = gettext("%s: Argument #%d: Decimal number(s) expected.\n")
74     if length(ListArg)>0 & (length(ListArg)==1 | and(type(ListArg(2))~=[1 8]) | ..
75         (length(ListArg(2))==1 & ListArg(2)>0 & ListArg(2)<=1))  // is width
76         Y = ListArg(1)
77         if isvector(Y)
78             Y = Y(:)
79         end
80         X = (1:size(Y,1))'
81         ListArg(1) = null()
82         ky = shift+1
83     else
84         // bar([h,] x, y,..)  expected
85         // X
86         if ListArg==list()
87             error(msprintf(msg, fname, shift+1));
88         end
89         X = ListArg(1)
90         ListArg(1) = null()
91         // Y
92         if ListArg==list()
93             error(msprintf(msg, fname, shift+2));
94         end
95         Y = ListArg(1)
96         ListArg(1) = null()
97         ky = shift+2
98         if X==[]
99             X = 1:size(Y,1)
100         end
101         X = X(:)
102         if isvector(X) & isvector(Y)
103             Y = Y(:)
104         end
105     end
106     if Y==[] then
107         msg = gettext("%s: Argument #%d: Non-empty matrix expected.\n")
108         error(msprintf(msg, fname, ky))
109     end
110     if and(type(X)~=[1 8]) | (type(X)==1 & ~isreal(X)) then
111         error(msprintf(msg, fname, shift+1))
112     else
113         X = double(X)
114     end
115     if and(type(Y)~=[1 8]) | (type(Y)==1 & ~isreal(Y)) then
116         error(msprintf(msg, fname, ky))
117     else
118         Y = double(Y)
119     end
120     if size(Y,1)~=length(X) then
121         msg = gettext("%s: Arguments #%d and #%d: Incompatible sizes.\n")
122         error(msprintf(msg, fname, shift+1, shift+2))
123     end
124     if (isnan(X) | isinf(X))
125         msg = gettext("%s: Argument #%d: Inf and Nan values forbidden.\n")
126         error(msprintf(msg, fname, shift+1))
127     end
128     if STYLE=="stacked"
129         if (isnan(Y) | isinf(Y))
130             msg = gettext("%s: Argument #%d: Inf and Nan values forbidden.\n")
131             error(msprintf(msg, fname, ky))
132         end
133         if or(Y<0)
134             msg = gettext("%s: Argument #%d: Non-negative values expected.\n")
135             warning(msprintf(msg, fname, ky))
136         end
137     end
138
139     // Width
140     // -----
141     kw = ky
142     WIDTH = 0.8
143     if length(ListArg)>0 & or(type(ListArg(1))==[1 8]) then
144         kw = ky+1   // position of the width arg
145         WIDTH = ListArg(1)
146         if length(WIDTH)>1
147             msg = gettext("%s: Argument #%d: Scalar (1 element) expected.\n")
148             error(msprintf(msg, fname, kw))
149         end
150         if WIDTH==[]
151             WIDTH = 0.80
152         end
153         if ~isreal(WIDTH) | WIDTH<0 | WIDTH>1
154             msg = gettext("%s: Argument #%d: Must be in the interval %s.\n")
155             error(msprintf(msg, fname, kw, "[0, 1]"))
156         end
157         ListArg(1) = null();
158     end
159
160     // Colors
161     // ------
162     COLOR = []
163     if length(ListArg)>0
164         COLOR = ListArg(1)
165         if COLOR~=[]
166             nColors = size(COLOR,"*")
167             msg = gettext("%s: Argument #%d: Wrong color specification.\n")
168             if type(COLOR)~=10
169                 error(msprintf(msg, fname, kw+1));
170             end
171             c = iscolor(COLOR, "a#")
172             if or(c(:,1)==-1)
173                 error(msprintf(msg, fname, kw+1));
174             end
175             if nColors~=1 & nColors<size(Y,2) then
176                 msg = _("%s: Arguments #%d and #%d: Incompatible sizes.\n")
177                 error(msprintf(msg, fname, ky, kw+1));
178             end
179             if nColors>1 then
180                 COLOR = COLOR(1:size(Y,2)) // extra components ignored
181             else
182                 COLOR = emptystr(1,size(Y,2)) + COLOR;  // name or "#RRGGBB"
183             end
184         end
185     end
186
187     // PLOTTING
188     // ========
189     curFig = gcf()
190     immediate_drawing = curFig.immediate_drawing
191     wmode = warning("query")
192     warning("off")
193     if COLOR~=[]
194         plot(X,Y, "color",COLOR)
195     else
196         plot(X,Y)
197     end
198     warning(wmode)
199     curFig.immediate_drawing = "off"
200
201     bar_number=size(Y,2)
202     if size(X,"*")>1 then
203         Xtemp=gsort(X,"r","i")
204         inter=Xtemp(2)-Xtemp(1)
205         for i=2:size(Xtemp,"*")-1
206             inter=min(Xtemp(i+1)-Xtemp(i),inter)
207         end
208         if bar_number>1
209             if STYLE == "stacked"
210                 inter = inter * 0.9
211             else
212                 inter = inter * 0.7
213             end
214         end
215     else
216         Xtemp=X
217         inter=1
218     end
219
220     wmax=inter/bar_number
221     y_shift=zeros(size(X,"*"),1)
222     bar_number= bar_number
223
224     e = gce()
225     a = gca()
226
227     a.sub_ticks(1) = 0; // bar (barh => a.sub_ticks(2) = 0;)
228
229     for i=bar_number:-1:1
230
231         ei = e.children(i);
232
233         // Perform x_shift
234         if modulo(bar_number,2)==0 then
235             x_shift=(-i+bar_number/2)*wmax+wmax/2
236         elseif modulo(bar_number,2)==1 then
237             x_shift=(-i+1+floor(bar_number/2))*wmax
238         end
239
240         // Perform y_shift
241         if i==bar_number then
242             y_shift=zeros(size(X,"*"),1)
243         else
244             y_shift=Y(:,bar_number-i)+y_shift
245         end
246
247         // Udate the axes data bounds
248         if STYLE=="grouped"
249             xmin = min(a.data_bounds(1,1),min(X)+x_shift-0.45*wmax)
250             ymin = min(a.data_bounds(1,2),0,min(y_shift+Y(:,bar_number-i+1)))
251             xmax = max(a.data_bounds(2,1),max(X)+x_shift+0.45*wmax)
252             ymax = max(a.data_bounds(2,2),0)
253             ei.x_shift = x_shift*ones(size(X,"*"),1)
254         else
255             wmax = inter
256             xmin = min(a.data_bounds(1,1),min(X)-0.45*wmax)
257             ymin = min(a.data_bounds(1,2), 0, min(y_shift+Y(:,bar_number-i+1)))
258             xmax = max(a.data_bounds(2,1),max(X)+0.45*wmax)
259             ymax = max(a.data_bounds(2,2), 0, max(y_shift+Y(:,bar_number-i+1)))
260             ei.y_shift = y_shift
261         end
262         a.data_bounds=[xmin ymin; xmax ymax]
263
264         a.x_ticks=tlist("ticks",Xtemp,string(Xtemp))
265
266         w=WIDTH*wmax
267
268         ei.bar_width=w
269         ei.background=ei.foreground
270         ei.polyline_style=6; // bar type
271         ei.background=ei.foreground
272         ei.foreground = -1; // black by default
273         ei.line_mode="off";
274         ei.mark_foreground = -1; // black by default
275     end
276
277     // drawnow
278     curFig.immediate_drawing = immediate_drawing;
279
280 endfunction