1 // Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
2 // Copyright (C) 2004-2006 - INRIA - Fabrice Leray
3 // Copyright (C) 2008 - INRIA - Jean-Baptiste Silvy
4 // This file must be used under the terms of the CeCILL.
5 // This source file is licensed as described in the file COPYING, which
6 // you should have received as part of this distribution. The terms
7 // are also available at
8 // http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
10 function plot(varargin)
11 // Try to build a new better parser that could manage things like:
12 // plot(x,y,'X',1:10); // where X stands for Xdata (Matlab recognizes
13 //it and treats it well...)
18 //LineSpec and PropertySpec examples:
24 plot(tt, sin(tt), "ro-.", tt, cos(tt), "cya+", tt, abs(sin(tt)), "--mo");
26 plot([t ;t],[sin(t); cos(t)],"xdat",[1:2]);
33 CurColor = 0; // current color used if no color specified via LineSpec
40 //detect and set the current axes now:
41 if type(ListArg(1)) == 9
43 if (hdle.type == "Axes")
45 ListArg(1) = null(); // remove this parameter from the list
47 warning("Handle should be an Axes handle")
63 argTypes(curArgIndex,1) = type(ListArg(curArgIndex))
70 acceptedTypes=find(Ttmp(i,1)==1 & or(Ttmp(i+1,1)==[1,13,130])) // to accept double, macro function or primitive as second argument
72 if (acceptedTypes<>[]) then
74 Ttmp(i,1) = 99; // Replace a known type by 99 (no meaning) to count it once only!
75 Ttmp(i+1,1)= 99; // to avoid having (x1,y1,x2,y2) ->couple=[1,2,3]
76 // With this trick, couple=[1,3];
82 if (couple==[]) // No data couple found
83 // Search for at least a single data , i.e.: plot(y)
85 if ((argTypes(1,1)==1 | argTypes(1,1)==8) & ListArg(1)<>[]) then // case plot(SINGLE y,...)
89 if (modulo(nv-couple,2)<>0) then
90 P1 = couple+2 // Position of the first PropertyName field
96 warning("Error inside input argument : no data");
102 // Some test to check wrong inputs
104 // 1. Test if 2 data couples (first : type==1, second : type=[1,13,130])
105 // are at least separated by 2 indices
106 if (couple(2:$)-couple(1:$-1)<2)
107 warning("Error inside input argument !");
111 // 2. Test if no string couples happen before P1 (see below for P1 definition)
112 for index=1:couple($)
114 acceptedTypes=find(Ttmp(index,1)==10 & Ttmp(index+1,1)==10)
116 if (acceptedTypes<>[]) then
117 warning("Error inside input argument : String argument is an unknown option.");
124 if (modulo(nv-(couple($)+1),2)<>0) then
125 P1 = couple($)+3 // Position of the first PropertyName field
132 numplot = size(couple,"*");
134 xyIndexLineSpec = zeros(numplot,3);
135 // xyIndexLineSpec is a matrix storing the index of x, y and linespec
136 // if one of these indices is 0 => it does not exist
137 // (which is possible for x and linepsec, not for y)
139 if (provided_data == 2) then
141 for curCouple=1:size(couple,"*")
142 xyIndexLineSpec(curCouple,1:2) = couple(curCouple) +[0,1] // x,y index storage
144 if (couple(curCouple)+2 < P1)
145 if (argTypes(couple(curCouple)+2,1)==10) then // LineSpec treatment
146 xyIndexLineSpec(curCouple,3) = couple(curCouple)+2;
151 // we are in the case where: plot(SINGLE y,... x not specified
152 // or plot(handle,SINGLE y,...
153 xyIndexLineSpec(1,1) = 0; // no x specified
154 xyIndexLineSpec(1,2) = couple;
159 if (argTypes(couple+1,1)==10) then // LineSpec treatment
160 xyIndexLineSpec(1,3) = couple+1;
167 // delay the drawing commands
169 current_figure=gcf();
170 cur_draw_mode = current_figure.immediate_drawing;
171 current_figure.immediate_drawing = "off";
173 // check wether this is the first plot for the axes in which we will draw
175 // save auto_clear state.
176 OldAutoClear = curAxes.auto_clear;
178 isFirstPlot = (curAxes.children == [])
180 //Now, we plot the decomposed plots one by one with their own linespec
181 // provided_data = 2 : x and y are provided
183 FinalAgreg=[]; // Final Compound containing all the new created plots.
187 // Set off auto_clear for allowing multiple graphics entity
188 // will be restored behond
190 curAxes.auto_clear="off";
201 if (provided_data == 2) then
203 if (type(ListArg(xyIndexLineSpec(i,2))) == 13 | type(ListArg(xyIndexLineSpec(i,2))) == 130)
204 // A function (macro or primitive) is given. We need to build the vector or matrix.
205 sizefirstarg = size(ListArg(xyIndexLineSpec(i,1)));
206 buildFunc = ListArg(xyIndexLineSpec(i,2));
207 firstarg = ListArg(xyIndexLineSpec(i,1));
210 for ii=1:sizefirstarg(1,2)
211 for jj=1:sizefirstarg(1,1)
213 // function evaluation may fail
214 // try/cacth is buggy for now
215 // so use execstr until the bug is fixed
216 err = execstr("tmp(jj,ii) = buildFunc(firstarg(jj,ii))","errcatch","n");
220 ResetFigureDDM(current_figure, cur_draw_mode);
223 [err_message, err_number, err_line, err_func] = lasterror(%t);
227 if (err_func <> "") then
229 error(msprintf(gettext("%s: Error : unable to evaluate input function ''%s''.") + ascii(10) + gettext("Error %d at line %d of the function: ''%s''"), "plot", err_func,err_number, err_line, err_message));
231 error(msprintf(gettext("%s: Error : unable to evaluate input function.") + ascii(10) + gettext("Error %d at line %d of the function: ''%s''"), "plot", err_number, err_line, err_message));
241 ListArg(xyIndexLineSpec(i,2)) = tmp;
242 // if there is an other iteration, we will have error message redefining function.
243 // we need to clear here and not before, because user must see the warning if needed.
246 [X,Y] = checkXYPair(typeOfPlot,ListArg(xyIndexLineSpec(i,1)),ListArg(xyIndexLineSpec(i,2)),current_figure,cur_draw_mode)
248 if or(size(ListArg(xyIndexLineSpec(1,2)))==1) // If this is a vector
249 X=(1:length(ListArg(xyIndexLineSpec(1,2))))'; // insert an abcsissa vector of same length,
250 else // if this is a matrix,
251 X=(1:size(ListArg(xyIndexLineSpec(1,2)),1))'; // insert an abcsissa vector with same size
253 // In both cases (matrix/vector), transpose it now so no warning is issued in checkXYPair().
254 [X,Y] = checkXYPair(typeOfPlot,X,ListArg(xyIndexLineSpec(1,2)),current_figure,cur_draw_mode)
257 // Case if 'Xdata', 'Ydata' or 'Zdata' have been set in (PropertyName,Propertyvalue) couples
258 // must be taken into account now
260 // P1 is the position of the first PropertyName field.
263 while (Property <= nv-1)
264 PropertyName = ListArg(Property);
265 PropertyValue = ListArg(Property+1);
267 // Xdata can ONLY be a vector (cf. Matlab help)
268 PName = getPlotPropertyName(PropertyName,current_figure,cur_draw_mode);
269 if (PName == "xdata")
271 if (type(PropertyValue)<>1 | and(size(PropertyValue)<>1))
272 warning("Xdata value must be a column or row vector.");
273 ResetFigureDDM(current_figure, cur_draw_mode);
276 PropertyValue = PropertyValue(:); // force
277 if or(size(X))==1 // If X is a vector (inevitably a column vector because checkXYPair always returns a column vector)
278 X = PropertyValue; // X is replaced by PropertyValue
279 [X,Y] = checkXYPair(typeOfPlot,X,Y,current_figure,cur_draw_mode)
280 else // X is a matrix
281 if size(PropertyValue,"*") == size(X,1)
282 for j=1:size(PropertyValue,"*")
283 X(j,:) = PropertyValue(j,1);
286 str="plot : incompatible dimensions in input arguments";
288 ResetFigureDDM(current_figure, cur_draw_mode);
293 // Ydata ONLY be a vector (contrary to what is said by the Matlab help)
294 elseif (PName == "ydata")
296 if (type(PropertyValue)<>1 | and(size(PropertyValue)<>1))
297 warning("Ydata value must be a column or row vector.");
298 ResetFigureDDM(current_figure, cur_draw_mode);
301 PropertyValue = PropertyValue(:); // force
302 if or(size(Y))==1 // If Y is a vector (inevitably a column vector because checkXYPair always returns a column vector)
303 Y = PropertyValue; // Y is replaced by PropertyValue
304 [X,Y] = checkXYPair(typeOfPlot,X,Y,current_figure,cur_draw_mode)
305 else // Y is a matrix
306 if size(PropertyValue,"*") == size(Y,1)
307 for j=1:size(PropertyValue,"*")
308 Y(j,:) = PropertyValue(j);
311 str="plot : incompatible dimensions in input arguments";
313 ResetFigureDDM(current_figure, cur_draw_mode);
319 // Zdata will be treated after plot building
322 Property = Property+2;
327 //Now we have an array xyIndexLineSpec [numplot x 3] containing indices pointing on T for :
328 // - x (<>0 if existing)
330 // - linespec (<>0 if existing)
331 // for each plot passed in argument
334 //plot1 0|i1 |0 <=> plot(y)
335 //plot2 i2|i3 |0 <=> plot(x,y)
336 //plot3 i4|i5 |i6 <=> plot(x,y,LINESPEC)
341 if (xyIndexLineSpec(i,3)<>0) then // if we have a line spec <=> index <> 0
342 [Color,Line,LineStyle,Marker,MarkerStyle,MarkerSize,fail] = getLineSpec(ListArg(xyIndexLineSpec(i,3)),current_figure,cur_draw_mode);
345 // The plot is made now :
346 err = execstr("plot2d(X,Y)","errcatch","m");
349 mprintf("Error %d : in plot2d called by plot",err);
350 ResetFigureDDM(current_figure, cur_draw_mode);
354 agreg=gce(); // when using plot2d, we always have an Compound as the current entity
356 FinalAgreg = [agreg FinalAgreg];
364 for ii=size(agreg.children,"*"):-1:1
365 curPolyline=agreg.children(ii); // we apply linespec to the lines
367 // Color treatment : if no color specified by LineSpec nor PropertyName
368 // Set the default color to the curve
369 if DefaultColor == %T
370 [Color,CurColor] = setDefaultColor(CurColor);
374 curPolyline.mark_style=MarkerStyle;
375 curPolyline.mark_mode ="on";
376 curPolyline.mark_foreground = Color;
377 curPolyline.mark_style=MarkerStyle;
378 curPolyline.mark_size=MarkerSize;
380 curPolyline.mark_mode ="off"
384 curPolyline.line_mode="on";
385 curPolyline.foreground = Color;
386 curPolyline.line_style = LineStyle;
388 curPolyline.line_mode="off"
391 if (Line == %F & Marker ==%F) // no linespec nor PropertyName set
392 curPolyline.line_mode="on";
393 curPolyline.foreground = Color;
394 curPolyline.line_style = LineStyle;
400 //Reset auto_clear Property
401 curAxes.auto_clear = OldAutoClear;
403 ///////////////////////////////////
404 //Global Property treatment //
405 //PropertyName and PropertyValue //
406 ///////////////////////////////////
410 // Those properties will be applied to Agreg children
411 Agreg = glue(FinalAgreg(1:$))
413 nbCompound = find(Agreg.children.type=="Compound")
415 while (nbCompound<>[])
416 nbCompound=nbCompound(1);
417 unglue(Agreg.children(nbCompound));
418 nbCompound=find(Agreg.children.type=="Compound")
423 // P1 is the position of the first PropertyName field.
426 Curves = Agreg.children
427 //Curves(:,1) = Curves(:,$:-1:1);
429 // set mark_size_unit to 'point' for all the curves
430 Curves.mark_size_unit="point";
432 while (Property <= nv-1)
433 setPlotProperty(ListArg(Property),ListArg(Property+1),Curves,current_figure,cur_draw_mode)
435 Property = Property+2;
438 // force drawing of box like in matlab
440 // unless we are using centered axes
441 // to keep compatibility with Scilab 4
442 if isFirstPlot & curAxes.x_location <> "origin" & curAxes.y_location <> "origin" then
448 //postponed drawings are done now !
450 ResetFigureDDM(current_figure, cur_draw_mode)