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//
6// This file is hereby licensed under the terms of the GNU GPL v2.0,
7// pursuant to article 5.3.4 of the CeCILL v.2.1.
8// This file was originally licensed under the terms of the CeCILL v2.1,
9// and continues to be available under such terms.
10// For more information, see the COPYING file which you should have received
11// along with this program.
12
13
14function  barh(varargin)
15
16    // barh(x,y,width,style,color)
17    // Input :
18    // x : a scalar or a vector of reals
19    // y : a scalar, a vector or a matrix of reals
20    // width : a double, the bar width, it's the percentage (0<width<1) of the max width of one bar which is wanted (default: width=0.8)
21    // style : a string, 'grouped' or 'stacked' (default: style='grouped')
22
23    if and(size(varargin)<>[1:5]) then
24        error(msprintf(gettext("%s: Wrong number of input argument(s): %d to %d expected.\n"), "barh", 1, 5));
25    end
26
27    styletab=["grouped","stacked"]
28    COLORBOOL=%f
29
30    // Default values
31    STYLE="grouped"
32    WIDTH=0.8
33    COLORBOOL=%f
34
35    // Check RHS arguments
36    ListArg = varargin;
37
38    // Detect and set the current axes now:
39    if type(ListArg(1)) == 9
40        hdle = ListArg(1);
41        if (hdle.type == "Axes")
42            sca(ListArg(1));
43            ListArg(1) = null(); // remove this parameter from the list
44        else
45            warning(msprintf(gettext("%s: Wrong type for input argument #%d: Axes handle expected.\n"),"barh",1));
46            return;
47        end
48    end
49    if size(ListArg) == 4 then
50        COLOR=ListArg(4);
51        if type(COLOR) <> 10 then
52            error(msprintf(gettext("%s: Wrong type for input argument #%d: string expected.\n"),"barh",4));
53        end
54    end
55    if size(ListArg) == 5 then
56        STYLE=ListArg(5);
57        if type(STYLE) <> 10 then
58            error(msprintf(gettext("%s: Wrong type for input argument #%d: string expected.\n"),"barh",5));
59        end
60    end
61
62    nv = size(ListArg)
63
64    T=[];
65
66    for k=1:nv
67        T(k) = type(ListArg(k))
68    end
69
70    argdb=find(T==1)
71    argstr=find(T==10)
72
73    if size(argdb,"*")<> argdb($) then
74        error(msprintf(gettext("%s: Wrong type for input arguments: Matrix expected for %s, %s and %s.\n"),"barh", "x", "y", "width"));
75    end
76
77    if size(argstr,"*") <> nv-argdb($) then
78        error(msprintf(gettext("%s: Wrong type for input arguments: String expected for %s and %s.\n"),"barh", "color", "style"));
79    end
80
81    // Set the double argument : x,y,width
82    // barh(y,...)
83    if size(argdb,"*")==1
84        Y=ListArg(1)
85        if or(size(Y)==1) then
86            Y=Y(:)
87        end
88        X=1:size(Y,1)
89    end
90
91    if size(argdb,"*")==2
92        if size(ListArg(2),"*")==1 then
93            // barh(x,y,...)
94            if size(ListArg(1),"*")==1 then
95                X=ListArg(1)
96                Y=ListArg(2)
97            else
98                //barh(y,width,...)
99                WIDTH=ListArg(2)
100                Y=ListArg(1)
101                if or(size(Y)==1) then
102                    Y=Y(:)
103                end
104                X=1:size(Y,1)
105            end
106        else
107            // barh(x,y,...)
108            X=ListArg(1)
109            Y=ListArg(2)
110            if or(size(X)==1) then
111                if size(X,"*")<>1 then // X is a vector
112                    if or(size(Y)==1) then // Y is a vector
113                        Y=Y(:)
114                    end
115                    if size(X,"*")<>size(Y,1)
116                        error(msprintf(gettext("%s: Wrong size for input arguments #%d and #%d: The number of rows of argument #%d must be equal to the size of argument #%d.\n"),"bar",1, 2, 2, 1));
117                    end
118                elseif size(Y,1)>1 then
119                    error(msprintf(gettext("%s: Wrong size for input arguments #%d: A scalar or a column vector expected.\n"),"bar",2));
120                end
121            else
122                error(msprintf(gettext("%s: Wrong type for input argument #%d: A scalar or a vector expected.\n"),"barh",1));
123            end
124        end
125    end
126
127    // barh(x,y,width,...)
128    if size(argdb,"*")==3
129        X=ListArg(1)
130        Y=ListArg(2)
131        WIDTH=ListArg(3)
132        if size(WIDTH,"*")<>1 then
133            error(msprintf(gettext("%s: Wrong type for input argument #%d: A scalar expected.\n"),"barh",3));
134        elseif or(size(X)==1) then
135            if size(X,"*")<>1 then // X is a vector
136                if or(size(Y)==1) then // Y is a vector
137                    Y=Y(:)
138                end
139                if size(X,"*")<>size(Y,1)
140                    error(msprintf(gettext("%s: Wrong size for input arguments #%d and #%d: The number of rows of argument #%d must be equal to the size of argument #%d.\n"),"bar",1, 2, 2, 1));
141                end
142            elseif size(Y,1)>1 then
143                error(msprintf(gettext("%s: Wrong size for input arguments #%d: A scalar or a column vector expected.\n"),"bar",2));
144            end
145        else
146            error(msprintf(gettext("%s: Wrong type for input argument #%d: A scalar or a vector expected.\n"),"barh",1));
147        end
148    end
149
150    X=X(:)
151
152    // Set the string argument
153    for i=1:size(argstr,"*")
154        // barh(...,style)
155        if or(ListArg(argstr(i))==styletab) then
156            STYLE=ListArg(argstr(i))
157        else
158            COLOR=ListArg(argstr(i))
159            COLORBOOL=%t
160        end
161    end
162
163    // Verify if there are data bounds which are defined before creation the horizontal bars creation, in order to merge the data bounds
164    a=gca()
165    if size(a.children)<>0 then
166        gca_children_empty=%t
167        a_data_bounds=a.data_bounds
168    else
169        gca_children_empty=%f
170    end
171
172    //drawlater
173    curFig = gcf();
174    immediate_drawing = curFig.immediate_drawing;
175
176    if COLORBOOL
177        plot(X,Y,COLOR); // plot manages immediate_drawing property itself to avoid flickering
178    else
179        plot(X,Y); // plot manages immediate_drawing property itself to avoid flickering
180    end
181
182    curFig.immediate_drawing = "off";
183
184    barh_number=size(Y,2)
185
186    if size(X,"*")>1 then
187        Xtemp=gsort(X,"r","i")
188        inter=Xtemp(2)-Xtemp(1)
189        for i=2:size(Xtemp,"*")-1
190            inter=min(Xtemp(i+1)-Xtemp(i),inter)
191        end
192        if barh_number>1
193            inter=inter*0.9
194        end
195    else
196        Xtemp=X
197        inter=1
198    end
199
200    wmax=inter/barh_number
201    y_shift=zeros(size(X,"*"),1)
202    bar_number= size(Y,2)
203    e=gce()
204    a=gca()
205    a.sub_ticks(2) = 0
206
207    for i=bar_number:-1:1
208
209        ei = e.children(i)
210
211        // Perform x_shift
212        if modulo(bar_number,2)==0 then
213            x_shift=(-i+bar_number/2)*wmax+0.4*wmax
214        elseif modulo(bar_number,2)==1 then
215            x_shift=(-i+1+floor(bar_number/2))*wmax
216        end
217
218        // Perform y_shift
219        if i==bar_number then
220            y_shift=zeros(size(X,"*"),1)
221        else
222            y_shift=Y(:,bar_number-i)+y_shift
223        end
224
225        // Update axes data bounds
226        // case 'grouped'
227        if STYLE=="grouped"
228            if i <> bar_number then
229                ymin=min(a.data_bounds(1,1),min(Y(:,bar_number-i+1)),0)
230                xmin=min(a.data_bounds(1,2),min(X)+x_shift-0.4*wmax)
231                ymax=max(a.data_bounds(2,1),max(Y(:,bar_number-i+1)),0)
232                xmax=max(a.data_bounds(2,2),max(X)+x_shift+0.4*wmax)
233            else
234                if ~gca_children_empty
235                    ymin=min(min(Y(:,bar_number-i+1)),0)
236                    xmin=min(X)+x_shift-0.4*wmax
237                    ymax=max(max(Y(:,bar_number-i+1)),0)
238                    xmax=max(X)+x_shift+0.4*wmax
239                else
240                    ymin=min(a_data_bounds(1,1),min(Y(:,bar_number-i+1)),0)
241                    xmin=min(a_data_bounds(1,2),min(X)+x_shift-0.4*wmax)
242                    ymax=max(a_data_bounds(2,1),max(Y(:,bar_number-i+1)),0)
243                    xmax=max(a_data_bounds(2,2),max(X)+x_shift+0.4*wmax)
244                end
245            end
246            a.data_bounds=[ymin xmin;ymax xmax]
247            ei.x_shift=x_shift*ones(size(X,"*"),1)
248        else  // case 'stacked'
249            wmax=inter
250            if i <> bar_number then
251                ymin=min(a.data_bounds(1,1),min(Y(:,bar_number-i+1)+y_shift))
252                xmin=min(a.data_bounds(1,2),0,min(X-0.4*wmax))
253                ymax=max(a.data_bounds(2,1),max(Y(:,bar_number-i+1)+y_shift))
254                xmax=max(a.data_bounds(2,2),0,max(X+0.4*wmax))
255            else
256                if ~gca_children_empty
257                    ymin=min(Y(:,bar_number-i+1)+y_shift)
258                    xmin=min(0,min(X-0.4*wmax))
259                    ymax=max(Y(:,bar_number-i+1)+y_shift)
260                    xmax=max(0,max(X+0.4*wmax))
261                else
262                    ymin=min(a_data_bounds(1,1),min(Y(:,bar_number-i+1)+y_shift))
263                    xmin=min(a_data_bounds(1,2),0,min(X-0.4*wmax))
264                    ymax=max(a_data_bounds(2,1),max(Y(:,bar_number-i+1)+y_shift))
265                    xmax=max(a_data_bounds(2,2),0,max(X+0.4*wmax))
266                end
267            end
268            a.data_bounds=[ymin xmin; ymax xmax]
269            ei.y_shift=y_shift
270        end
271
272        a.y_ticks=tlist("ticks",Xtemp,string(Xtemp))
273        w=WIDTH*wmax
274        ei.bar_width=w
275        ei.background=ei.foreground
276        ei.polyline_style=7; // bar type
277        ei.background=ei.foreground
278        ei.foreground = -1; // black by default
279        ei.line_mode="off";
280    end
281
282    //drawnow
283    curFig.immediate_drawing = immediate_drawing;
284
285endfunction
286