a932179066d7ee6a267a9d761b03f9bba7227e27
[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     elseif Type=="Plot3d"
113         u = h.data.z
114     elseif Type=="Fac3d"
115         u = h.data.z;
116         c = h.data.color;
117         colorsAreZ = ~isvector(c)
118         //if colorsAreZ
119         //    // c = U*a+b
120         //    c2 = c-mean(c);
121         //    u2 = u-mean(u);
122         //    k = u~=0;
123         //    colorsAreZ = colorsAreZ & stdev(c(k)./u(k))==0 // Improvement to explore
124         //end
125         if colorsAreZ
126             select h.color_flag
127             case 0
128                 u = []
129             case 1
130                 u = mean(u,"r")
131             case 2
132                 u = mean(u,"r")
133             case 3  // keep u as is
134             case 4
135                 u = u(1,:)
136             end
137         else
138             u = []  // no Z-colors mapping possible
139         end
140
141     elseif Type=="Grayplot"
142         u = h.data.z
143         u = (u(1:$-1,1:$-1)+u(2:$,1:$-1)+u(2:$,2:$)+u(1:$-1,2:$))/4;
144         if h.data_mapping=="direct"
145             Type = "Matplot"
146         end
147     elseif Type=="Matplot"
148         u = h.data
149     else
150         u = []
151     end
152     k = ~isinf(u) & ~isnan(u)
153     uminmax = [min(u(k)) max(u(k))]
154     clear k
155
156     // umin
157     if ~isdef("umin","l") | type(umin)==0 | umin==[] then
158         if u~=[]
159             if colminmax~=[] & (length(colminmax)>1 | colminmax~=-1)
160                 if Type=="Matplot"
161                     umin = colminmax(1)
162                 else
163                     if argn(2)<2
164                         c = colminmax // raw bounds (not integers)
165                         nc = max(1,floor(colminmax(1)))
166                         // recomputing umin matching the rounded colminmax(1)
167                         umin = uminmax(1) + (uminmax(2)-uminmax(1)) * ..
168                                         (colminmax(1)-nc)/(c(2)-c(1))
169                     else
170                         umin = uminmax(1) + (uminmax(2)-uminmax(1)) * ..
171                                         (colminmax(1)-0)/nColorsCM
172                     end
173                 end
174             else
175                 umin = uminmax(1)
176             end
177         else
178             msg =_("%s: Argument #%d: Can''t retrieve a default value: Decimal number expected.\n")
179             error(msprintf(msg, "colorbar", 1))
180         end
181     else
182         msg = _("%s: Argument #%d: Decimal number(s) expected.\n")
183         if type(umin)~=1 | ~isreal(umin)
184             error(msprintf(msg, "colorbar", 1))
185         end
186         if length(umin)>1
187             msg = _("%s: Argument #%d: Scalar (1 element) expected.\n")
188             error(msprintf(msg, "colorbar", 1))
189         end
190         if umin==-%inf
191             umin = uminmax(1)  // umin=-%inf means umin=min(u)
192         end
193     end
194
195     // umax
196     if ~isdef("umax","l") | type(umax)==0 | umax==[] then
197         if u~=[]
198             if colminmax~=[] & colminmax~=-1
199                 if Type=="Matplot"
200                     umax = colminmax(2)
201                 else
202                     if argn(2)<2
203                         c = colminmax // raw bounds (not integers)
204                         nc = min(nColorsCM,ceil(colminmax(2)))
205                         // recomputing umax matching the rounded colminmax(1)
206                         umax = uminmax(2) + (uminmax(2)-uminmax(1)) * ..
207                                         (nc-c(2))/(c(2)-c(1))
208                     else
209                         umax = uminmax(1) + (uminmax(2)-uminmax(1)) * ..
210                                             (colminmax(2)-0)/nColorsCM
211                     end
212                 end
213             else
214                 umax = uminmax(2)
215             end
216         else
217             msg =_("%s: Argument #%d: Can''t retrieve a default value: Decimal number expected.\n")
218             error(msprintf(msg, "colorbar", 1))
219         end
220     else
221         msg = _("%s: Argument #%d: Decimal number(s) expected.\n")
222         if type(umax)~=1 | ~isreal(umax)
223             error(msprintf(msg, "colorbar", 2))
224         end
225         if length(umax)>1
226             msg = _("%s: Argument #%d: Scalar (1 element) expected.\n")
227             error(msprintf(msg, "colorbar", 2))
228         end
229         if umax==%inf
230             umax = uminmax(2)  // umax=%inf means umax=max(u)
231         end
232     end
233
234     // colminmax
235     if colminmax(1)==-1  // => relative color range matches relative u range
236         if Type=="Matplot"
237             colminmax = [umin umax]
238         else
239             colminmax = 1 + (nColorsCM-1) * ..
240                        ([umin umax]-uminmax(1)) / (uminmax(2)-uminmax(1))
241         end
242     end
243     if Type~="Matplot"
244         colminmax = [max(1,round(colminmax(1))) min(nColorsCM,round(colminmax(2)))]
245     end
246
247     // fmt
248     if isdef("fmt","l") then
249         if type(fmt)<>10 | size(fmt,"*")<>1 then
250             msg = gettext("%s: Wrong type for input argument #%d: %s expected.\n")
251             error(msprintf(msg, "colorbar", argn(2), "string (containing a C format)"));
252         end
253     else
254         fmt = ""
255     end
256
257     // DRAWING
258     // =======
259     //defer the drawing to avoid binking
260     idMem = f.immediate_drawing;
261     f.immediate_drawing = "off";
262     // get current axes and properties
263     a = gca();
264     fg_color=a.foreground
265     wr=a.axes_bounds; //get the rectangle of the current axes
266
267     // modify the orginal axes to let space for the colorbar
268     a_pl=a;
269     a_pl.axes_bounds=[wr(1) , wr(2) , 0.85*wr(3) , wr(4)]
270
271
272     // create a new axes for the colorbar et set its properties
273     a_cb = newaxes(a.parent);
274     a_cb.axes_bounds=[wr(1)+0.83*wr(3) , wr(2)+wr(4)*0.2 , 0.2*wr(3) , wr(4)*0.6];
275     a_cb.foreground = a.foreground;
276     a_cb.background = f.background;
277     a_cb.axes_visible = "on";
278     a_cb.y_location   = "right";
279     a_cb.tight_limits = "on";
280
281     //It is not possible to set no ticks for x (should be fixed)
282     a_cb.x_ticks=tlist(["ticks","locations","labels"],-1,"");
283     a_cb.auto_ticks = ["off","on","off"];
284     a_cb.ticks_format(2) = fmt;
285     a_cb.box = "on";
286     a_cb.margins=[0 0.75 0 0];
287
288     //draw the colorbar
289     Matplot((colminmax(2):-1:colminmax(1))')
290     a_cb.y_location = "right";
291     a_cb.tight_limits = "on";
292     if Type~="Matplot" then
293         du = (umax-umin)
294         gce().rect = [0.5 umin 1.5 umax];
295         a_cb.data_bounds  = [0.5, 1.5, umin-du/500, umax+du/500];
296     else
297         s = ((umax-umin)==(colminmax(2)-colminmax(1)))*0.5
298         gce().rect = [0.5 umin-s 1.5 umax+s];
299         a_cb.data_bounds  = [0.5 1.5 umin-s umax+s];
300     end
301
302     //reset the initial values
303     sca(a_pl) //current axes
304
305     // Restoring input drawing mode
306     f.immediate_drawing = idMem;
307 endfunction