1### Copyright (c) 2007, Tyzx Corporation. All rights reserved.
2function g = g_ez (varargin)
3### g = g_ez (command, args,...) - Single-command plotting function
4###
5### This function allows to do basic plots with a single function call, i.e.
6### like octave's plot() commant.
7###
8### If no output argument is required, the plot is shown and all data created
9### for this plot is deleted. Otherwise use, g_plot(g) to plot g.
10###
11### Commands:
12### ---------
13### "plot", <PLOT_DATA>, where the plotted data can be 2D points or images
14###        2D data can be specified by a two-column matrix of 2D points,
15###        optionnally followed by a cell array of label strings
16###
17### "plot", x, y, fmt,... : Reads arguments like in octave's plot (x,y,fmt,...)
18###            fmt can be an octave-like formatting, e.g. "-;My Key;", see
19###            _g_parse_oct_fmt().
20###            or "img", which may be followed by "range", "xrange", "yrange",
21###            "colormap" options. See _g_image_cmd().
22### "geometry",[w,h]      : Set gnuplot window geometry
23### "FILE.(eps|fig)"      : Plot to FILE.eps or FILE.fig file.
24### "xrange", [min,max]   : Set horizontal range
25### "yrange", [min,max]   : Set vertical range
26### "xlabel", str         : Set x label
27### "ylabel", str         : Set y label
28### "title",  str         : Set title
29### "cmd",    str         : Insert command str.
30### "grid",               : Same as "cmd","set grid"
31### "xgrid",
32### "ygrid"               : Same as "cmd","set grid x"
33### "xtics", arg          : If arg is a non-empty string, then this adds the
34###                         command ["set xtics " arg]. If arg is empty, same as
35###                         "unset xtics".
36### "ytics", arg          : Same as "cmd","set ytics " arg
37### "color",   yesno
38### "display", yesno
39###
40### TODO: "hist", "mesh" etc ...
41
42  ## args = struct();
43  args.cmds = {};
44  filename = "";
45
46				# Read arguments and put them in args.
47
48  cnt = 1;			# Arg counter
49  nplots = 0;			# Plot counter
50  plotcmds = "";		# arguments to plot
51  step = zeros(1,0);		# Number of points per "plot" curve
52  stop = {};
53  N = length (varargin);
54  plots =       {};		# Plotted data
55  names =       {};		# Names of data files
56  labels =      {};		# Labels of each dataset
57  dataLabels =  {};		# Labels attached to individual data points
58  do_color =    1;
59  do_wait =     1;
60  do_display =  1;
61  labpos =      zeros(0,2);
62  img_indices = zeros(1,0);
63
64  args.xmap = args.ymap = args.map = [];
65
66  while cnt < N
67    cmd = varargin{cnt};
68    if !ischar (cmd)
69      error ("Expecting string, got a '%s' as %ith argument",\
70	     typeinfo(cmd),cnt);
71    end
72
73				# It's a filename
74    if length (cmd) > 3 \
75      && (strcmp (cmd(end-3:end), ".eps") \
76	  || strcmp (cmd(end-3:end), ".fig")\
77	  || strcmp (cmd(end-3:end), ".png"))
78#	  || strcmp (cmd(end-3:end), ".ppm")\
79#	  || strcmp (cmd(end-3:end), ".pgm")\
80#	  || strcmp (cmd(end-3:end), ".jpg"))
81      filename = cmd;
82      cnt++;
83      continue
84    endif
85
86    switch cmd
87
88      case {"title", "xlabel", "ylabel", "x2label", "y2label"},
89	str = varargin{++cnt};
90	if !ischar (str),
91	  error ("Option '%s' requires a char argument; got a %s",\
92		 cmd, typeinfo (str));
93	endif
94	#str = strrep (str,"%","\\%")
95	args.(cmd) = str;
96
97      case "color"
98	do_color = varargin{++cnt};
99
100      case {"display", "-display"}
101	do_display = varargin{++cnt};
102
103      case "label"
104
105	str = varargin{++cnt};
106	if !ischar (str),
107	  error ("Option '%s' requires a char argument; got a %s",\
108		 cmd, typeinfo (str));
109	endif
110	pos = varargin{++cnt};
111	if !isnumeric (pos),
112	  error ("Option '%s' requires a 1 x 2 matrix argument; got a %s",\
113		 cmd, typeinfo (pos));
114	endif
115	if length (pos) != 2
116	  error ("Option '%s' requires a 1 x 2 matrix argument; got %s",\
117		 cmd, sprintf("%i x",size (pos))(1:end-2));
118	endif
119	labels = {labels{:},str};
120	labpos = [labpos;pos];
121	#str = strrep (str,"%","\\%")
122      case {"geometry", "xrange", "yrange", "x2range", "y2range"},
123	args.(cmd) = varargin{++cnt};
124
125      case {"range"},
126	args.xrange = args.yrange = varargin{++cnt};
127
128      case "grid"
129	args.grid = "";
130      case "xgrid"
131	args.grid = "x";
132      case "ygrid"
133	args.grid = "y";
134
135      case "xmap"
136	args.xmap = varargin{++cnt};
137      case "ymap"
138	args.ymap = varargin{++cnt};
139
140      case "plot"
141	do			# Add following datasets
142	  nplots++;
143
144	  foundLabels = {};	# Labels for datapoints
145
146    	  data = varargin{++cnt};
147	  if !isnumeric (data)
148	    error ("Argument after 'plot' should be numeric. Got '%s'.",\
149		   typeinfo(data));
150	  endif
151	  orig_data_size = size (data);
152	  if rows (data) == 1, data = data'; endif
153	  ##nplots
154	  ##step
155	  ##rows(data)
156	  ##keyboard
157	  step(1,nplots) = rows (data);
158
159	  if cnt < length (varargin)
160  	    if isnumeric (varargin{cnt+1}) # x and y are separate args
161	      tmp = varargin{++cnt};
162	      if prod (size (tmp))    != prod (size (data))
163		if rows (data) != rows (tmp)
164		  if rows (data) == columns (tmp)
165		    tmp = tmp';
166		  end
167		end
168		if rows (data) == rows (tmp) \
169		      && columns (data) == 1
170		  data = data*ones(1,columns(tmp)); # Replicate abscissa data
171		else
172		  error ("First 'plot' arg is %i x %i, while 2nd is %i x %i\n",\
173			 orig_data_size, size (tmp));
174		endif
175	      endif
176	      if !xor (isuint(data), isuint(tmp)) # Octave's stupid bug
177		data = [data(:), tmp(:)];
178	      else
179		data = [double(data(:)),double(tmp(:))];
180	      end
181	    else
182	      if columns(data) == 1
183		data = [(1:rows(data))', data];
184	      end
185	    endif		# EOF x and y are separate args
186	  else
187	    if columns(data) == 1
188	      data = [(1:rows(data))', data];
189	    end
190	  end
191				# Transpose data, if needed.
192	  if rows(data)==2 && columns(data)>2, data = data'; endif
193
194	  names{nplots} = sprintf ("data%i",nplots);
195				# Determine how to plot it
196	  try_arg = [];
197	  if cnt < N
198	    try_arg = varargin{cnt+1};
199	  endif
200				# Labels passed as a vector: turn into a cell
201	  if isnumeric (try_arg) && ! isempty (try_arg)
202	    if numel (try_arg) > rows (data)
203	      error (["Don't know what to do with third numeric argument of size",\
204		      sprintf(" %i",size(try_arg)),". Plot has has %i points"],\
205		     rows(data));
206	    end
207	    try_arg = num2cell (try_arg);
208	  end
209	  ##foundLabels
210	  if iscell (try_arg)	# user-specified labels
211	    foundLabels = try_arg;
212	    cnt++;
213	    try_arg = 0;
214	    if cnt < N
215	      try_arg = varargin{cnt+1};
216	    endif
217	  end
218	  if ischar (try_arg) && strcmp (try_arg, "img")
219
220	    zrange = [min(data(:)), max(data(:))];
221	    ##data =   floor (255.999*(data - zrange(1))/diff(zrange));
222
223	    [imFmt, extra, nImArgs,zrange] = _g_image_cmd (size (data), zrange, args, {varargin{cnt+2:end}});
224
225	    cnt += nImArgs + 1;
226
227	    data =   floor (255.999*(data - zrange(1))/diff(zrange));
228	    data(data < 0) =   0;
229	    data(data > 255) = 255;
230	    data(isnan (data)) = 0;
231
232	    if length (size (data)) == 3 && size(data)(3) == 3
233	      data = [data(:,:,1)'(:),data(:,:,2)'(:),data(:,:,3)'(:)]';
234	    else
235	      data = data';
236	    end
237	    plotcmds =    [plotcmds,"'", names{nplots},"' ",imFmt,", "];
238	    img_indices = [img_indices,  nplots];
239	    args.cmds =   {args.cmds{:}, extra{:}};
240
241	    			# EOF "img"
242	  elseif ischar (try_arg) && strcmp (try_arg, "box") # Unused for now
243
244	    interlaced = prod (orig_data_size) == rows (data)
245	    if !interlaced
246	      nbox = prod (orig_data_size);
247	      datlen = rows (data)/nbox;
248	      data1 =  data(1:datlen,1);
249	      data2 =  reshape (data(:,2), nbox, datlen)';
250	    else
251	      datindices = data(:,1);
252	      #data1 = create_set (data(:,1));
253	      data1 = unique (data(:,1));
254	      nbox = length (data1);
255	      data2 = data(:,2);
256	    end
257	    data =   zeros(0,2);
258	    stops =  zeros(1,0);
259
260	    for i = 1:nbox
261	      if !interlaced, the_data = data2(:,i);
262	      else            the_data = data2(data1(i) == datindices);
263	      end
264	      boxData = boxplot_data (the_data);
265	      boxWid = 0.1;
266	      data = [data;\
267		      [  data1(i)+boxWid*[1 -1 -1 1 1 -1 -1]/2;\
268		       boxData.quantiles([3  3  2 2 4  4  3])']';\
269		      [         data1(i)*[1 1 1 1];\
270		       boxData.quantiles([1 2 4 5])']';];
271	      stops = [stops, [7 9 11]+11*(i-1)];
272	    end
273
274	    cnt += 1;
275	    plotcmds = [plotcmds, "'", names{nplots},"' ","w l title '' , "];
276	    stop{nplots} = stops;
277
278				# EOF "box"
279	  else			# Plain N x 2 data
280
281	    [isFmt, fmtContents, wantLabel] = _g_parse_oct_fmt (try_arg, nplots,foundLabels);
282
283	    cnt += isFmt;
284	    if wantLabel
285	      dataLabels{nplots} = 1;
286	    else
287	      dataLabels{nplots} = 0;
288	    end
289	    if !isempty (foundLabels)
290	      dataLabels{nplots} = foundLabels;
291	    end
292	    plotcmds = [plotcmds,"'",names{nplots},"' ",fmtContents,", "];
293	    if wantLabel
294	      plotcmds = [plotcmds,"'",names{nplots},"' ",wantLabel,", "];
295	    end
296	  end
297	  plots{nplots} = data;
298				# Determine how to plot it
299
300				# EOF read datasets
301        until (cnt >= N) || !isnumeric (varargin{cnt+1});
302
303				# EOF case plot
304      case "cmd"
305	args.cmds = {args.cmds{:}, varargin{++cnt}};
306
307      case "wait"
308	do_wait = varargin{++cnt};
309
310      case {"xtics","ytics", "x2tics", "y2tics", "tics"},
311	t = varargin{++cnt};
312	args.(cmd) =  t;
313
314      otherwise
315	error ("Unknown command '%s'", cmd);
316    endswitch
317    cnt++;
318  endwhile			# EOF Read arguments and put in struct
319
320				# Transform args in a gnuplot_object
321
322  if struct_contains (args, "geometry"), g = g_new ("geometry", args.geometry);
323  else                                   g = g_new ();
324  endif
325
326				# Special case: quote title
327  #if struct_contains (args, "title"), args.title = ["'",args.title,"'"]; endif
328
329  if length (args.cmds), g = g_cmd (g, args.cmds{:}); endif
330
331				# set all in g.cmds
332  tmp = {"title", \
333	 "xrange", "yrange", "y2range", "x2range", \
334	 "xlabel", "ylabel", "x2label", "y2label", \
335	 "grid", "xgrid", "ygrid"};
336  for i = 1:length(tmp)
337    if struct_contains (args, tmp{i})
338      value = args.(tmp{i});
339      val_str = _g_stringify (tmp{i}, value);
340      g = g_cmd (g,["set ",tmp{i}," ",val_str,""]);
341    endif
342  endfor
343  for i = 1:length(labels)
344    g = g_cmd (g,"pr:3:set label %i \"%s\" at screen %g,%g",i,labels{i},labpos(i,:));
345  endfor
346
347  if nplots
348
349    for j = 1:3
350
351      Z = {"x","y",""}{j};
352      Zmap =   [Z,"map"];
353      Ztics =  [Z,"tics"];
354      Zrange = [Z,"range"];
355
356      if ! isempty (args.(Zmap)) && ! struct_contains (args,Ztics) # Must figure tics for map
357
358	if struct_contains(args,Zrange)	# Determine range
359	  rng = args.(Zrange);
360	else
361	  rng = [inf,-inf];
362	  for i = 1:nplots
363	    if all (img_indices != i)
364	      rng = [min(rng(1), min (plots{i}(:,1))), \
365		     max(rng(2), max (plots{i}(:,1)))];
366	    end
367	  end
368	  assert (all (isfinite (rng)))
369	end
370	args.(Ztics) = _g_default_tics (rng);
371      end
372      if struct_contains(args,Ztics)
373
374	if isempty (args.(Ztics))	# No tics
375
376	  g = g_cmd (g,["unset ",Ztics]);
377
378				# Explicit command tics
379	elseif ischar (args.(Ztics))
380
381	  g =  g_cmd (g, ["set ", Ztics, " ", args.(Ztics)]);
382
383				# Numerical tics
384	else
385	  Zmajor = {};
386	  if any (isnan (args.(Ztics)))	# FIXME only works for vector args.(Ztics)
387	    imajor =  find(isnan (args.(Ztics)));
388	    imajor -= cumsum(isnan (args.(Ztics)))(imajor) - 1;
389	    Zmajor = {"major",imajor};
390	    args.(Ztics) = args.(Ztics)(! isnan (args.(Ztics)));
391	  end
392	  if ! isempty (args.(Zmap)) && isvector (args.(Ztics))
393	    args.(Ztics) = [_g_map(args.(Zmap), args.(Ztics)(:)'); args.(Ztics)(:)'];
394	    g = g_cmd (g, _g_tics (args.(Ztics)(1,:), args.(Ztics)(2,:), Z, Zmajor{:}));
395	  else
396	    g = g_cmd (g, _g_tics (args.(Ztics), args.(Ztics), Z, Zmajor{:}));
397	  end
398	end
399      end
400    end				# EOF loop over x, y
401
402    for i = 1:nplots
403
404      if all (img_indices != i)
405
406	plots{i}(:,1) = _g_map (args.xmap, plots{i}(:,1));
407	plots{i}(:,2) = _g_map (args.ymap, plots{i}(:,2));
408	if length (stop) >= i && ! isempty (stop{i})
409	  pre_args = {"-stops",stop{i}};
410	else
411	  pre_args = {"-step", step(i)};
412	end
413
414	if ! (isscalar (dataLabels{i}) && !dataLabels{i})
415	  pre_args = {pre_args{:}, "-label", dataLabels{i}};
416	end
417
418	g = g_data (g,pre_args{:}, names{i}, plots{i});
419
420      else
421	g = g_data (g,"-uint8",        names{i}, plots{i});
422      end
423    endfor
424    ##plotcmds
425    g = g_cmd (g,["plot ",plotcmds(1:end-2)]);
426  endif
427				# EOF Transform args in a gnuplot_object
428  if nargout < 1 || length(filename) || do_display
429    extras = {"-color",do_color};
430    if do_wait
431      extras = {extras{:}, "-wait"};
432    endif
433    if ! do_display
434      extras = {extras{:}, "-display", 0};
435    endif
436    if filename, g = g_plot (g,filename,extras{:});
437    else         g = g_plot (g,extras{:});
438    endif
439    if struct_contains (g, "double_clicks")
440      printf ("Double-clicked locations:\n");
441      g.double_clicks
442    end
443    if struct_contains (g, "middle_clicks")
444      printf ("Middle-clicked locations:\n");
445      g.middle_clicks
446    end
447    filename = "";
448    if nargout < 1
449      "deleting"
450      g_delete (g);
451      clear g;
452    else
453      "not deleting"
454    endif
455  endif
456endfunction
457
458
459%!demo
460%! printf ("\n\tNote: You may need to resize the window to see the plots\n\n");
461%! %-------------------------------------------------
462%! im = rand(16,31);
463%! im(3:10,5:25) = linspace(0,0.5,8)'*ones(1,21)+ones(8,1)*linspace(0,0.5,21);
464%! g_ez ("title","A random grey image","plot",im, "img")
465%! %-------------------------------------------------
466%! % a random greylevel image
467
468%!demo
469%! t=linspace(-pi,pi,101); x = sin(t); y = sin (t+pi/3);
470%! g_ez ("title","Some sines","plot",t,x,"-",t,y,"-")
471%! %-------------------------------------------------
472%! % some sines
473
474%!demo
475%! im = rand(16,31,3);
476%! im(3:10,5:25,1) = linspace(0,1,8)'*ones(1,21);
477%! im(3:10,5:25,2) = 0.5;
478%! im(3:10,5:25,3) = 1;
479%! g_ez ("xrange",[-1,1],"plot",im*255, "img")
480%! %-------------------------------------------------
481%! % a random color image
482
483
484
485
486
487
488
489