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