Mercurial > hg > ltpda
diff m-toolbox/classes/@ao/.#iplot.m.1.139 @ 0:f0afece42f48
Import.
author | Daniele Nicolodi <nicolodi@science.unitn.it> |
---|---|
date | Wed, 23 Nov 2011 19:22:13 +0100 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/m-toolbox/classes/@ao/.#iplot.m.1.139 Wed Nov 23 19:22:13 2011 +0100 @@ -0,0 +1,2570 @@ +% IPLOT provides an intelligent plotting tool for LTPDA. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% DESCRIPTION: IPLOT provides an intelligent plotting tool for LTPDA. +% +% CALL: hfig = iplot (a,pl) +% [hfig, hax] = iplot (a,pl) +% [hfig, hax, hli] = iplot (a,pl) +% +% INPUTS: pl - a parameter list +% a - input analysis object +% +% OUTPUTS: hfig - handles to figures +% hax - handles to axes +% hli - handles to lines +% +% AO Plot Info +% ------------ +% +% If an input AO has a filled plotinfo plist, then the options contained in +% therein will overide any other options. The recognised keys are: +% +% 'linestyle', 'linewidth', 'color', 'marker', 'legend_on' +% +% The possible values are all those accepted by plot. +% +% +% Notes on Parameters +% ------------------- +% +% Many of the properties take cell-array values. If the length of +% the cell array is shorter than the number of lines to plot, the +% remaining lines will be plotted with the default options. If the +% cell array is of length 2 and the first cell contains the string +% 'all', then the second cell is used to set the propery of all +% lines. +% +% +% Error parameters: If you give more than one input AO then you must +% specify the following parameter values in a cell-array, +% one cell for each input AO. Leave the cell empty to +% plot no errors. Each error can be a value or a vector +% the same length as the data vector. If you give and +% upper limit but not lower limit, then the errors are +% assumed to be symmetric (and vice versa) +% +% +% EXAMPLES: +% +% 1) Plot two time-series AOs with different colors, line styles, and widths +% +% pl = plist('Linecolors', {'g', 'k'}, 'LineStyles', {'None', '--'}, 'LineWidths', {1, 4}); +% iplot(tsao1, tsao2, pl); +% +% 2) Plot two time-series AOs in subplots. Also override the second legend +% text and the first line style. +% +% pl = plist('Arrangement', 'subplots', 'LineStyles', {'--'}, 'Legends', {'', 'My Sine Wave'}); +% iplot(tsao1, tsao2, pl); +% +% +% 3) Plot two frequency-series AOs on subplots with the same Y-scales and +% Y-ranges +% +% pl1 = plist('Yscales', {'All', 'lin'}); +% pl2 = plist('arrangement', 'subplots', 'YRanges', {'All', [1e-6 100]}); +% iplot(fsd1, fsd2, pl1, pl2) +% +% <a href="matlab:utils.helper.displayMethodInfo('ao', 'iplot')">Parameters Description</a> +% +% VERSION: $Id: iplot.m,v 1.139 2011/06/01 13:08:47 hewitson Exp $ +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% DEPRECATED xmaths and ymaths in release 2.4 + +% 3) Plot two time-series AOs taking the square of the y-values of the +% first AO and the log of the x-values of the second AO. +% +% pl = plist('Arrangement', 'subplots', 'YMaths', 'y.^2', 'XMaths', {'', 'log(x)'}); +% iplot(tsao1, tsao2, pl); + +% Math operations: You can specify rudimentary math operations to be +% performed on the X and Y data prior to plotting. The +% 'all' keyword is also supported by these parameters. +% + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% TODO: +% 1) Add XRange, YRange, ZRange to xyzdata +% + +function varargout = iplot(varargin) + + import utils.const.* + + %% Check if this is a call for parameters + if utils.helper.isinfocall(varargin{:}) + varargout{1} = getInfo(varargin{3}); + return + end + + utils.helper.msg(msg.PROC3, 'running %s/%s', mfilename('class'), mfilename); + + % Collect input variable names + in_names = cell(size(varargin)); + for ii = 1:nargin,in_names{ii} = inputname(ii);end + + % Collect all AOs and plists + [as, ao_invars] = utils.helper.collect_objects(varargin(:), 'ao', in_names); + [upl, pl_invars] = utils.helper.collect_objects(varargin(:), 'plist', in_names); + if numel(upl)>1, upl = combine(upl); end + + %% Go through AOs and collect them into similar types + + tsAOs = []; + fsAOs = []; + xyAOs = []; + xyzAOs = []; + cAOs = []; + + consistent = 1; + for jj = 1:numel(as) + % Check if AOs are consistent (all containing data of the same class): + if ~strcmpi(class(as(jj).data) , class(as(1).data) ), consistent = 0; end; + switch class(as(jj).data) + case 'tsdata' + if isempty(as(jj).y) + warning('AO %s has no data and will not be plotted', as(jj).name); + else + tsAOs = [tsAOs as(jj)]; %#ok<*AGROW> + end + case 'fsdata' + if isempty(as(jj).y) + warning('AO %s has no data and will not be plotted', as(jj).name); + else + fsAOs = [fsAOs as(jj)]; + end + case 'xydata' + if isempty(as(jj).y) + warning('AO %s has no data and will not be plotted', as(jj).name); + else + xyAOs = [xyAOs as(jj)]; + end + case 'xyzdata' + if isempty(as(jj).y) + warning('AO %s has no data and will not be plotted', as(jj).name); %#ok<*WNTAG> + else + xyzAOs = [xyzAOs as(jj)]; + end + case 'cdata' + if isempty(as(jj).y) + warning('AO %s has no data and will not be plotted', as(jj).name); + else + cAOs = [cAOs as(jj)]; + end + otherwise + warning('!!! Unknown data type %s', class(as(jj).data)); + end + end + + + %% Now plot all the objects on separate figures + % (unless they're consistent and a figure handle was passed) + + if consistent && ~isempty(upl), fig2plot = find(upl,'Figure'); else fig2plot = []; end + + hfig = []; + hax = []; + hli = []; + + %----------- TSDATA + if ~isempty(tsAOs) + % get default plist + dpl = getDefaultPlist('Time-series plot'); + % combine the plists + pl = parse(upl, dpl); + % Call x-y plot + [hf, ha, hl] = xy_plot(tsAOs, pl, fig2plot); + hfig = [hfig hf]; + hax = [hax ha]; + hli = [hli hl]; + end + %----------- XYDATA + if ~isempty(xyAOs) + % get default plist + dpl = getDefaultPlist('X-Y data plot'); + % combine the plists + pl = parse(upl, dpl); + % Call x-y plot + [hf, ha, hl] = xy_plot(xyAOs, pl, fig2plot); + hfig = [hfig hf]; + hax = [hax ha]; + hli = [hli hl]; + end + %----------- XYZDATA + if ~isempty(xyzAOs) + % get default plist + dpl = getDefaultPlist('3D plot'); + % combine the plists + pl = parse(upl, dpl); + % Call x-y-z plot + [hf, ha, hl] = xyz_plot(xyzAOs, pl, fig2plot); + hfig = [hfig hf]; + hax = [hax ha]; + hli = [hli hl]; + end + %----------- CDATA + if ~isempty(cAOs) + % get default plist + dpl = getDefaultPlist('Y data plot'); + % combine the plists + pl = parse(upl, dpl); + % Call x-y plot + [hf, ha, hl] = y_plot(cAOs, pl, fig2plot); + hfig = [hfig hf]; + hax = [hax ha]; + hli = [hli hl]; + end + %----------- FSDATA + if ~isempty(fsAOs) + % get default plist + dpl = getDefaultPlist('Frequency-series plot'); + % combine the plists + pl = parse(upl, dpl); + % Call fsdata plot + [hf, ha, hl] = fs_plot(fsAOs, pl, fig2plot); + hfig = [hfig hf]; + hax = [hax ha]; + hli = [hli hl]; + end + + %% Deal with outputs + if nargout == 1 + varargout{1} = hfig; + end + if nargout == 2 + varargout{1} = hfig; + varargout{2} = hax; + end + if nargout == 3 + varargout{1} = hfig; + varargout{2} = hax; + varargout{3} = hli; + end + + if nargout > 3 + error('### Incorrect number of outputs'); + end + +end + +%-------------------------------------------------------------------------- +% Plot fsdata objects +% +function varargout = fs_plot(varargin) + + aos = varargin{1}; + pl = varargin{2}; + fig2plot = varargin{3}; + + UseLatex = find(pl, 'LatexLabels'); + if ischar(UseLatex) + UseLatex = eval(UseLatex); + end + + % Extract parameters + arrangement = find(pl, 'Arrangement'); + colors = find(pl, 'Colors'); + linecolors = find(pl, 'LineColors'); + linestyles = find(pl, 'LineStyles'); + markers = find(pl, 'Markers'); + linewidths = find(pl, 'LineWidths'); + legends = find(pl, 'Legends'); + legendsFont = find(pl, 'LegendFontSize'); + ylabels = find(pl, 'YLabels'); + xlabels = find(pl, 'XLabels'); + yscales = find(pl, 'YScales'); + xscales = find(pl, 'XScales'); + yranges = find(pl, 'YRanges'); + xranges = find(pl, 'XRanges'); + xmaths = find(pl, 'XMaths'); + ymaths = find(pl, 'YMaths'); + type = find(pl, 'Function'); + legendLoc = find(pl, 'LegendLocation'); + complexPlotType = find(pl, 'complexPlotType'); + autoErrors = find(pl, 'AUTOERRORS'); + + % Convert the colour if it is a character to a cell-string + if ischar(colors) + colors = cellstr(colors); + end + + % get errors + XerrL = find(pl, 'XerrL'); + XerrU = find(pl, 'XerrU'); + YerrL = find(pl, 'YerrL'); + YerrU = find(pl, 'YerrU'); + if ~iscell(XerrU), XerrU = {XerrU}; end + if ~iscell(XerrL), XerrL = {XerrL}; end + if ~iscell(YerrU), YerrU = {YerrU}; end + if ~iscell(YerrL), YerrL = {YerrL}; end + if (numel(XerrL) > 1 && numel(XerrL) ~= numel(aos)) || ... + (numel(YerrL) > 1 && numel(YerrL) ~= numel(aos)) || ... + (numel(XerrU) > 1 && numel(XerrU) ~= numel(aos)) || ... + (numel(YerrU) > 1 && numel(YerrU) ~= numel(aos)) + error('### Please specify 1 set of errors for all AOs, or a set of errors for each AO.'); + end + + % check whether we want legends or not + if iscell(legends) + legendsOn = 1; + else + if strcmpi(legends, 'off') + legendsOn = 0; + else + legendsOn = 1; + legends = []; + end + end + + if ~isempty(ymaths) || ~isempty(xmaths) + warning('The use of the ''ymaths'' and ''xmaths'' parameters is deprecated. Please perform any calculations before calling iplot.'); + end + + if ~iscell(linewidths), linewidths = {linewidths}; end + if ~iscell(linestyles), linestyles = {linestyles}; end + if ~iscell(linecolors), linecolors = {linecolors}; end + if ~iscell(markers), markers = {markers}; end + if ~iscell(legends), legends = {legends}; end + if ~iscell(ylabels), ylabels = {ylabels}; end + if ~iscell(xlabels), xlabels = {xlabels}; end + if ~iscell(xmaths), xmaths = {xmaths}; end + if ~iscell(ymaths), ymaths = {ymaths}; end + if ~iscell(xscales), xscales = {xscales}; end + if ~iscell(yscales), yscales = {yscales}; end + if ~iscell(xranges), xranges = {xranges}; end + if ~iscell(yranges), yranges = {yranges}; end + + % collect figure handles + fsfig = []; fsax = []; fsli = []; + % Legend holder + legendStrR = []; + legendStrI = []; + % Helper variables + ymin = Inf; + ymax = -Inf; + xmin = Inf; + xmax = -Inf; + complexFig = []; + complexAxes = []; + + if ~isempty(aos) + % Now loop over AOs + Na = length(aos); + % First to check if any are complex y data including any Y maths at the same + % time. + haveComplex = 0; + for jj = 1:Na + % Get data + y = aos(jj).data.getY; + % Do any math operations + ymath = parseOptions(jj, ymaths, 'y'); + eval(sprintf('y = %s;', ymath)); + % Is this a complex plot? + if ~isreal(y) + haveComplex = 1; + end + end + + % Do we want to use a unit placeholder on the yaxis? + yunits = aos(1).data.yunits; + yunitPlaceholder = '[Mixed]'; + useYunitPlaceholder = false; + if strcmpi(arrangement, 'stacked') + for jj = 1:Na + if yunits ~= aos(jj).data.yunits + useYunitPlaceholder = true; + break; + end + end + end + ylabeli = ''; + % Do we want to use a unit placeholder on the xaxis? + xunits = aos(1).data.xunits; + xunitPlaceholder = '[Mixed]'; + useXunitPlaceholder = false; + if strcmpi(arrangement, 'stacked') + for jj = 1:Na + if xunits ~= aos(jj).data.xunits + useXunitPlaceholder = true; + break; + end + end + end + + % No plot + for jj = 1:Na + + if useYunitPlaceholder + yunits = yunitPlaceholder; + else + yunits = aos(jj).data.yunits; + end + if useXunitPlaceholder + xunits = xunitPlaceholder; + else + xunits = aos(jj).data.xunits; + end + % set real and imag subplot handles to empty + fsax_r = []; + fsax_i = []; + % Get data + x = aos(jj).data.getX; y = aos(jj).data.getY; + % Do any math operations + ymath = parseOptions(jj, ymaths, 'y'); eval(sprintf('y = %s;', ymath)); + xmath = parseOptions(jj, xmaths, 'x'); eval(sprintf('x = %s;', xmath)); + % what figures do we need? + switch arrangement + case 'single' + fsfig = [fsfig figure]; + col = colors{1}; + % check if this data set is real or complex + if ~isreal(y) + % complex means we use two subplots + fsax_r = subplot(2,1,1); fsax_i = subplot(2,1,2); + fsax = [fsax fsax_r fsax_i]; + complexFig = [complexFig get(fsax_r, 'Parent')]; + complexAxes = [complexAxes fsax_r fsax_i]; + else + % real means we use a single subplot + fsax_r = subplot(1, 1, 1); + fsax = [fsax fsax_r]; + end + % Make sure we reset the helper variables in this case + ymin = Inf; ymax = -Inf; xmin = Inf; xmax = -Inf; + case 'stacked' + if ~isempty(fig2plot), fsfig = fig2plot; + elseif jj == 1, fsfig = figure; + end + % if at least one of the input fsdata AOs is complex, we need to + % allow for subplots + if haveComplex + fsax_r = subplot(2,1,1,'Parent',fsfig); fsax_i = subplot(2,1,2,'Parent',fsfig); + fsax = [fsax_r fsax_i]; + if jj == 1 + complexFig = [complexFig fsfig]; + complexAxes = [complexAxes fsax_r fsax_i]; + end + else + fsax_r = subplot(1, 1, 1,'Parent',fsfig); + fsax = fsax_r; + end + col = colors{mod(jj-1,length(colors))+1}; + hold(fsax_r, 'on'); + if ishandle(fsax_i) + hold(fsax_i, 'on'); + end + case 'subplots' + if ~isempty(fig2plot), fsfig = fig2plot; + elseif jj == 1, fsfig = figure; + end + c = 1+(jj-1)*2; + sx = Na; + sy = 2; + % Now we have one or two subplots per input object. + if ~isreal(y) + fsax_r = subplot(sx, sy,c); fsax_i = subplot(sx, sy,c+1); + fsax = [fsax fsax_r fsax_i]; + else + fsax_r = subplot(sx, sy, c:c+1); + fsax = [fsax fsax_r]; + end + col = colors{1}; + % Make sure we reset the helper variables in this case + ymin = Inf; ymax = -Inf; xmin = Inf; xmax = -Inf; + otherwise + error('### Unknown plot arrangement'); + end + + % Process errors + [fcn, xu, xl, yu, yl] = process_errors(jj, size(y), type, XerrU, XerrL, YerrU, YerrL, aos(jj), autoErrors); + + %------- Plot the data + + % plot real or complex data and setup default values for scale and + % labels as we go. + if isreal(y) + % if the data are real, then we don't expect negative error bars + idx = find(yl>abs(y)); + yl(idx) = 0.999*abs(y(idx)); + switch fcn + case 'errorbar' + li = errorbar(fsax_r, x, y, yl, yu); + le = false; + case type + li = feval(type, fsax_r, x, y); + le = false; % we have no error plots + case 'errorbarxy' + lhs = errorbarxy(fsax_r, x, y, xu, yu, xl, yl); + li = lhs(1); + le = lhs(2); + end + fsli = [fsli li]; + ylabelr = ''; ylabeli = 'imag'; + yscaleR = 'log'; yscaleI = 'lin'; + xscaleR = 'log'; xscaleI = 'log'; + else + switch complexPlotType + case 'realimag' + switch fcn + case 'errorbar' + ry = real(y); + ferr = yl./abs(y); + yl = ry.*ferr; + yu = ry.*ferr; + li = errorbar(fsax_r, x, ry, yl, yu); + le = false; + case type + li = feval(type, fsax_r, x, real(y)); + le = false; % we have no error plots + case 'errorbarxy' + lhs = errorbarxy(fsax_r, x, real(y), xu, yu, xl, yl); + li = lhs(1); + le = lhs(2); + end + switch fcn + case 'errorbar' + iy = imag(y); + ferr = yl./abs(y); + yl = iy.*ferr; + yu = iy.*ferr; + li = [li errorbar(fsax_i, x, iy, yl, yu)]; + le = false; + case type + li = [li feval(type, fsax_i, x, imag(y))]; + le = false; % we have no error plots + case 'errorbarxy' + lhs = errorbarxy(fsax_i, x, imag(y), xu, yu, xl, yl); + li = [li lhs(1)]; + le = lhs(2); + end + fsli = [fsli li]; + ylabelr = 'real'; ylabeli = 'imag'; + yscaleR = 'lin'; yscaleI = 'lin'; + xscaleR = 'log'; xscaleI = 'log'; + case 'absdeg' + a = abs(y); + p = utils.math.phase(y); + % if the data are absolute values, then we don't expect + % negative error bars + idx = find(yl>abs(y)); + yl(idx) = 0.999*abs(y(idx)); + switch fcn + case 'errorbar' + li = errorbar(fsax_r, x, a, yl, yu); + le = false; + case type + li = feval(type, fsax_r, x, abs(y)); + le = false; % we have no error plots + case 'errorbarxy' + lhs = errorbarxy(fsax_r, x, abs(y), xu, yu, xl, yl); + li = lhs(1); le = lhs(2); + end + switch fcn + case 'errorbar' + ferr = yl./a; + yl = 360.*ferr; + yu = 360.*ferr; + li = [li errorbar(fsax_i, x, p, yl, yu)]; + le = false; + case type + li = [li feval(type, fsax_i, x, utils.math.phase(y))]; + le = false; % we have no error plots + case 'errorbarxy' + lhs = errorbarxy(fsax_i, x, utils.math.phase(y), xu, yu, xl, yl); + li = [li lhs(1)]; le = lhs(2); + end + fsli = [fsli li]; + ylabelr = 'Amplitude'; ylabeli = 'Phase'; + yscaleR = 'log'; yscaleI = 'lin'; + xscaleR = 'log'; xscaleI = 'log'; + case 'absrad' + % if the data are absolute values, then we don't expect + % negative error bars + idx = find(yl>abs(y)); + yl(idx) = 0.999*abs(y(idx)); + switch fcn + case 'errorbar' + li = errorbar(fsax_r, x, abs(y), yl, yu); + le = false; %#ok<*NASGU> + case type + li = feval(type, fsax_r, x, abs(y)); + le = false; % we have no error plots + case 'errorbarxy' + lhs = errorbarxy(fsax_r, x, abs(y), xu, yu, xl, yl); + li = lhs(1); le = lhs(2); + end + switch fcn + case 'errorbar' + ferr = yl./abs(y); + yl = pi.*ferr; + yu = pi.*ferr; + li = [li errorbar(fsax_i, x, angle(y), yl, yu)]; + le = false; + case type + li = [li feval(type, fsax_i, x, angle(y))]; + le = false; % we have no error plots + case 'errorbarxy' + lhs = errorbarxy(fsax_i, x, angle(y), xu, yu, xl, yl); + li = [li lhs(1)]; + le = lhs(2); + end + fsli = [fsli li]; + ylabelr = 'Amplitude'; ylabeli = 'Phase'; + yscaleR = 'log'; yscaleI = 'lin'; + xscaleR = 'log'; xscaleI = 'log'; + otherwise + error('### Unknown plot type for complex data'); + end + end + + %------- Axis properties + % axis counter + c = 1+(jj-1)*2; + + % Set real axis ylabel + ylstrR = parseOptions(c, ylabels, ylabelr); + ylstrR = prepareAxisLabel(yunits, ymath, ylstrR, 'y', UseLatex); + ylstrR = fixlabel(ylstrR); + if UseLatex + ylabel(fsax_r, ylstrR, 'interpreter', 'latex'); + else + ylabel(fsax_r, ylstrR); + end + + % Set imag axis ylabel + if ishandle(fsax_i) + ylstrI = parseOptions(c+1, ylabels, ylabeli); + switch complexPlotType + case 'realimag' + ylstrI = prepareAxisLabel(yunits, ymath, ylstrI, 'y', UseLatex); + case 'absdeg' + ylstrI = prepareAxisLabel(unit('deg'), [], ylstrI, 'y', UseLatex); + case 'absrad' + ylstrI = prepareAxisLabel(unit('rad'), [], ylstrI, 'y', UseLatex); + otherwise + end + ylstrI = fixlabel(ylstrI); + if UseLatex + ylabel(fsax_i, ylstrI, 'interpreter', 'latex'); + else + ylabel(fsax_i, ylstrI); + end + end + + % Set xlabel + xlstr = parseOptions(jj, xlabels, find(pl, 'XLabels')); + xlstr = prepareAxisLabel(xunits, xmath, xlstr, 'x', UseLatex); + xlstr = fixlabel(xlstr); + if isreal(y) + if UseLatex + xlabel(fsax_r, xlstr, 'interpreter', 'latex'); + else + xlabel(fsax_r, xlstr); + end + else + % Do not draw Xlabel and XTicklabel on the real plot + set(fsax_r, 'XTickLabel',[]); + end + if ~isempty(fsax_i) && ishandle(fsax_i) + if UseLatex + xlabel(fsax_i, xlstr, 'interpreter', 'latex'); + else + xlabel(fsax_i, xlstr); + end + end + + % Set grid on or off + grid(fsax_r, 'on'); + if ~isempty(fsax_i) && ishandle(fsax_i), grid(fsax_i, 'on'); end + + % Set Y scale + yscaleR = parseOptions(c, yscales, yscaleR); + yscaleI = parseOptions(c+1, yscales, yscaleI); + set(fsax_r, 'YScale', yscaleR); + if ~isempty(fsax_i) && ishandle(fsax_i), set(fsax_i, 'YScale', yscaleI); end + + % Set X scale + xscaleR = parseOptions(c, xscales, xscaleR); + xscaleI = parseOptions(c+1, xscales, xscaleI); + set(fsax_r, 'XScale', xscaleR); + if ~isempty(fsax_i) && ishandle(fsax_i) + set(fsax_i, 'XScale', xscaleI); + end + + % Set Y range + yrange = parseOptions(c, yranges, []); + if ~isempty(yrange) + set(fsax_r, 'YLim', yrange); + elseif strcmpi(yscaleR, 'log') + [tcks,ymin,ymax] = getRealYDataTicks(y, ymin, ymax, complexPlotType, yscaleR); + nticks = numel(tcks); + if nticks>0 && nticks < 10 + yrange = [tcks(1) tcks(end)]; + set(fsax_r, 'YLim', yrange); + set(fsax_r, 'Ytickmode', 'manual'); + set(fsax_r, 'Ytick', tcks); + end + end + yrange = parseOptions(c+1, yranges, []); + if ~isempty(fsax_i) && ishandle(fsax_i) + if ~isempty(yrange) + set(fsax_i, 'YLim', yrange); + elseif strcmpi(yscaleI, 'log') + + % This doesn't really make sense since the imaginary part or + % phase or angle will always contain negative parts. Would the + % user really choose a log scale in that case? + % tcks = getImagYDataTicks(y, ymin, ymax, complexPlotType, yscaleI); + % if ~isempty(tcks) + % yrange = [tcks(1) tcks(end)]; + % set(fsax_i, 'YLim', yrange); + % set(fsax_i, 'Ytickmode', 'manual'); + % set(fsax_i, 'Ytick', tcks); + % end + end + end + + % Set X range + xrange = parseOptions(c, xranges, []); + if ~isempty(xrange) + set(fsax_r, 'XLim', xrange); + elseif strcmpi(xscaleR, 'log') + xmin = min(xmin, floor(log10(min(x(x>0))))); + xmax = max(xmax, ceil(log10(max(x(x>0))))); + tcks = logspace(xmin, xmax, xmax - xmin +1); + xrange = [tcks(1) tcks(end)]; + set(fsax_r, 'XLim', xrange); + set(fsax_r, 'Xtickmode', 'manual'); + set(fsax_r, 'Xtick', tcks); + end + xrange = parseOptions(c+1, xranges, []); + if ~isempty(fsax_i) && ishandle(fsax_i) + if ~isempty(xrange) + set(fsax_i, 'XLim', xrange); + elseif strcmpi(xscaleR, 'log') + xmin = min(xmin, floor(log10(min(x(x>0))))); + xmax = max(xmax, ceil(log10(max(x(x>0))))); + tcks = logspace(xmin, xmax, xmax - xmin +1); + xrange = [tcks(1) tcks(end)]; + set(fsax_i, 'XLim', xrange); + set(fsax_i, 'Xtickmode', 'manual'); + set(fsax_i, 'Xtick', tcks); + end + end + + %------- line properties + [col, lstyle, lwidth, mkr] = parseLineProps(jj, aos(jj).plotinfo, ... + linecolors, col, ... + linestyles, '-', ... + linewidths, get(0,'DefaultLineLineWidth'), ... + markers, 'None'); + + % set props + set(li, 'Color', col); + set(li, 'LineStyle', lstyle); + set(li, 'LineWidth', lwidth); + if numel(x) == 1 && numel(y) == 1 && strcmp(mkr, 'None') + mkr = '.'; + end + set(li, 'Marker', mkr); + + % Set legend string + if legendsOn + if ~isempty(aos(jj).plotinfo) && ... + aos(jj).plotinfo.isparam('LEGEND_ON') && ... + ~aos(jj).plotinfo.find('LEGEND_ON') + for kk=1:numel(li) + set(get(get(li(kk),'Annotation'),'LegendInformation'),'IconDisplayStyle','off'); % Exclude line from legend + end + else + lstr = parseOptions(jj, legends, makeLegendStr(aos(jj))); + legendStrR = [legendStrR cellstr(lstr)]; + if ~isreal(y) + legendStrI = [legendStrI cellstr(lstr)]; + end + if strcmp(arrangement, 'single') || strcmp(arrangement, 'subplots') + legend(fsax_r, fixlabel(legendStrR{end}), 'Location', legendLoc); + if ~isempty(fsax_i) && ishandle(fsax_i) + h = legend(fsax_i, fixlabel(legendStrI), 'Location', legendLoc); + end + end + end + end + + end % End loop over AOs + + % Make sure the plots are refreshed + drawnow(); + % Trim the size of complex plots + for jj = 1:length(complexFig) + p_r = get(complexAxes(2*jj-1), 'Position'); + p_i = get(complexAxes(2*jj), 'Position'); + dh = (p_r(2) - (p_i(2)+p_i(4)))/3; + set(complexAxes(2*jj-1), 'Position', [p_r(1) p_r(2)-dh p_r(3) p_r(4)+dh]); + set(complexAxes(2*jj), 'Position', [p_i(1) p_i(2) p_i(3) p_i(4)+dh]); + end + + % Process legends for stacked plots + if legendsOn + if strcmp(arrangement, 'stacked') + if ~isempty(legendStrR) + h = legend(fsax_r, fixlabel(legendStrR), 'Location', legendLoc); + set(h, 'FontSize', legendsFont); + if ~isempty(fsax_i) && ishandle(fsax_i) + h = legend(fsax_i, fixlabel(legendStrI), 'Location', legendLoc); + set(h, 'FontSize', legendsFont); + end + end + end + end + end % End ~isempty AOs + + % Apply plot settings to the figure + applyPlotSettings(fsax, fsli); + + % Set outputs + if nargout > 0 + varargout{1} = fsfig; + end + if nargout > 1 + varargout{2} = fsax; + end + if nargout == 3 + varargout{3} = fsli; + end + if nargout > 3 + error('### Too many output arguments'); + end +end % End fs_plot + +%-------------------------------------------------------------------------- +% Plot tsdata and xydata objects +% +function varargout = xy_plot(varargin) + + aos = varargin{1}; + pl = varargin{2}; + fig2plot = varargin{3}; + Na = length(aos); + + UseLatex = find(pl, 'LatexLabels'); + if ischar(UseLatex) + UseLatex = eval(UseLatex); + end + + % Extract parameters + arrangement = find(pl, 'Arrangement'); + linecolors = find(pl, 'LineColors'); + colors = find(pl, 'Colors'); + linestyles = find(pl, 'LineStyles'); + markers = find(pl, 'Markers'); + linewidths = find(pl, 'LineWidths'); + legends = find(pl, 'Legends'); + legendsFont = find(pl, 'LegendFontSize'); + ylabels = find(pl, 'YLabels'); + xlabels = find(pl, 'XLabels'); + xmaths = find(pl, 'XMaths'); + ymaths = find(pl, 'YMaths'); + yranges = find(pl, 'YRanges'); + xranges = find(pl, 'XRanges'); + yscales = find(pl, 'YScales'); + xscales = find(pl, 'XScales'); + type = find(pl, 'Function'); + legendLoc = find(pl, 'LegendLocation'); + xunits = find(pl, 'Xunits'); + autoErrors = utils.prog.yes2true(find(pl, 'AUTOERRORS')); + + % Convert the colour if it is a character to a cell-string + if ischar(colors) + colors = cellstr(colors); + end + + % get errors + XerrL = find(pl, 'XerrL'); + XerrU = find(pl, 'XerrU'); + YerrL = find(pl, 'YerrL'); + YerrU = find(pl, 'YerrU'); + if ~iscell(XerrU), XerrU = {XerrU}; end + if ~iscell(XerrL), XerrL = {XerrL}; end + if ~iscell(YerrU), YerrU = {YerrU}; end + if ~iscell(YerrL), YerrL = {YerrL}; end + if (numel(XerrL) > 1 && numel(XerrL) ~= numel(aos)) || ... + (numel(YerrL) > 1 && numel(YerrL) ~= numel(aos)) || ... + (numel(XerrU) > 1 && numel(XerrU) ~= numel(aos)) || ... + (numel(YerrU) > 1 && numel(YerrU) ~= numel(aos)) + error('### Please specify 1 set of errors for all AOs, or a set of errors for each AO.'); + end + + torigin = []; + + % check whether we want legends or not + if iscell(legends) + legendsOn = 1; + else + if strcmpi(legends, 'off') + legendsOn = 0; + else + legendsOn = 1; + legends = []; + end + end + + if ~isempty(ymaths) || ~isempty(xmaths) + warning('The use of the ''ymaths'' and ''xmaths'' parameters is deprecated. Please perform any calculations before calling iplot.'); + end + + if ~iscell(linewidths), linewidths = {linewidths}; end + if ~iscell(linestyles), linestyles = {linestyles}; end + if ~iscell(linecolors), linecolors = {linecolors}; end + if ~iscell(markers), markers = {markers}; end + if ~iscell(legends), legends = {legends}; end + if ~iscell(ylabels), ylabels = {ylabels}; end + if ~iscell(xlabels), xlabels = {xlabels}; end + if ~iscell(xmaths), xmaths = {xmaths}; end + if ~iscell(ymaths), ymaths = {ymaths}; end + if ~iscell(xranges), xranges = {xranges}; end + if ~iscell(yranges), yranges = {yranges}; end + if ~iscell(xscales), xscales = {xscales}; end + if ~iscell(yscales), yscales = {yscales}; end + if ~iscell(xunits), xunits = {xunits}; end + + % collect figure handles + tsfig = []; tsax = []; tsli = []; + % Legend holder + legendStr = []; + if ~isempty(aos) + % Now loop over AOs to get earliest start time + T0 = 0; + if strcmp(arrangement, 'stacked') + T0 = 1e50; + for jj = 1:Na + % Get this AO + if isa(aos(jj).data, 'tsdata') && aos(jj).data.t0.utc_epoch_milli/1000 < T0 + T0 = floor(aos(jj).data.t0.utc_epoch_milli/1000); + end + end + end + + % Do we want to use a unit placeholder on the yaxis? + yunits = aos(1).data.yunits; + yunitPlaceholder = '[Mixed]'; + useYunitPlaceholder = false; + if strcmpi(arrangement, 'stacked') + for jj = 1:Na + if yunits ~= aos(jj).data.yunits + useYunitPlaceholder = true; + break; + end + end + end + + % Do we want to use a unit placeholder on the xaxis? + firstXunits = aos(1).data.xunits; + xunitPlaceholder = '[Mixed]'; + useXunitPlaceholder = false; + if strcmpi(arrangement, 'stacked') + for jj = 1:Na + if firstXunits ~= aos(jj).data.xunits + useXunitPlaceholder = true; + break; + end + end + end + + % Now loop over AOs + for jj = 1:Na + % Get this AO + toff = 0; + + if useYunitPlaceholder + yunits = yunitPlaceholder; + else + yunits = aos(jj).data.yunits; + end + + % what figures do we need? + switch arrangement + case 'single' + tsfig = [tsfig figure]; + tsax = subplot(1,1,1); + col = colors{1}; + if isa(aos(jj).data, 'tsdata') + torigin = aos(jj).data.t0; + end + case 'stacked' + if ~isempty(fig2plot), tsfig = fig2plot; + elseif jj==1, tsfig = figure; + end + tsax = subplot(1,1,1,'Parent',tsfig); + col = colors{mod(jj-1,length(colors))+1}; + hold on; + % deal with time-stamps here + if isa(aos(jj).data, 'tsdata') + toff = aos(jj).data.t0.utc_epoch_milli/1000 - T0; + else + toff = 0; + end + if isa(aos(jj).data, 'tsdata') + torigin = time(T0); + end + case 'subplots' + if ~isempty(fig2plot), tsfig = fig2plot; + elseif jj==1, tsfig = figure; + end + tsax = [tsax subplot(Na, 1, jj,'Parent',tsfig)]; + col = colors{1}; + if isa(aos(jj).data, 'tsdata') + torigin = aos(jj).data.t0; + end + otherwise + error('### Unknown plot arrangement'); + end + + %------- Apply math functions + + % Get data and add t0 offset for this time-series + x = aos(jj).data.getX + toff; + y = aos(jj).data.getY; + + % Apply any math operations + ymath = parseOptions(jj, ymaths, 'y'); eval(sprintf('y = %s;', ymath)); + xmath = parseOptions(jj, xmaths, 'x'); eval(sprintf('x = %s;', xmath)); + + % Process X units + if useXunitPlaceholder + xunit = xunitPlaceholder; + dateTicSpec = false; + else + if isa(aos(jj).data, 'tsdata') + xunitIn = char(aos(jj).data.xunits); + xunit = parseOptions(jj, xunits, xunitIn); + [x, xunit, dateTicSpec] = convertXunits(x, torigin, xunit, xunitIn); + elseif isa(aos(jj).data, 'xydata') + xunitIn = char(aos(jj).data.xunits); + xunit = parseOptions(jj, xunits, xunitIn); + dateTicSpec = false; + else + xunit = ''; + dateTicSpec = false; + end + end + + % Process errors + [fcn, xu, xl, yu, yl] = process_errors(jj, size(y), type, XerrU, XerrL, YerrU, YerrL, aos(jj), autoErrors); + + %------- Plot the data + + switch fcn + case 'errorbar' + li = errorbar(tsax(end), x, y, yl, yu); + le = false; + case type + li = feval(type, tsax(end), x, y); + le = false; % we have no error plots + case 'errorbarxy' + lhs = errorbarxy(tsax(end), x, y, xu, yu, xl, yl); + li = lhs(1); + le = lhs(2); + end + tsli = [tsli li]; + if isa(aos(jj).data, 'tsdata') + title(sprintf('Time origin: %s', char(torigin))); + end + + %------- Add time origin to the axis handle + + if isempty(torigin) + torigin = time(); + end + + set(tsax(end), 'UserData', torigin) + try + dcm_obj = datacursormode(get(tsfig(end),'Parent')); + catch + dcm_obj = datacursormode(tsfig(end)); + end + set(dcm_obj, 'UpdateFcn', @utils.plottools.datacursormode) + + %---------- Call datetic + if dateTicSpec + datetick(tsax(end), 'x', xunit(2:end-1), 'keeplimits'); + end + + %------- Axis properties + + % Set ylabel + ylstr = parseOptions(jj, ylabels, find(pl, 'YLabels')); + ylstr = prepareAxisLabel(yunits, ymath, ylstr, 'y', UseLatex); + ylstr = fixlabel(ylstr); + if UseLatex + ylabel(ylstr, 'interpreter', 'latex'); + else + ylabel(ylstr); + end + + % Set xlabel + xlstr = parseOptions(jj, xlabels, find(pl, 'XLabels')); + xlstr = prepareAxisLabel(xunit, xmath, xlstr, 'x', UseLatex); + xlstr = fixlabel(xlstr); + if UseLatex + xlabel(xlstr, 'interpreter', 'latex'); + else + xlabel(xlstr); + end + + % Set Y range + yrange = parseOptions(jj, yranges, []); + if ~isempty(yrange), set(tsax(end), 'YLim', yrange); end + + % Set X range + xrange = parseOptions(jj, xranges, []); + if ~isempty(xrange), set(tsax(end), 'XLim', xrange); end + + % Set Y scale + yscale = parseOptions(jj, yscales, 'lin'); + set(tsax(end), 'YScale', yscale); + + % Set X scale + xscale = parseOptions(jj, xscales, 'lin'); + set(tsax(end), 'XScale', xscale); + + % Set grid on or off + grid(tsax(end), 'on'); + + + %------- line properties + [col, lstyle, lwidth, mkr] = parseLineProps(jj, aos(jj).plotinfo, ... + linecolors, col, ... + linestyles, '-', ... + linewidths, get(0,'DefaultLineLineWidth'), ... + markers, 'None'); + + + % Set line color + set(li, 'Color', col); + if ~isempty(le) && ishandle(le), set(le, 'Color', col); end + % Set line style + set(li, 'LineStyle', lstyle); + if ishandle(le), set(le, 'LineStyle', lstyle); end + % Set markers + if numel(x) == 1 && numel(y) == 1 && strcmp(mkr, 'None') + mkr = '.'; + end + set(li, 'Marker', mkr); + % Set line widths + set(li, 'LineWidth', lwidth); + if ~isempty(le) && ishandle(le), set(le, 'LineWidth', lwidth); end + + % Set legend string + if legendsOn + if ~isempty(aos(jj).plotinfo) && ... + aos(jj).plotinfo.isparam('LEGEND_ON') && ... + ~aos(jj).plotinfo.find('LEGEND_ON') + for kk=1:numel(li) + set(get(get(li(kk),'Annotation'),'LegendInformation'),'IconDisplayStyle','off'); % Exclude line from legend + end + else + lstr = parseOptions(jj, legends, makeLegendStr(aos(jj))); + legendStr = [legendStr cellstr(lstr)]; + % Set the legend now if we can + if strcmp(arrangement, 'single') || strcmp(arrangement, 'subplots') + legend(fixlabel(legendStr{end}), 'Location', legendLoc); + end + end + end + end + + % Process legends for stacked plots + if legendsOn + if strcmp(arrangement, 'stacked') + if ~isempty(legendStr) + h = legend(fixlabel(legendStr), 'Location', legendLoc); + set(h, 'FontSize', legendsFont); + end + end + end + end % End if empty AOs + + % Apply plot settings to the figure + applyPlotSettings(tsax, tsli); + + % Set outputs + if nargout > 0 + varargout{1} = tsfig; + end + if nargout > 1 + varargout{2} = tsax; + end + if nargout == 3 + varargout{3} = tsli; + end + if nargout > 3 + error('### Too many output arguments'); + end +end % end xy_plot + + +%-------------------------------------------------------------------------- +% Plot cdata objects +% +function varargout = y_plot(varargin) + + aos = varargin{1}; + pl = varargin{2}; + fig2plot = varargin{3}; + + UseLatex = find(pl, 'LatexLabels'); + if ischar(UseLatex) + UseLatex = eval(UseLatex); + end + + % Extract parameters + arrangement = find(pl, 'Arrangement'); + linecolors = find(pl, 'LineColors'); + colors = find(pl, 'Colors'); + linestyles = find(pl, 'LineStyles'); + markers = find(pl, 'Markers'); + linewidths = find(pl, 'LineWidths'); + legends = find(pl, 'Legends'); + legendsFont = find(pl, 'LegendFontSize'); + ylabels = find(pl, 'YLabels'); + xlabels = find(pl, 'XLabels'); + xmaths = find(pl, 'XMaths'); + ymaths = find(pl, 'YMaths'); + yranges = find(pl, 'YRanges'); + xranges = find(pl, 'XRanges'); + yscales = find(pl, 'YScales'); + xscales = find(pl, 'XScales'); + type = find(pl, 'Function'); + legendLoc = find(pl, 'LegendLocation'); + autoErrors = find(pl, 'AUTOERRORS'); + + % Convert the colour if it is a character to a cell-string + if ischar(colors) + colors = cellstr(colors); + end + + % get errors + YerrL = find(pl, 'YerrL'); + YerrU = find(pl, 'YerrU'); + if ~iscell(YerrU), YerrU = {YerrU}; end + if ~iscell(YerrL), YerrL = {YerrL}; end + if (numel(YerrL) > 1 && numel(YerrL) ~= numel(aos)) || ... + (numel(YerrU) > 1 && numel(YerrU) ~= numel(aos)) + error('### Please specify 1 set of errors for all AOs, or a set of errors for each AO.'); + end + + % check whether we want legends or not + if iscell(legends) + legendsOn = 1; + else + if strcmp(legends, 'off') + legendsOn = 0; + else + legendsOn = 1; + legends = []; + end + end + + if ~isempty(ymaths) || ~isempty(xmaths) + warning('The use of the ''ymaths'' and ''xmaths'' parameters is deprecated. Please perform any calculations before calling iplot.'); + end + + if ~iscell(linewidths), linewidths = {linewidths}; end + if ~iscell(linestyles), linestyles = {linestyles}; end + if ~iscell(linecolors), linecolors = {linecolors}; end + if ~iscell(markers), markers = {markers}; end + if ~iscell(legends), legends = {legends}; end + if ~iscell(ylabels), ylabels = {ylabels}; end + if ~iscell(xlabels), xlabels = {xlabels}; end + if ~iscell(xmaths), xmaths = {xmaths}; end + if ~iscell(ymaths), ymaths = {ymaths}; end + if ~iscell(xranges), xranges = {xranges}; end + if ~iscell(yranges), yranges = {yranges}; end + if ~iscell(xscales), xscales = {xscales}; end + if ~iscell(yscales), yscales = {yscales}; end + + % collect figure handles + cfig = []; cax = []; cli = []; + % Legend holder + legendStr = []; + if ~isempty(aos) + + % Now loop over AOs + Na = length(aos); + + % Do we want to use a unit placeholder on the yaxis? + yunits = aos(1).data.yunits; + yunitPlaceholder = '[Mixed]'; + useYunitPlaceholder = false; + if strcmpi(arrangement, 'stacked') + for jj = 1:Na + if yunits ~= aos(jj).data.yunits + useYunitPlaceholder = true; + break; + end + end + end + + for jj = 1:Na + if useYunitPlaceholder + yunits = yunitPlaceholder; + else + yunits = aos(jj).data.yunits; + end + + % what figures do we need? + switch arrangement + case 'single' + cfig = [cfig figure]; + cax = subplot(1,1,1); + col = colors{1}; + case 'stacked' + if ~isempty(fig2plot), cfig = fig2plot; + elseif jj==1, cfig = figure; + end + % if jj==1, cfig = figure; end + cax = subplot(1,1,1,'Parent',cfig); + col = colors{mod(jj-1,length(colors))+1}; + hold on; + case 'subplots' + if ~isempty(fig2plot), cfig = fig2plot; + elseif jj==1, cfig = figure; + end + % if jj == 1, cfig = figure; end + cax = [cax subplot(Na, 1, jj)]; + col = colors{1}; + otherwise + error('### Unknown plot arrangement'); + end + + % Get data + if isreal(aos(jj).data.getY) + x = 1:length(aos(jj).data.getY); + y = aos(jj).data.getY; + else + x = real(aos(jj).data.getY); + y = imag(aos(jj).data.getY); + end + + %------- Apply math functions + ymath = parseOptions(jj, ymaths, 'y'); eval(sprintf('y = %s;', ymath)); + xmath = parseOptions(jj, xmaths, 'x'); eval(sprintf('x = %s;', xmath)); + % Process errors + [fcn, xu, xl, yu, yl] = process_errors(jj, size(y), type, {[]}, {[]}, YerrU, YerrL, aos(jj), autoErrors); + + %------- Plot the data + switch fcn + case 'errorbar' + lhs = errorbarxy(cax(end), x, y,zeros(size(yl)),yu,zeros(size(yl)),yl); + idcs = lhs(1); + le = lhs(2); + case type + idcs = feval(type, cax(end), x, y); + le = false; % we have no error plots + case 'errorbarxy' + lhs = errorbarxy(cax(end), x, y, xu, yu, xl, yl); + idcs = lhs(1); + le = lhs(2); + end + %------- Plot the data + % idcs = feval(type, cax(end), x, y); + % cli = [cli idcs(1:end).']; + + %------- Axis properties + + % Set ylabel + ylstr = parseOptions(jj, ylabels, find(pl, 'YLabels')); + ylstr = prepareAxisLabel(yunits, ymath, ylstr, 'y', UseLatex); + ylstr = fixlabel(ylstr); + if UseLatex + ylabel(ylstr, 'interpreter', 'latex'); + else + ylabel(ylstr); + end + + % Set xlabel + xlstr = parseOptions(jj, xlabels, find(pl, 'XLabels')); + xlstr = prepareAxisLabel(unit('Index'), xmath, xlstr, 'x', UseLatex); + xlstr = fixlabel(xlstr); + if UseLatex + xlabel(xlstr, 'interpreter', 'latex'); + else + xlabel(xlstr); + end + + % Set Y scale + yscale = parseOptions(jj, yscales, 'lin'); + set(cax(end), 'YScale', yscale); + + % Set X scale + xscale = parseOptions(jj, xscales, 'lin'); + set(cax(end), 'XScale', xscale); + + % Set Y range + yrange = parseOptions(jj, yranges, []); + if ~isempty(yrange), set(cax(end), 'YLim', yrange); end + + % Set X range + xrange = parseOptions(jj, xranges, []); + if ~isempty(xrange), set(cax(end), 'XLim', xrange); end + + % Set grid on or off + grid(cax(end), 'on'); + + %------- line properties + + [col, lstyle, lwidth, mkr] = parseLineProps(jj, aos(jj).plotinfo, ... + linecolors, col, ... + linestyles, '-', ... + linewidths, get(0,'DefaultLineLineWidth'), ... + markers, 'None'); + + % Overide line colors with user defined colors + set(idcs, 'Color', col); + if ~isempty(le) && ishandle(le), set(le, 'Color', col); end + + % Set line style + set(idcs, 'LineStyle', lstyle); + if ishandle(le), set(le, 'LineStyle', lstyle); end + % Set Markers + if numel(x) == 1 && numel(y) == 1 && strcmp(mkr, 'None') + mkr = '.'; + end + set(idcs, 'Marker', mkr); + % Set line widths + set(idcs, 'LineWidth', lwidth); + if ~isempty(le) && ishandle(le), set(le, 'LineWidth', lwidth); end + + % Set legend string + if legendsOn + if ~isempty(aos(jj).plotinfo) && ... + aos(jj).plotinfo.isparam('LEGEND_ON') && ... + ~aos(jj).plotinfo.find('LEGEND_ON') + for kk=1:numel(li) + set(get(get(li(kk),'Annotation'),'LegendInformation'),'IconDisplayStyle','off'); % Exclude line from legend + end + else + lstr = parseOptions(jj, legends, makeLegendStr(aos(jj))); + legendStr = [legendStr cellstr(lstr)]; + % Set the legend now if we can + if strcmp(arrangement, 'single') || strcmp(arrangement, 'subplots') + legend(fixlabel(legendStr{end}), 'Location', legendLoc); + end + end + end + end % End AO loop + + % Process legends for stacked plots + if legendsOn + if strcmp(arrangement, 'stacked') + if ~isempty(legendStr) + h = legend(fixlabel(legendStr), 'Location', legendLoc); + set(h, 'FontSize', legendsFont); + end + end + end + + end + + % Apply plot settings to the figure + applyPlotSettings(cax, cli); + + % Set outputs + if nargout > 0 + varargout{1} = cfig; + end + if nargout > 1 + varargout{2} = cax; + end + if nargout == 3 + varargout{3} = cli; + end + if nargout > 3 + error('### Too many output arguments'); + end +end % End y_plot + +%-------------------------------------------------------------------------- +% Plot xyzdata objects +% +function varargout = xyz_plot(varargin) + + aos = varargin{1}; + pl = varargin{2}; + fig2plot = varargin{3}; + + UseLatex = find(pl, 'LatexLabels'); + if ischar(UseLatex) + UseLatex = eval(UseLatex); + end + + % Extract parameters + arrangement = find(pl, 'Arrangement'); + legends = find(pl, 'Legends'); + legendsFont = find(pl, 'LegendFontSize'); + zlabels = find(pl, 'ZLabels'); + ylabels = find(pl, 'YLabels'); + xlabels = find(pl, 'XLabels'); + xmaths = find(pl, 'XMaths'); + ymaths = find(pl, 'YMaths'); + zmaths = find(pl, 'ZMaths'); + legendLoc = find(pl, 'LegendLocation'); + yranges = find(pl, 'YRanges'); + xranges = find(pl, 'XRanges'); + zranges = find(pl, 'ZRanges'); + zscales = find(pl, 'ZScales'); + yscales = find(pl, 'YScales'); + xscales = find(pl, 'XScales'); + invertY = find(pl, 'InvertY'); + + % check whether we want legends or not + if iscell(legends) + legendsOn = 1; + else + if strcmp(legends, 'off') + legendsOn = 0; + else + legendsOn = 1; + legends = []; + end + end + + if ~isempty(ymaths) || ~isempty(xmaths) + warning('The use of the ''ymaths'' and ''xmaths'' parameters is deprecated. Please perform any calculations before calling iplot.'); + end + + if ~iscell(legends), legends = {legends}; end + if ~iscell(ylabels), ylabels = {ylabels}; end + if ~iscell(xlabels), xlabels = {xlabels}; end + if ~iscell(zlabels), zlabels = {zlabels}; end + if ~iscell(xmaths), xmaths = {xmaths}; end + if ~iscell(ymaths), ymaths = {ymaths}; end + if ~iscell(zmaths), zmaths = {zmaths}; end + if ~iscell(xranges), xranges = {xranges}; end + if ~iscell(yranges), yranges = {yranges}; end + if ~iscell(zranges), zranges = {zranges}; end + if ~iscell(xscales), xscales = {xscales}; end + if ~iscell(yscales), yscales = {yscales}; end + if ~iscell(zscales), zscales = {zscales}; end + + + % collect figure handles + tdfig = []; + tdax = []; + tdli = []; + + % Legend holder + legendStr = []; + + if ~isempty(aos) + + % Now loop over AOs + Na = length(aos); + for jj = 1:Na + % what figures do we need? + switch arrangement + case 'single' + tdfig = [tdfig figure]; + tdax = subplot(1,1,1); + case 'subplots' + if ~isempty(fig2plot), tdfig = fig2plot; + elseif jj==1, tdfig = figure; + end + % if jj == 1, tdfig = figure; end + tdax = [tdax subplot(Na, 1, jj)]; + otherwise + warning('!!! Plot arrangement ''%s'' not supported on XYZ plots. Using ''single'' instead.', arrangement); + arrangment = 'single'; + tdfig = [tdfig figure]; + tdax = subplot(1,1,1); + end + + %------- Apply math functions + x = aos(jj).data.x; + y = aos(jj).data.getY; + z = aos(jj).data.z; + + ymath = parseOptions(jj, ymaths, 'y'); eval(sprintf('y = %s;', ymath)); + xmath = parseOptions(jj, xmaths, 'x'); eval(sprintf('x = %s;', xmath)); + zmath = parseOptions(jj, zmaths, 'z'); eval(sprintf('z = %s;', zmath)); + + %------- Plot the data + + idcs = pcolor(x,y,z); + tdli = [tdli idcs(1:end).']; + + % plot properties + set(idcs, 'EdgeColor', 'none'); + + %------- Axis properties + + % Reverse y-direction for spectrograms + if invertY + set(tdax(end), 'YDir', 'reverse'); + end + + % Set ylabel + ylstr = parseOptions(jj, ylabels, find(pl, 'YLabels')); + ylstr = prepareAxisLabel(aos(jj).data.yunits, ymath, ylstr, 'y', UseLatex); + ylstr = fixlabel(ylstr); + if UseLatex + ylabel(ylstr, 'interpreter', 'latex'); + else + ylabel(ylstr); + end + + % Set xlabel + xlstr = parseOptions(jj, xlabels, find(pl, 'XLabels')); + xlstr = prepareAxisLabel(aos(jj).data.xunits, xmath, xlstr, 'x', UseLatex); + xlstr = fixlabel(xlstr); + if UseLatex + xlabel(xlstr, 'interpreter', 'latex'); + else + xlabel(xlstr); + end + + % Set grid on or off + grid(tdax(end), 'on'); + + % Set title string + if legendsOn + if ~isempty(aos(jj).plotinfo) && ... + aos(jj).plotinfo.isparam('LEGEND_ON') && ... + ~aos(jj).plotinfo.find('LEGEND_ON') + for kk=1:numel(li) + set(get(get(li(kk),'Annotation'),'LegendInformation'),'IconDisplayStyle','off'); % Exclude line from legend + end + else + lstr = parseOptions(jj, legends, makeLegendStr(aos(jj))); + legendStr = [legendStr cellstr(lstr)]; + % Set the legend now if we can + title(legendStr{end}); + end + end + + % Set colorbars + hc = colorbar('peer', tdax(end)); + zlstr = parseOptions(jj, zlabels, find(pl, 'Zlabels')); + zlstr = prepareAxisLabel(aos(jj).data.zunits, zmath, zlstr, 'z', UseLatex); + zlstr = fixlabel(zlstr); + ylh = get(hc, 'YLabel'); + set(ylh, 'String', zlstr); + set(ylh, 'Fontsize', get(tdax(end), 'Fontsize')) + set(ylh, 'FontName', get(tdax(end), 'FontName')) + set(ylh, 'FontAngle', get(tdax(end), 'FontAngle')) + set(ylh, 'FontWeight', get(tdax(end), 'FontWeight')) + + + % Set Y scale + yscale = parseOptions(jj, yscales, 'lin'); + set(tdax(end), 'YScale', yscale); + + % Set X scale + xscale = parseOptions(jj, xscales, 'lin'); + set(tdax(end), 'XScale', xscale); + + % Set Z scale + zscale = parseOptions(jj, zscales, 'lin'); + set(tdax(end), 'ZScale', zscale); + + % Set Y range + yrange = parseOptions(jj, yranges, []); + if ~isempty(yrange), set(tdax(end), 'YLim', yrange); end + + % Set X range + xrange = parseOptions(jj, xranges, []); + if ~isempty(xrange), set(tdax(end), 'XLim', xrange); end + + % Set Z range + zrange = parseOptions(jj, zranges, []); + if ~isempty(zrange), set(tdax(end), 'CLim', zrange); end + end + end + + % Apply plot settings to the figure + applyPlotSettings(tdax, tdli); + + % Set outputs + if nargout > 0 + varargout{1} = tdfig; + end + if nargout > 1 + varargout{2} = tdax; + end + if nargout == 3 + varargout{3} = tdli; + end + if nargout > 3 + error('### Too many output arguments'); + end +end % end xyz_plot + +%-------------------------------------------------------------------------- +% Get Info Object +%-------------------------------------------------------------------------- +function ii = getInfo(varargin) + if nargin == 1 && strcmpi(varargin{1}, 'None') + sets = {}; + pl = []; + elseif nargin == 1&& ~isempty(varargin{1}) && ischar(varargin{1}) + sets{1} = varargin{1}; + pl = getDefaultPlist(sets{1}); + else + sets = {'Time-series Plot', 'Frequency-series Plot', 'Y Data Plot', 'X-Y Data Plot', '3D Plot'}; + % get plists + pl(size(sets)) = plist; + for k = 1:numel(sets) + pl(k) = getDefaultPlist(sets{k}); + end + end + % Build info object + ii = minfo(mfilename, 'ao', 'ltpda', utils.const.categories.output, '$Id: iplot.m,v 1.139 2011/06/01 13:08:47 hewitson Exp $', sets, pl); + ii.setModifier(false); + ii.setOutmin(0); +end + +% Parse line properties from plist, or defaults +function [col, lstyle, lwidth, mkr] = parseLineProps(jj, pli, ... + linecolors, dcol, ... + linestyles, dlstyle, ... + linewidths, dlwidth, ... + markers, dmkr) + + if isempty(pli) + pli = plist; + end + + % Set line color but overide with user colors + col = pli.find('color'); + if isempty(col) + col = parseOptions(jj, linecolors, dcol); + end + + % Set line style + lstyle = pli.find('linestyle'); + if isempty(lstyle) + lstyle = parseOptions(jj, linestyles, dlstyle); + end + + % Set line widths + lwidth = pli.find('linewidth'); + if isempty(lwidth) + lwidth = parseOptions(jj, linewidths, dlwidth); + end + + % Set markers + mkr = pli.find('marker'); + if isempty(mkr) + mkr = parseOptions(jj, markers, dmkr); + end + +end + + +%-------------------------------------------------------------------------- +% Get Default Plist +%-------------------------------------------------------------------------- +function plout = getDefaultPlist(set) + persistent pl; + persistent lastset; + if exist('pl', 'var')==0 || isempty(pl) || ~strcmp(lastset, set) + pl = buildplist(set); + lastset = set; + end + pl.pset('LEGENDFONTSIZE', LTPDAprefs.legendFontSize); + plout = pl; +end + +function out = buildplist(set) + + % Get the LTPDA color set for lines + colors = getappdata(0,'ltpda_default_plot_colors'); + + out = plist(); + + % Figure + p = param({'Figure',['The handle of the figure to plot in to. This will be ignored if the AOs to plot are inconsistent,<br>'... + 'containing different class of data (such as tsdata and fsdata), or if the ''arrangement''<br>',... + 'parameter is passed as ''single''.']}, paramValue.EMPTY_DOUBLE); + out.append(p); + + % Colors + p = param({'Colors', 'A list of colors which will be cycled through for each line in a plot.'}, colors); + out.append(p); + + % Arrangement + p = param({'Arrangement',['Select the plot layout:<ul>',... + '<li>''single'' - plot all AOs on individual figures</li>',... + '<li>''stacked'' - plot all AOs on the same axes</li>',... + '<li>''subplots'' - plot all AOs on subplots</li>'... + '</ul>']}, {1, {'stacked', 'single', 'subplots'}, paramValue.SINGLE}); + out.append(p); + + % Function + p = param({'Function',['Specify the plot function:<ul>',... + '<li>''plot''</li>', ... + '<li>''stairs''</li>',... + '<li>''stem''</li>',... + '</ul>'... + '[*** doesn''t work for xyzdata AOs]']}, {1, {'plot', 'stairs', 'stem'}, paramValue.SINGLE}); + out.append(p); + + % LineColors + p = param({'LineColors', ['A cell-array of color definitions, one for each trace.<br>'... + 'Give an empty string to use the default color.']}, ... + {1, {''}, paramValue.OPTIONAL}); + out.append(p); + + % LineColors + p = param({'LineStyles', ['A cell-array of line styles, one for each trace.<br>'... + 'Give an empty string to use the default style.']}, ... + {1, {''}, paramValue.OPTIONAL}); + out.append(p); + + % Markers + p = param({'Markers', ['A cell-array of markers, one for each trace.']}, ... + {1, {''}, paramValue.OPTIONAL}); + out.append(p); + + % LineWidths + p = param({'LineWidths', ['A cell-array of line widths, one for each trace.<br>'... + 'Give an empty string to use the default line width.']}, ... + {1, {''}, paramValue.OPTIONAL}); + out.append(p); + + % Legends + p = param({'Legends', ['Give a cell-array of strings to be used for<br>'... + 'the plot legends. If a cell contains an empty<br>'... + 'string, the default legend string is built.<br>'... + 'If a single string ''off'' is given instead of a<br>'... + 'cell-array, then the legends are all switched off.']}, ... + {1, {''}, paramValue.OPTIONAL}); + out.append(p); + + % LegendLocation + p = param({'LegendLocation','Choose the legend location.'}, ... + {5, {'North', 'South', 'East', 'West', ... + 'NorthEast', 'NorthWest', 'SouthEast', 'SouthWest', ... + 'NorthOutside', 'SouthOutside', 'EastOutside', 'WestOutside', ... + 'NorthEastOutside', 'NorthWestOutside', 'SouthEastOutside', ... + 'SouthWestOutside', 'Best', 'BestOutside'}, paramValue.SINGLE}); + out.append(p); + + % LegendFontSize + p = param({'LegendFontSize','Choose the legend font size.'}, ... + {1, {LTPDAprefs.legendFontSize}, paramValue.SINGLE}); + out.append(p); + + % XerrL + p = param({'XerrL','Lower bound error values for the X data points.'}, paramValue.EMPTY_DOUBLE); + out.append(p); + + % XerrU + p = param({'XerrU','Upper bound error values for the X data points.'}, paramValue.EMPTY_DOUBLE); + out.append(p); + + % YerrL + p = param({'YerrL','Lower bound error values for the Y data points.'}, paramValue.EMPTY_DOUBLE); + out.append(p); + + % YerrU + p = param({'YerrU','Upper bound error values for the Y data points.'}, paramValue.EMPTY_DOUBLE); + out.append(p); + + % XScales + p = param({'XScales', ['A cell-array specifying the scale to be used on each x-axis.<br>'... + 'For example, {''lin'', ''log''}']}, {1, {''}, paramValue.OPTIONAL}); + out.append(p); + + % YScales + p = param({'YScales', ['A cell-array specifying the scale to be used on each y-axis.<br>'... + 'For example, {''lin'', ''log''}']}, {1, {''}, paramValue.OPTIONAL}); + out.append(p); + + % XRanges + p = param({'XRanges', ['A cell-array specifying the ranges to be displayed on each x-axis.<br>'... + 'For example, {[0 1], [-4 4]}.']}, {1, {''}, paramValue.OPTIONAL}); + out.append(p); + + % YRanges + p = param({'YRanges', ['A cell-array specifying the ranges to be displayed on each y-axis.<br>'... + 'For example, {[0 1], [-4 4]}.']}, {1, {''}, paramValue.OPTIONAL}); + out.append(p); + + % LatexLabels + p = param({'LatexLabels','Use latex interpreter for axis labels.'}, paramValue.TRUE_FALSE); + p.val.setValIndex(2); + out.append(p); + + % YMaths + p = param({'YMaths',['Specify math operations to perform on the data vector ''y''. [DEPRECATED]<br>',... + 'For example, <tt>plist(''Ymaths'', ''sqrt(y)'')</tt>.']}, paramValue.EMPTY_STRING); + out.append(p); + + + % No auto-errors + p = param({'AUTOERRORS',['If the AO contains errors, they will be plotted. You can avoid plotting the <br>',... + 'errors by setting this to false.']}, paramValue.FALSE_TRUE); + out.append(p); + + switch lower(set) + case 'frequency-series plot' + % ComplexPlotType + p = param({'complexPlotType',['Specify how to plot complex data. Choose from:<ul>',... + '<li>''realimag''</li>',... + '<li>''absdeg''</li>',... + '<li>''absrad''</li>'... + '</ul>']}, {1, {'absdeg', 'realimag', 'absrad'}, paramValue.SINGLE}); + out.append(p); + + % Xlabel + p = param({'XLabels',['Specify the labels to be used on the x-axes. The units are added from<br>',... + 'the data object ''xunits'' property.']}, paramValue.STRING_VALUE('Frequency')); + out.append(p); + % ylabels + p = param({'YLabels',['Specify the labels to be used on the y-axes. The units are added from<br>',... + 'the data object ''yunits'' property.']}, paramValue.STRING_VALUE('')); + out.append(p); + + % XMaths + p = param({'XMaths',['Specify math operations to perform on the data vector ''x''. [DEPRECATED]<br>',... + 'For example, <tt>plist(''Xmaths'', ''abs(x)'')</tt>.']}, paramValue.EMPTY_STRING); + out.append(p); + + case 'time-series plot' + + % Xlabel + p = param({'XLabels',['Specify the labels to be used on the x-axes. The units are added from<br>',... + 'the data object ''xunits'' property.']}, paramValue.STRING_VALUE('Time')); + out.append(p); + + % Ylabels + p = param({'YLabels',['Specify the labels to be used on the y-axes. The units are added from<br>',... + 'the data object ''yunits'' property.']}, paramValue.STRING_VALUE('Amplitude')); + out.append(p); + + % Xunits + p = param({'Xunits', ['Specify the units of time on the x-axis as<ul>'... + '<li>''us'' - microseconds<li>' ... + '<li>''ms'' - milliseconds<li>' ... + '<li>''s'' - seconds<li>' ... + '<li>''m'' - minutes<li>' ... + '<li>''h'' - hours<li>' ... + '<li>''D'' - days<li>' ... + '<li>''M'' - months<li>' ... + '<li>''HH:MM:SS'' - using a date/time format</li>' ... + '</ul>']}, {3, {'us', 'ms', 's', 'm', 'h', 'D', 'M', 'HH:MM:SS', 'yyyy-mm-dd HH:MM:SS'}, paramValue.OPTIONAL}); + out.append(p); + + case 'x-y data plot' + % Xlabel + p = param({'XLabels',['Specify the labels to be used on the x-axes. The units are added from<br>',... + 'the data object ''xunits'' property.']}, paramValue.STRING_VALUE('X-data')); + out.append(p); + + % Ylabels + p = param({'YLabels',['Specify the labels to be used on the y-axes. The units are added from<br>',... + 'the data object ''yunits'' property.']}, paramValue.STRING_VALUE('Y-data')); + out.append(p); + + % XMaths + p = param({'XMaths',['Specify math operations to perform on the data vector ''x''. [DEPRECATED]<br>',... + 'For example, <tt>plist(''Xmaths'', ''abs(x)'')</tt>.']}, paramValue.EMPTY_STRING); + out.append(p); + + case '3d plot' + + out.pset('arrangement', 'single'); + + % Xlabel + p = param({'XLabels',['Specify the labels to be used on the x-axes. The units are added from<br>',... + 'the data object ''xunits'' property.']}, paramValue.STRING_VALUE('Time')); + out.append(p); + + % Ylabels + p = param({'YLabels',['Specify the labels to be used on the y-axes. The units are added from<br>',... + 'the data object ''yunits'' property.']}, paramValue.STRING_VALUE('Frequency')); + out.append(p); + + % Zlabels + p = param({'ZLabels',['Specify the labels to be used on the z-axes. The units are added from<br>',... + 'the data object ''zunits'' property.']}, paramValue.STRING_VALUE('Amplitude')); + out.append(p); + + % XMaths + p = param({'XMaths',['Specify math operations to perform on the data vector ''x''. [DEPRECATED]<br>',... + 'For example, <tt>plist(''Xmaths'', ''abs(x)'')</tt>.']}, paramValue.EMPTY_STRING); + out.append(p); + + % ZMaths + p = param({'ZMaths',['Specify math operations to perform on the data vector ''z''. [DEPRECATED]<br>',... + 'For example, <tt>plist(''Zmaths'', ''abs(z)'')</tt>.']}, paramValue.EMPTY_STRING); + out.append(p); + + % ZScales + p = param({'ZScales', ['A cell-array specifying the scale to be used on each z-axis.<br>'... + 'For example, {''lin'', ''log''}']}, {1, {''}, paramValue.OPTIONAL}); + out.append(p); + + % ZRanges + p = param({'ZRanges', ['A cell-array specifying the ranges to be displayed on each z-axis.<br>'... + 'For example, {[0 1], [-4 4]}.']}, {1, {''}, paramValue.OPTIONAL}); + out.append(p); + + % Invert y-axis + p = param({'InvertY', ['Invert the y-axis or not.']}, paramValue.TRUE_FALSE); + out.append(p); + + out.remove('linestyles'); + out.remove('linewidths'); + out.remove('linecolors'); + out.remove('markers'); + + case 'y data plot' + % Xlabel + p = param({'XLabels',['Specify the labels to be used on the x-axes. The units are added from<br>',... + 'the data object ''xunits'' property.']}, paramValue.STRING_VALUE('Sample')); + out.append(p); + + % Ylabels + p = param({'YLabels',['Specify the labels to be used on the y-axes. The units are added from<br>',... + 'the data object ''yunits'' property.']}, paramValue.STRING_VALUE('Value')); + out.append(p); + otherwise + error('### Unknown set [%s]', set); + end +end + + +function name = makeLegendStr(a) + + name = utils.plottools.label(a.name); + desc = utils.plottools.label(a.description); + + if isempty(name) + name = '?'; + end + + if ~isempty(desc) && LTPDAprefs.includeDescription + name = [name ': ' desc]; + end + + +end + +% Perform some substitutions on the labels +function ss = fixlabel(ss) + + MAX_LENGTH = 100; + wasCell = true; + if ~iscell(ss) + ss = {ss}; + wasCell = false; + end + + for kk = 1:numel(ss) + s = ss{kk}; + if ~isempty(s) + % Replace all ^(...) with ^{...} + jj = 1; + while jj < numel(s) + if strcmp(s(jj:jj+1), '^(') + % find next ) + for k = 1:numel(s)-jj+1 + if s(jj+k) == ')' + s(jj+1) = '{'; + s(jj+k) = '}'; + break; + end + end + end + jj = jj + 1; + end + % Replace all .^ with ^ + s = strrep(s, '.^', '^'); + + % reduce size + if length(s) > MAX_LENGTH + s = s(1:MAX_LENGTH-3); + if s(end) == '\' + s = s(1:end-1) + end + s = [ s '...' ]; + end + + end + ss(kk) = {s}; + end + + if ~wasCell + ss = ss{1}; + end + +end + +%----------------------------------------------- +% Change X data for time-series according to the specified xunits +function [x, xunit, dateTicSpec] = convertXunits(x, t0, xunit, xunitIn) + + dateTicSpec = false; + + xunit = strtrim(xunit); + xunitIn = strtrim(xunitIn); + if ~strcmpi(strtrim(xunitIn), '[s]') + warning('### I can only convert from [s] to %s - ignoring requested Xunit', xunit); + xunit = xunitIn; + else + switch strtrim(xunit) + case {'[us]', 'us'} + x = x .* 1e6; + case {'[ms]', 'ms'} + x = x .* 1e3; + case {'[s]', 's'} + case {'[m]', 'm'} + x = x ./ 60; + case {'[h]', 'h'} + x = x ./ 3600; + case {'[D]', 'D'} + x = x ./ 86400; + otherwise + % then we have a datetic spec + dateTicSpec = true; + % first convert x data to serial date + st = format(t0, 'yyyy-mm-dd hh:mm:ss'); + st = regexp(st, ' ', 'split'); + st = [st{1} ' ' st{2}]; + t0 = datenum(st); % get t0 as a serial date + x = t0 + x./86400; % convert x to days + end + end + if xunit(1) ~= '[' + xunit = ['[' xunit]; + end + if xunit(end) ~= ']' + xunit = [xunit ']']; + end + % 'us' - microseconds + % 'ms' - milliseconds + % 's' - seconds [default] + % 'm' - minutes + % 'h' - hours + % 'D' - days + % 'M' - months + % 'HH:MM:SS' - using a date/time format + +end + +%---------------------------------------- +% Prepare an axis label +function lstr = prepareAxisLabel(units, math, lstr, axis, UseLatex) + if isa(units, 'unit') + + if ismac && UseLatex + units = units.tolabel; + else + units = {fixlabel(char(units))}; + end + else + units = {units}; + end + if ~isempty(math) + if ~isempty(lstr) + lstr = strrep(math, axis, lstr); + end + lstr = [fixlabel(lstr) ' ' units{1} ]; + else + lstr = [fixlabel(lstr) ' ' units{1}]; + end +end + +% Parse cell-array of options +function opt = parseOptions(varargin) %jj, opts, dopt + + jj = varargin{1}; + opts = varargin{2}; + dopt = varargin{3}; + opt = dopt; + + if ~iscell(opts) + opts = {opts}; + end + Nopts = numel(opts); + + % First look for the 'all' keyword + if Nopts == 2 && strcmpi(opts{1}, 'all') + opt = opts{2}; + else + if jj <= Nopts && ~isempty(opts{jj}) + opt = opts{jj}; + end + end + +end + + + +% ERRORBARXY Customizable error bar plot in X and Y direction +% +% This function allows the user to plot the graph of x against y, along with +% both x and y errorbars. +% +% With 4 numeric arguments (x,y,dx,dy), error bar are assumed to be of +% same magnitude in both direction. +% +% One can specify lower and upper error bar with 6 numeric arguments +% (x,y,dx_high,dy_high,dx_low,dy_low). +% +% x,y,dx,dy,... must be vectors of the same length +% +% [hp he] = errorbarxy(...) returns respectively the handle for the line +% plot object and the line error bar object. +% +% It is possible to customize the line properties of the error bars by +% adding pair of 'field/value' fields (such as 'LineWidth',2) that can be +% understood by line. See LineProperties for more information. +% +% -------- +% EXAMPLES +% -------- +% X = 10 * rand(7,1); +% Y = 10 * rand(7,1); +% dx = rand(7,1); +% dy = rand(7,1); +% errorbarxy(X,Y,dx,dy,'Color','k','LineStyle','none','Marker','o',... +% 'MarkerFaceColor','w','LineWidth',1,'MarkerSize',11); +% +% X = 10 * rand(7,1); +% Y = 10 * rand(7,1); +% dx = rand(7,1); +% dy = rand(7,1); +% dx2 = rand(7,1); +% dy2 = rand(7,1); +% errorbarxy(X,Y,dx,dy,dx2,dy2,'Color','B','LineStyle','--','Marker','s',... +% 'MarkerFaceColor','w','LineWidth',2,'MarkerSize',11); +% +% This is a rewrite of the m-file errorbarxy of James Rooney, to add +% customizable line properties. + +% ------------------ INFO ------------------ +% Authors: Jean-Yves Tinevez +% Work address: Max-Plank Insitute for Cell Biology and Genetics, +% Dresden, Germany. +% Email: tinevez AT mpi-cbg DOT de +% November 2007 - June 2008; +% Permission is given to distribute and modify this file as long as this +% notice remains in it. Permission is also given to write to the author +% for any suggestion, comment, modification or usage. +% ------------------ BEGIN CODE ------------------ + +function out = errorbarxy(ax, x,y,varargin) + + + nargs = length(varargin); + + for i = 1 : nargs + + if ~( isnumeric(varargin{i}) ) + break + end + errbaropt{i} = varargin{i}; + + end + + + if i+3 < nargin + displayopt = varargin(i:end); + if isstruct(displayopt{1}) + options = displayopt{1}; + else + options = varargin2struct(displayopt); + end + erroroptions = options; + else + displayopt = []; + end + + options.Color = 'k'; + erroroptions.LineStyle = '-'; + erroroptions.Marker = 'none'; + + + xw = (max(x)-min(x))/100; + yw = (max(y)-min(y))/100; + + n = length(varargin) - length(displayopt); + + if n == 2 + % only 2 cells, so this is the same for lower and upper bar + ux = errbaropt{1}; + lx = ux; + uy = errbaropt{2}; + ly = uy; + + elseif n == 4 + % 4 cells, the user specified both upper and lower limit + ux = errbaropt{1}; + lx = errbaropt{3}; + uy = errbaropt{2}; + ly = errbaropt{4}; + + else + errid = 'MATLAB:errorbarxy:BadArgumentNumber'; + errmsg = ['Must have 4 or 6 numeric arguments, got ' ,num2str(n+2),'.']; + error(errid,errmsg); + + end + + + %% + + holdstate = ishold(gca); + X = []; + Y = []; + for t = 1:length(x) + + % x errorbars + X = [ X nan x(t)-lx(t) x(t)+ux(t) nan x(t)-lx(t) x(t)-lx(t) nan x(t)+ux(t) x(t)+ux(t) ]; + Y = [ Y nan y(t) y(t) nan y(t)-yw y(t)+yw nan y(t)-yw y(t)+yw ]; + + % y errorbars + X = [ X nan x(t) x(t) nan x(t)-xw x(t)+xw nan x(t)-xw x(t)+xw ]; + Y = [ Y nan y(t)-ly(t) y(t)+uy(t) nan y(t)-ly(t) y(t)-ly(t) nan y(t)+uy(t) y(t)+uy(t) ]; + + end + + hold on + axes(ax); + he = line(X,Y,erroroptions); + hp = plot(ax, x,y,options); + out = [hp he]; + + % Return to initial hold state if needed + if ~holdstate + hold off + end + + function out = varargin2struct(in) + % I hould write help + + if ~iscell(in) + errid = 'MATLAB:struct2varargin:BadInputType'; + errmsg = ['Input argument must be a cell, got a ' ,class(in),'.']; + error(errid,errmsg); + end + + n = length(in); + + if mod(n,2) ~= 0 + errid = 'MATLAB:struct2varargin:BadInputType'; + errmsg = ['Input argument must have an even number of elements, got ' ,num2str(n),'.']; + error(errid,errmsg); + end + + out = struct; + + for jj = 1 : n/2 + name = in{2*jj-1}; + value = in{2*jj}; + out.(name) = value; + end + + end + +end + +% Get a suitable ymin and ymax (in logscale) for the given +% data. +function [ticks,ymin,ymax] = getRealYDataTicks(y, ymin, ymax, complexPlotType, scale) + + ticks = []; + switch complexPlotType + case 'realimag' + if strcmpi(scale', 'log') + + % do nothing because it doesn't make sense since we will have + % negative values on a log scale + + end + case {'absdeg', 'absrad'} + + if strcmpi(scale, 'log') + % This is the main case we want to cover. + ay = abs(y); + newymin = min(ymin, floor(log10(min(ay(ay>0))))); + newymax = max(ymax, ceil(log10(max(ay(ay>0))))); + + if ~isempty(newymin) && ~isempty(newymax) + ymin = newymin; + ymax = newymax; + + if ymin == ymax + ymin = floor(log10(min(ay)/10)); + ymax = ceil(log10(max(ay)*10)); + end + + else + + if ymin == inf + ymin = -1; + end + + if ymax == -inf + ymax = 1; + end + + end + nticks = ymax - ymin +1; + % can we reduce this if they don't all fit? + + ticks = logspace(ymin, ymax, nticks); + end + + otherwise + error('### Unknown plot type for complex data'); + end + +end + +% Get a suitable ymin and ymax (in linscale) for the given +% data. +function ticks = getImagYDataTicks(y, ymin, ymax, complexPlotType, scale) + + + ticks = []; + switch complexPlotType + case 'realimag' + if strcmpi(scale', 'log') + + % do nothing because it doesn't make sense since we will have + % negative values on a log scale + + end + case 'absdeg' + + if strcmpi(scale', 'log') + % do nothing because it doesn't make sense since we will have + % negative values on a log scale + end + + case 'absrad' + + otherwise + error('### Unknown plot type for complex data'); + end + + +end + + +%------------------- +% Process errorbars +function [fcn, xu, xl, yu, yl] = process_errors(jj, dsize, ptype, XerrU, XerrL, YerrU, YerrL, a, auto) + + if numel(XerrL) == 1 + xl = XerrL{1}; + else + xl = XerrL{jj}; + end + if numel(XerrU) == 1 + xu = XerrU{1}; + else + xu = XerrU{jj}; + end + if numel(YerrL) == 1 + yl = YerrL{1}; + else + yl = YerrL{jj}; + end + if numel(YerrU) == 1 + yu = YerrU{1}; + else + yu = YerrU{jj}; + end + + % Check if we have AOs + if isa(xl, 'ao'), xl = xl.data.getY; end + if isa(xu, 'ao'), xu = xu.data.getY; end + if isa(yl, 'ao'), yl = yl.data.getY; end + if isa(yu, 'ao'), yu = yu.data.getY; end + + if isempty(xl) && ~isempty(xu) + xl = xu; + end + if isempty(xu) && ~isempty(xl) + xu = xl; + end + if isempty(yl) && ~isempty(yu) + yl = yu; + end + if isempty(yu) && ~isempty(yl) + yu = yl; + end + + + + % If the AO has errors, we use them + if ~isempty(a.dy) && auto + yl = a.dy; + yu = a.dy; + yu(yu==inf) = 0; + yl(yl==inf) = 0; + end + + if isempty(xl) && isempty(xu) && isempty(yu) && isempty(yl) + fcn = ptype; + elseif isempty(xl) && isempty(xu) + fcn = 'errorbar'; + else + fcn = 'errorbarxy'; + end + + if isempty(xl), xl = zeros(dsize); end + if isempty(yl), yl = zeros(dsize); end + if isempty(xu), xu = zeros(dsize); end + if isempty(yu), yu = zeros(dsize); end + if numel(xl) == 1, xl = xl.*ones(dsize); end + if numel(xu) == 1, xu = xu.*ones(dsize); end + if numel(yu) == 1, yu = yu.*ones(dsize); end + if numel(yl) == 1, yl = yl.*ones(dsize); end +end + +function applyPlotSettings(axesH, lineH) + + prefs = getappdata(0, 'LTPDApreferences'); + jPlotPrefs = prefs.getPlotPrefs(); + + if jPlotPrefs.getPlotApplyPlotSettings.equals(mpipeline.ltpdapreferences.EnumPlotSetting.IPLOT_ONLY) + + % Set all axes properteis + for ii =1:numel(axesH) + set(axesH(ii), 'FontSize', double(jPlotPrefs.getPlotDefaultAxesFontSize)); + set(axesH(ii), 'LineWidth', double(jPlotPrefs.getPlotDefaultAxesLineWidth)); + set(axesH(ii), 'GridLineStyle', char(jPlotPrefs.getPlotDefaultAxesGridLineStyle)); + set(axesH(ii), 'MinorGridLineStyle', char(jPlotPrefs.getPlotDefaultAxesMinorGridLineStyle)); + switch char(jPlotPrefs.getPlotDefaultAxesFontWeight) + case 'Plain' + set(axesH(ii), 'FontWeight', 'normal'); + case 'Bold' + set(axesH(ii), 'FontWeight', 'bold'); + case 'Italic' + set(axesH(ii), 'FontWeight', 'light'); + case 'Bold Italic' + set(axesH(ii), 'FontWeight', 'demi'); + otherwise + error('### Unknown value (%s) for the default axes property ''FontWeight''', char(jPlotPrefs.getPlotDefaultAxesFontWeight)); + end + end + + % Set all line properties + for ii = 1:numel(lineH) + set(lineH(ii), 'LineWidth', double(jPlotPrefs.getPlotDefaultLineLineWidth)); + set(lineH(ii), 'MarkerSize', double(jPlotPrefs.getPlotDefaultLineMarkerSize)); + end + end +end