* Bug 16445 fixed: colorbar() for Champ.colored='on'
[scilab.git] / scilab / modules / graphics / macros / colorbar.sci
1 // Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
2 // Copyright (C) Bruno Pincon
3 // Copyright (C) Serge Steer (adaptation to new graphic system)
4 // Copyright (C) 2012 - 2016 - Scilab Enterprises
5 // Copyright (C) 2017 - 2020 - 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 colorbar(umin, umax, colminmax, fmt)
15
16     //  PURPOSE
17     //     Draw a colorbar for a plot3d, fec, Sgrayplot, etc...
18     //
19     //  PARAMETERS
20     //     umin : data value corresponding to the colorbar lower bound
21     //     umax : data value corresponding to the colorbar upper bound
22     //     colminmax : a [cmin cmax] vector providing the colors corresponding
23     //                 to the [umin, umax] data bounds.
24     //                 Is a vector of 2 colors indices, where $ stands for the
25     //                 total number of colors in the current colormap.
26     //                 Examples: [1 $]   // the whole colormap
27     //                           [$/2 $] // The second half of the colormap
28     //                 May be useful to deal with a part of the colormap
29     //                 (for instance using fec or plot3d)
30     //     fmt : optional, a C format to display colorbar graduations
31     //
32     //  HISTORY
33     // 2017 : http://bugzilla.scilab.org/14711 : in uicontrol frame
34     // 2018 : http://bugzilla.scilab.org/15638 : unequal color spans
35     //        http://bugzilla.scilab.org/15805 : poor ticking
36     //        http://bugzilla.scilab.org/15806 : syntaxes with default umin, umax..
37     // 2019 : http://bugzilla.scilab.org/16232 : Support of $ in colminmax added
38     //        http://bugzilla.scilab.org/10553 : gce() is now the colorbar handle
39
40     // Check number of input argument
41     [lhs, rhs] = argn();
42     if rhs > 4 then
43         msg = gettext("%s: Wrong number of input arguments: %d to %d expected.\n")
44         error(msprintf(msg, "colorbar", 0, 4));
45     end
46
47     // TYPE OF THE ASSOCIATED PLOT
48     // ===========================
49     Type = []
50     f = gcf();
51     nColorsCM = size(f.color_map,1);
52     for h = gca().children'
53         if or(h.type==["Matplot" "Fec" "Fac3d" "Plot3d" "Grayplot" "Champ"])
54             Type = h.type
55             break
56         end
57         for g = h.children'
58             if or(g.type==["Matplot" "Fec" "Fac3d" "Plot3d" "Grayplot" "Champ"])
59                 Type = g.type
60                 h = g
61                 break
62             end
63         end
64         if Type~=[] then
65             break
66         end
67     end
68     if Type=="Matplot" & h.image_type~="index" then
69         Type = []
70     //elseif Type=="Fac3d" & h.cdata_mapping=="direct"
71     //    Type = "Matplot"      // done later
72     end
73
74     // PARSING INPUT ARGUMENTS
75     // =======================
76     // colminmax
77     if isdef("colminmax","l") & type(colminmax)==2
78         colminmax = horner(colminmax, nColorsCM)
79         colminmax(colminmax < 1) = 1
80         colminmax(colminmax > nColorsCM) = nColorsCM
81     end
82     if isdef("colminmax","l") & type(colminmax)~=0 & colminmax~=[] & colminmax(1)~=-1
83         msg = _("%s: Argument #%d: Decimal number(s) expected.\n")
84         if and(type(colminmax)~=[1 2])| ~isreal(colminmax)
85             error(msprintf(msg, "colorbar", 3))
86         end
87         if length(colminmax)~=2
88             msg = _("%s: Argument #%d: Vector with %d elements expected.\n")
89             error(msprintf(msg, "colorbar", 3, 2))
90         end
91         colminmax = gsort(colminmax,"g","i");
92         if and(colminmax>=0 & colminmax<=1) // fractions of the whole colormap range
93             colminmax = round(1 + colminmax*(nColorsCM-1))
94         end
95         colminmax = [max(colminmax(1),1) min(colminmax(2), nColorsCM)];
96     elseif ~isdef("colminmax","l") | type(colminmax)==0 | colminmax==[]
97         if ~isdef("umin","l") | type(umin)==0 | umin==[] then
98             colminmax = -1
99         else
100             colminmax = [1, nColorsCM]
101         end
102     else
103         colminmax = -1
104     end
105
106     // Default umin, umax, colminmax
107     if Type=="Fec"
108         u = h.data(:,3);
109
110     elseif Type=="Plot3d"
111         u = h.data.z
112
113     elseif Type=="Fac3d"
114         u = h.data.z;
115         colorsAreZ = %f;
116         if or(fieldnames(h.data)=="color")
117             c = h.data.color;
118             colorsAreZ = ~isvector(c)
119             if  or(h.color_flag==[2 3 4]) & h.cdata_mapping == "direct"
120                 u = h.data.color
121                 if colminmax == -1
122                     colminmax = [min(u) max(u)]
123                 end
124             end
125             //if colorsAreZ
126             //    // c = U*a+b
127             //    c2 = c-mean(c);
128             //    u2 = u-mean(u);
129             //    k = u~=0;
130             //    colorsAreZ = colorsAreZ & stdev(c(k)./u(k))==0 // Improvement to explore
131             //end
132         end
133         if colorsAreZ
134             select h.color_flag
135             case 0
136                 u = []
137             case 1
138                 u = mean(u,"r")
139             case 2
140                 u = mean(u,"r")
141             case 3  // keep u as is
142             case 4
143                 u = u(1,:)
144             end
145         else
146             u = []  // no Z-colors mapping possible
147         end
148
149     elseif Type=="Grayplot"
150         u = h.data.z
151         u = (u(1:$-1,1:$-1)+u(2:$,1:$-1)+u(2:$,2:$)+u(1:$-1,2:$))/4;
152         if h.data_mapping=="direct"
153             Type = "Matplot"
154         end
155
156     elseif Type=="Matplot"
157         u = h.data
158
159     elseif Type=="Champ"
160         u = sqrt(h.data.fx .^2 + h.data.fy .^2)
161     else
162         u = []
163     end
164     k = ~isinf(u) & ~isnan(u)
165     uminmax = [min(u(k)) max(u(k))]
166     clear k
167
168     // umin
169     if ~isdef("umin","l") | type(umin)==0 | umin==[] then
170         if u~=[]
171             if colminmax~=[] & (length(colminmax)>1 | colminmax~=-1)
172                 if Type=="Matplot" | Type=="Champ" | ..
173                    Type=="Fac3d" & or(h.color_flag==[2 3 4]) & h.cdata_mapping == "direct"
174                     umin = colminmax(1)
175                 else
176                     if argn(2)<2
177                         c = colminmax // raw bounds (not integers)
178                         nc = max(1,floor(colminmax(1)))
179                         // recomputing umin matching the rounded colminmax(1)
180                         umin = uminmax(1) + (uminmax(2)-uminmax(1)) * ..
181                                         (colminmax(1)-nc)/(c(2)-c(1))
182                     else
183                         umin = uminmax(1) + (uminmax(2)-uminmax(1)) * ..
184                                         (colminmax(1)-0)/nColorsCM
185                     end
186                 end
187             else
188                 umin = uminmax(1)
189             end
190         else
191             msg =_("%s: Argument #%d: Can''t retrieve a default value: Decimal number expected.\n")
192             error(msprintf(msg, "colorbar", 1))
193         end
194     else
195         msg = _("%s: Argument #%d: Decimal number(s) expected.\n")
196         if type(umin)~=1 | ~isreal(umin)
197             error(msprintf(msg, "colorbar", 1))
198         end
199         if length(umin)>1
200             msg = _("%s: Argument #%d: Scalar (1 element) expected.\n")
201             error(msprintf(msg, "colorbar", 1))
202         end
203         if umin==-%inf
204             umin = uminmax(1)  // umin=-%inf means umin=min(u)
205         end
206     end
207
208     // umax
209     if ~isdef("umax","l") | type(umax)==0 | umax==[] then
210         if u~=[]
211             if colminmax~=[] & colminmax~=-1
212                 if Type=="Matplot" | Type=="Champ" | ..
213                    Type=="Fac3d" & or(h.color_flag==[2 3 4]) & h.cdata_mapping == "direct"
214                     umax = colminmax(2)
215                 else
216                     if argn(2)<2
217                         c = colminmax // raw bounds (not integers)
218                         nc = min(nColorsCM,ceil(colminmax(2)))
219                         // recomputing umax matching the rounded colminmax(1)
220                         umax = uminmax(2) + (uminmax(2)-uminmax(1)) * ..
221                                         (nc-c(2))/(c(2)-c(1))
222                     else
223                         umax = uminmax(1) + (uminmax(2)-uminmax(1)) * ..
224                                             (colminmax(2)-0)/nColorsCM
225                     end
226                 end
227             else
228                 umax = uminmax(2)
229             end
230         else
231             msg =_("%s: Argument #%d: Can''t retrieve a default value: Decimal number expected.\n")
232             error(msprintf(msg, "colorbar", 1))
233         end
234     else
235         msg = _("%s: Argument #%d: Decimal number(s) expected.\n")
236         if type(umax)~=1 | ~isreal(umax)
237             error(msprintf(msg, "colorbar", 2))
238         end
239         if length(umax)>1
240             msg = _("%s: Argument #%d: Scalar (1 element) expected.\n")
241             error(msprintf(msg, "colorbar", 2))
242         end
243         if umax==%inf
244             umax = uminmax(2)  // umax=%inf means umax=max(u)
245         end
246     end
247
248     // colminmax
249     if colminmax(1)==-1  // => relative color range matches relative u range
250         if Type=="Matplot"
251             colminmax = [umin umax]
252         else
253             colminmax = 1 + (nColorsCM-1) * ..
254                        ([umin umax]-uminmax(1)) / (uminmax(2)-uminmax(1))
255         end
256     end
257     if Type~="Matplot"
258         colminmax = [max(1,round(colminmax(1))) min(nColorsCM,round(colminmax(2)))]
259     end
260
261     // fmt
262     if isdef("fmt","l") then
263         if type(fmt)<>10 | size(fmt,"*")<>1 then
264             msg = gettext("%s: Wrong type for input argument #%d: %s expected.\n")
265             error(msprintf(msg, "colorbar", argn(2), "string (containing a C format)"));
266         end
267     else
268         fmt = ""
269     end
270
271     // DRAWING
272     // =======
273     //defer the drawing to avoid binking
274     idMem = f.immediate_drawing;
275     f.immediate_drawing = "off";
276     // get current axes and properties
277     a = gca();
278     fg_color=a.foreground
279     wr=a.axes_bounds; //get the rectangle of the current axes
280
281     // modify the orginal axes to let space for the colorbar
282     a_pl=a;
283     a_pl.axes_bounds=[wr(1) , wr(2) , 0.85*wr(3) , wr(4)]
284
285
286     // create a new axes for the colorbar et set its properties
287     a_cb = newaxes(a.parent);
288     a_cb.axes_bounds=[wr(1)+0.83*wr(3) , wr(2)+wr(4)*0.2 , 0.2*wr(3) , wr(4)*0.6];
289     a_cb.foreground = a.foreground;
290     a_cb.background = f.background;
291     a_cb.axes_visible = "on";
292     a_cb.y_location   = "right";
293     a_cb.tight_limits = "on";
294
295     //It is not possible to set no ticks for x (should be fixed)
296     a_cb.x_ticks=tlist(["ticks","locations","labels"],-1,"");
297     a_cb.auto_ticks = ["off","on","off"];
298     a_cb.ticks_format(2) = fmt;
299     a_cb.box = "on";
300     a_cb.margins=[0 0.75 0 0];
301
302     //draw the colorbar
303     Matplot((colminmax(2):-1:colminmax(1))')
304     a_cb.y_location = "right";
305     a_cb.tight_limits = "on";
306
307     if Type~="Matplot" then
308         du = (umax-umin)
309         gce().rect = [0.5 umin 1.5 umax];
310         a_cb.data_bounds  = [0.5, 1.5, umin-du/500, umax+du/500];
311     else
312         s = ((umax-umin)==(colminmax(2)-colminmax(1)))*0.5
313         gce().rect = [0.5 umin-s 1.5 umax+s];
314         a_cb.data_bounds  = [0.5 1.5 umin-s umax+s];
315     end
316
317     //reset the initial values
318     sca(a_pl) //current axes
319
320     // Restoring input drawing mode
321     f.immediate_drawing = idMem;
322
323     // setting gce()
324     set("current_entity", a_cb)
325 endfunction