e022acb59ca5b674f71ec633fe950033b1491e95
[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 - 2019 - 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"])
54             Type = h.type
55             break
56         end
57         for g = h.children'
58             if or(g.type==["Matplot" "Fec" "Fac3d" "Plot3d" "Grayplot"])
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     elseif Type=="Matplot"
156         u = h.data
157     else
158         u = []
159     end
160     k = ~isinf(u) & ~isnan(u)
161     uminmax = [min(u(k)) max(u(k))]
162     clear k
163
164     // umin
165     if ~isdef("umin","l") | type(umin)==0 | umin==[] then
166         if u~=[]
167             if colminmax~=[] & (length(colminmax)>1 | colminmax~=-1)
168                 if Type=="Matplot" | ..
169                    Type=="Fac3d" & or(h.color_flag==[2 3 4]) & h.cdata_mapping == "direct"
170                     umin = colminmax(1)
171                 else
172                     if argn(2)<2
173                         c = colminmax // raw bounds (not integers)
174                         nc = max(1,floor(colminmax(1)))
175                         // recomputing umin matching the rounded colminmax(1)
176                         umin = uminmax(1) + (uminmax(2)-uminmax(1)) * ..
177                                         (colminmax(1)-nc)/(c(2)-c(1))
178                     else
179                         umin = uminmax(1) + (uminmax(2)-uminmax(1)) * ..
180                                         (colminmax(1)-0)/nColorsCM
181                     end
182                 end
183             else
184                 umin = uminmax(1)
185             end
186         else
187             msg =_("%s: Argument #%d: Can''t retrieve a default value: Decimal number expected.\n")
188             error(msprintf(msg, "colorbar", 1))
189         end
190     else
191         msg = _("%s: Argument #%d: Decimal number(s) expected.\n")
192         if type(umin)~=1 | ~isreal(umin)
193             error(msprintf(msg, "colorbar", 1))
194         end
195         if length(umin)>1
196             msg = _("%s: Argument #%d: Scalar (1 element) expected.\n")
197             error(msprintf(msg, "colorbar", 1))
198         end
199         if umin==-%inf
200             umin = uminmax(1)  // umin=-%inf means umin=min(u)
201         end
202     end
203
204     // umax
205     if ~isdef("umax","l") | type(umax)==0 | umax==[] then
206         if u~=[]
207             if colminmax~=[] & colminmax~=-1
208                 if Type=="Matplot" | ..
209                    Type=="Fac3d" & or(h.color_flag==[2 3 4]) & h.cdata_mapping == "direct"
210                     umax = colminmax(2)
211                 else
212                     if argn(2)<2
213                         c = colminmax // raw bounds (not integers)
214                         nc = min(nColorsCM,ceil(colminmax(2)))
215                         // recomputing umax matching the rounded colminmax(1)
216                         umax = uminmax(2) + (uminmax(2)-uminmax(1)) * ..
217                                         (nc-c(2))/(c(2)-c(1))
218                     else
219                         umax = uminmax(1) + (uminmax(2)-uminmax(1)) * ..
220                                             (colminmax(2)-0)/nColorsCM
221                     end
222                 end
223             else
224                 umax = uminmax(2)
225             end
226         else
227             msg =_("%s: Argument #%d: Can''t retrieve a default value: Decimal number expected.\n")
228             error(msprintf(msg, "colorbar", 1))
229         end
230     else
231         msg = _("%s: Argument #%d: Decimal number(s) expected.\n")
232         if type(umax)~=1 | ~isreal(umax)
233             error(msprintf(msg, "colorbar", 2))
234         end
235         if length(umax)>1
236             msg = _("%s: Argument #%d: Scalar (1 element) expected.\n")
237             error(msprintf(msg, "colorbar", 2))
238         end
239         if umax==%inf
240             umax = uminmax(2)  // umax=%inf means umax=max(u)
241         end
242     end
243
244     // colminmax
245     if colminmax(1)==-1  // => relative color range matches relative u range
246         if Type=="Matplot"
247             colminmax = [umin umax]
248         else
249             colminmax = 1 + (nColorsCM-1) * ..
250                        ([umin umax]-uminmax(1)) / (uminmax(2)-uminmax(1))
251         end
252     end
253     if Type~="Matplot"
254         colminmax = [max(1,round(colminmax(1))) min(nColorsCM,round(colminmax(2)))]
255     end
256
257     // fmt
258     if isdef("fmt","l") then
259         if type(fmt)<>10 | size(fmt,"*")<>1 then
260             msg = gettext("%s: Wrong type for input argument #%d: %s expected.\n")
261             error(msprintf(msg, "colorbar", argn(2), "string (containing a C format)"));
262         end
263     else
264         fmt = ""
265     end
266
267     // DRAWING
268     // =======
269     //defer the drawing to avoid binking
270     idMem = f.immediate_drawing;
271     f.immediate_drawing = "off";
272     // get current axes and properties
273     a = gca();
274     fg_color=a.foreground
275     wr=a.axes_bounds; //get the rectangle of the current axes
276
277     // modify the orginal axes to let space for the colorbar
278     a_pl=a;
279     a_pl.axes_bounds=[wr(1) , wr(2) , 0.85*wr(3) , wr(4)]
280
281
282     // create a new axes for the colorbar et set its properties
283     a_cb = newaxes(a.parent);
284     a_cb.axes_bounds=[wr(1)+0.83*wr(3) , wr(2)+wr(4)*0.2 , 0.2*wr(3) , wr(4)*0.6];
285     a_cb.foreground = a.foreground;
286     a_cb.background = f.background;
287     a_cb.axes_visible = "on";
288     a_cb.y_location   = "right";
289     a_cb.tight_limits = "on";
290
291     //It is not possible to set no ticks for x (should be fixed)
292     a_cb.x_ticks=tlist(["ticks","locations","labels"],-1,"");
293     a_cb.auto_ticks = ["off","on","off"];
294     a_cb.ticks_format(2) = fmt;
295     a_cb.box = "on";
296     a_cb.margins=[0 0.75 0 0];
297
298     //draw the colorbar
299     Matplot((colminmax(2):-1:colminmax(1))')
300     a_cb.y_location = "right";
301     a_cb.tight_limits = "on";
302     if Type~="Matplot" then
303         du = (umax-umin)
304         gce().rect = [0.5 umin 1.5 umax];
305         a_cb.data_bounds  = [0.5, 1.5, umin-du/500, umax+du/500];
306     else
307         s = ((umax-umin)==(colminmax(2)-colminmax(1)))*0.5
308         gce().rect = [0.5 umin-s 1.5 umax+s];
309         a_cb.data_bounds  = [0.5 1.5 umin-s umax+s];
310     end
311
312     //reset the initial values
313     sca(a_pl) //current axes
314
315     // Restoring input drawing mode
316     f.immediate_drawing = idMem;
317
318     // setting gce()
319     set("current_entity", a_cb)
320 endfunction