diff options
Diffstat (limited to 'sourcecodes/bnt-master/GraphViz')
27 files changed, 3540 insertions, 0 deletions
diff --git a/sourcecodes/bnt-master/GraphViz/CVS/Entries b/sourcecodes/bnt-master/GraphViz/CVS/Entries new file mode 100644 index 00000000..5af96cda --- /dev/null +++ b/sourcecodes/bnt-master/GraphViz/CVS/Entries @@ -0,0 +1,16 @@ +/README.txt/1.1.1.1/Mon Jun 7 14:33:20 2004// +/approxeq.m/1.1.1.1/Mon Jul 28 22:44:46 2003// +/arrow.m/1.1.1.1/Fri Mar 28 16:35:06 2003// +/dot_to_graph.m/1.1.1.1/Fri Mar 12 23:21:08 2004// +/draw_dbn.m/1.1.1.1/Wed May 29 15:59:54 2002// +/draw_dbn_test.m/1.1.1.1/Sat Jan 18 21:17:18 2003// +/draw_dot.m/1.1.1.1/Wed May 5 13:32:32 2004// +/draw_graph.m/1.1.1.1/Mon Mar 22 22:32:04 2004// +/draw_graph_test.m/1.1.1.1/Mon Jan 20 16:56:02 2003// +/draw_hmm.m/1.1.1.1/Thu Feb 6 03:16:32 2003// +/editGraphGUI.m/1.1.1.1/Tue Jan 27 21:08:48 2004// +/graph_to_dot.m/1.1.1.1/Tue Jun 15 17:50:40 2004// +/make_layout.m/1.1.1.1/Wed May 29 15:59:54 2002// +/my_call.m/1.1.1.1/Tue Jan 27 21:08:38 2004// +/process_options.m/1.1.1.1/Mon Jul 28 22:44:46 2003// +D diff --git a/sourcecodes/bnt-master/GraphViz/CVS/Entries.Log b/sourcecodes/bnt-master/GraphViz/CVS/Entries.Log new file mode 100644 index 00000000..24f16336 --- /dev/null +++ b/sourcecodes/bnt-master/GraphViz/CVS/Entries.Log @@ -0,0 +1 @@ +A D/Old//// diff --git a/sourcecodes/bnt-master/GraphViz/CVS/Repository b/sourcecodes/bnt-master/GraphViz/CVS/Repository new file mode 100644 index 00000000..ba3ef5c8 --- /dev/null +++ b/sourcecodes/bnt-master/GraphViz/CVS/Repository @@ -0,0 +1 @@ +FullBNT/GraphViz diff --git a/sourcecodes/bnt-master/GraphViz/CVS/Root b/sourcecodes/bnt-master/GraphViz/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/GraphViz/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/GraphViz/Old/CVS/Entries b/sourcecodes/bnt-master/GraphViz/Old/CVS/Entries new file mode 100644 index 00000000..50af46f1 --- /dev/null +++ b/sourcecodes/bnt-master/GraphViz/Old/CVS/Entries @@ -0,0 +1,6 @@ +/dot_to_graph.m/1.1.1.1/Tue Jan 27 21:01:54 2004// +/draw_dot.m/1.1.1.1/Tue Jan 27 20:42:50 2004// +/draw_graph.m/1.1.1.1/Tue Jan 27 21:03:56 2004// +/graphToDot.m/1.1.1.1/Tue Feb 3 17:15:18 2004// +/pre_pesha_graph_to_dot.m/1.1.1.1/Tue Jan 27 20:47:40 2004// +D diff --git a/sourcecodes/bnt-master/GraphViz/Old/CVS/Repository b/sourcecodes/bnt-master/GraphViz/Old/CVS/Repository new file mode 100644 index 00000000..83ba7005 --- /dev/null +++ b/sourcecodes/bnt-master/GraphViz/Old/CVS/Repository @@ -0,0 +1 @@ +FullBNT/GraphViz/Old diff --git a/sourcecodes/bnt-master/GraphViz/Old/CVS/Root b/sourcecodes/bnt-master/GraphViz/Old/CVS/Root new file mode 100644 index 00000000..f3bd14a6 --- /dev/null +++ b/sourcecodes/bnt-master/GraphViz/Old/CVS/Root @@ -0,0 +1 @@ +:ext:nsaunier@bnt.cvs.sourceforge.net:/cvsroot/bnt diff --git a/sourcecodes/bnt-master/GraphViz/Old/dot_to_graph.m b/sourcecodes/bnt-master/GraphViz/Old/dot_to_graph.m new file mode 100644 index 00000000..59beb8fc --- /dev/null +++ b/sourcecodes/bnt-master/GraphViz/Old/dot_to_graph.m @@ -0,0 +1,107 @@ +function [Adj, labels, x, y] = dot_to_graph(filename) + +% [Adj, labels, x, y] = dot_to_graph(filename) +% Extract a matrix representation, node labels, and node position coordinates +% from a file in GraphViz format http://www.research.att.com/sw/tools/graphviz +% +% INPUTS: +% 'filename' - the file in DOT format containing the graph layout. +% OUTPUT: +% 'Adj' - an adjacency matrix representation of the graph in 'filename'; +% 'labels' - a character array with the names of the nodes of the graph; +% 'x' - a row vector with the x-coordinates of the nodes in 'filename'; +% 'y' - a row vector with the y-coordinates of the nodes in 'filename'. +% +% WARNINGS: not guaranted to parse ANY GraphViz file. Debugged on undirected +% sample graphs from GraphViz(Heawood, Petersen, ER, ngk10_4, process). +% Complaines about RecursionLimit set only to 500 on huge graphs. +% Ignores singletons (disjoint nodes). +% Sample DOT code "ABC.dot", read by [Adj, labels, x, y] = dot_to_graph('ABC.dot') +% digraph G { +% A [pos="28,31"]; +% B [pos="74,87"]; +% A -- B [pos="e,61,71 41,47 46,53 50,58 55,64"]; +% } +% last modified: Jan 2004 +% by Alexi Savov: asavov @wustl.edu | http://artsci.wustl.edu/~azsavov +% Leon Peshkin: pesha @ai.mit.edu | http://www.ai.mit.edu/~pesha + +if ~exist(filename) % Checks whether the specified file exists. + error('* * * File does not exist or could not be found. * * *'); return; +end; + +lines = textread(filename,'%s','delimiter','\n','commentstyle','c'); % Read file into cell array +dot_lines = strvcat(lines); % of lines, ignoring C-style comments + +if findstr(dot_lines(1,:), 'graph ') == [] % Is this a DOT file ? + error('* * * File does not appear to be in valid DOT format. * * *'); return; +end; + +Nlns = size(dot_lines,1); % The number of lines; +labels = {}; +unread = 1:Nlns; % 'unread' list of lines which has not been examined yet +edge_id = 1; +for line_ndx = 1:Nlns % This section sets the adjacency matrix A(Lnode,Rnode) = edge_id. + line = dot_lines(line_ndx,:); + Ddash_pos = strfind(line, ' -- ') + 1; % double dash positions + arrow_pos = strfind(line, ' -> ') + 1; % arrow dash positions + tokens = strread(line,'%s','delimiter',' "'); + left_bound = 1; + for dash_pos = [Ddash_pos arrow_pos]; % if empty - not a POS line + Lnode = sscanf(line(left_bound:dash_pos -2), '%s'); + Rnode = sscanf(line(dash_pos +3 : length(line)-1),'%s',1); + Lndx = strmatch(Lnode, labels, 'exact'); + Rndx = strmatch(Rnode, labels, 'exact'); + if isempty(Lndx) % extend our list of labels + labels{end+1} = Lnode; + Lndx = length(labels); + end + if isempty(Rndx) + labels{end+1} = Rnode; + Rndx = length(labels); + end + Adj(Lndx, Rndx) = edge_id;; + if ismember(dash_pos, Ddash_pos) % The edge is undirected, A(Rndx,LndxL) is also set to 1; + Adj(Rndx, Lndx) = edge_id; + end + edge_id = edge_id + 1; + left_bound = dash_pos + 3; + unread = setdiff(unread, line_ndx); + end +end +Nvrt = length(labels); % number of vertices we found [Do we ever have singleton vertices ???] +% labels = strvcat(labels); % convert to the searchable array +x = zeros(1, Nvrt); +y = zeros(1, Nvrt); +lst_node = 0; + % Find node's position coordinates if they are contained in 'filename'. +for line_ndx = unread % Look for node's coordiantes among the 'unread' lines. + line = dot_lines(line_ndx,:); + bra_pos = strfind(line, '['); % has to have "[" if it has the lable + pos_pos = strfind(line, 'pos'); % position of the "pos" + for node = 1:Nvrt % look through the list of labels + % THE NEXT STATEMENT we assume no label is substring of any other label + lbl_pos = strfind(line, labels{node}); + if (~isempty(lbl_pos) & ~isempty(bra_pos) & (x(node) == 0)) % make sure we have not seen it + if (lbl_pos(1) < bra_pos(1)) % label has to be to the left of braket + lst_node = node; + end + end + end + if (~isempty(pos_pos) & lst_node) % this line contains SOME position + [node_pos] = sscanf(line(pos_pos:length(line)), ' pos = "%d,%d"')'; + x(lst_node) = node_pos(1); + y(lst_node) = node_pos(2); + lst_node = 0; % not to assign position several times + end +end + +if (isempty(find(x)) & (nargout > 2)) % If coordinates were requested, but not found in 'filename'. + warning('File does not contain node coordinates.'); +end; +if ~(size(Adj,1)==size(Adj,2)) % Make sure Adj is a square matrix. ? + Adj = eye(max(size(Adj)),size(Adj,1))*Adj*eye(size(Adj,2),max(size(Adj))); +end; +x = .9*(x-min(x))/range(x)+.05; % normalise and push off margins +y = .9*(y-min(y))/range(y)+.05; + diff --git a/sourcecodes/bnt-master/GraphViz/Old/draw_dot.m b/sourcecodes/bnt-master/GraphViz/Old/draw_dot.m new file mode 100644 index 00000000..d6f37f81 --- /dev/null +++ b/sourcecodes/bnt-master/GraphViz/Old/draw_dot.m @@ -0,0 +1,26 @@ +function draw_dot(adj); +% +% draw_dot(name) +% +% Sample code illustrating use of dot_to_graph.m function +% Leon Peshkin +if ispc, shell = 'dos'; else, shell = 'unix'; end % Which OS ? + +cmdline = strcat(shell,'(''neato -V'')'); +status = eval(cmdline); +[status, result] = dos('neato -V'); % request version to check NEATO +if status == 1, fprintf('Complaining \n'); exit, end + +tmpDOTfile = '_GtDout.dot'; % to be platform independant no use of directories +tmpLAYOUT = '_LAYout.dot'; +directed = 0; % assume UN-directed graph +graph_to_dot(adj > 0, 'directed', directed, 'filename', tmpDOTfile); % save in file + +cmdline = strcat([shell '(''neato -Tdot ' tmpDOTfile ' -o ' tmpLAYOUT ''')']); % preserve trailing spaces +status = eval(cmdline); % get NEATO todo layout + +[adj, labels, x, y] = dot_to_graph(tmpLAYOUT); % load layout +delete(tmpLAYOUT); delete(tmpDOTfile); % clean up temporary files + +figure(1); clf; axis square % now plot +[x, y, h] = draw_graph(adj>0, labels, zeros(size(x,2),1), x, y); \ No newline at end of file diff --git a/sourcecodes/bnt-master/GraphViz/Old/draw_graph.m b/sourcecodes/bnt-master/GraphViz/Old/draw_graph.m new file mode 100644 index 00000000..06e3d7a1 --- /dev/null +++ b/sourcecodes/bnt-master/GraphViz/Old/draw_graph.m @@ -0,0 +1,310 @@ +function [x, y, h] = draw_graph(adj, labels, node_t, x, y) +% DRAW_LAYOUT Draws a layout for a graph +% +% [<X, Y>] = DRAW_LAYOUT(ADJ, <LABELS, ISBOX, X, Y>) +% +% Inputs : +% ADJ : Adjacency matrix (source, sink) +% LABELS : Cell array containing labels <Default : '1':'N'> +% ISBOX : 1 if node is a box, 0 if oval <Default : zeros> +% X, Y, : Coordinates of nodes on the unit square <Default : calls make_layout> +% +% Outputs : +% X, Y : Coordinates of nodes on the unit square +% H : Object handles +% +% Usage Example : [x, y] = draw_layout([0 1;0 0], {'Hidden','Visible'}, [1 0]'); +% +% h(i,1) is the text handle - color +% h(i,2) is the circle handle - facecolor +% +% Note : +% See also MAKE_LAYOUT + +% Uses : + +% Change History : +% Date Time Prog Note +% 13-Apr-2000 9:06 PM ATC Created under MATLAB 5.3.1.29215a (R11.1) + +% ATC = Ali Taylan Cemgil, +% SNN - University of Nijmegen, Department of Medical Physics and Biophysics +% e-mail : cemgil@mbfys.kun.nl +adj = double(adj); +N = size(adj,1); +if nargin<2, +% labels = cellstr(char(zeros(N,1)+double('+'))); + labels = cellstr(int2str((1:N)')); +end; + +if nargin<3, + node_t = zeros(N,1); +% node_t = rand(N,1) > 0.5; +else + node_t = node_t(:); +end; + +axis([0 1 0 1]); +set(gca,'XTick',[],'YTick',[],'box','on'); +% axis('square'); +%colormap(flipud(gray)); + +if nargin<4, + [x y] = make_layout(adj); +end; + +idx1 = find(node_t==0); wd1=[]; +if ~isempty(idx1), +[h1 wd1] = textoval(x(idx1), y(idx1), labels(idx1)); +end; + +idx2 = find(node_t~=0); wd2 = []; +if ~isempty(idx2), +[h2 wd2] = textbox(x(idx2), y(idx2), labels(idx2)); +end; + +wd = zeros(size(wd1,1)+size(wd2,1),2); +if ~isempty(idx1), wd(idx1, :) = wd1; end; +if ~isempty(idx2), wd(idx2, :) = wd2; end; + +for i=1:N, + j = find(adj(i,:)==1); + for k=j, + if x(k)-x(i)==0, + sign = 1; + if y(i)>y(k), alpha = -pi/2; else alpha = pi/2; end; + else + alpha = atan((y(k)-y(i))/(x(k)-x(i))); + if x(i)<x(k), sign = 1; else sign = -1; end; + end; + dy1 = sign.*wd(i,2).*sin(alpha); dx1 = sign.*wd(i,1).*cos(alpha); + dy2 = sign.*wd(k,2).*sin(alpha); dx2 = sign.*wd(k,1).*cos(alpha); + if adj(k,i)==0, % if directed edge + arrow([x(i)+dx1 y(i)+dy1],[x(k)-dx2 y(k)-dy2]); + else + line([x(i)+dx1 x(k)-dx2],[y(i)+dy1 y(k)-dy2],'color','k'); + adj(k,i)=-1; % Prevent drawing lines twice + end; + end; +end; + +if nargout>2, + h = zeros(length(wd),2); + if ~isempty(idx1), + h(idx1,:) = h1; + end; + if ~isempty(idx2), + h(idx2,:) = h2; + end; +end; + +%%%%% + +function [t, wd] = textoval(x, y, str) +% TEXTOVAL Draws an oval around text objects +% +% [T, WIDTH] = TEXTOVAL(X, Y, STR) +% [..] = TEXTOVAL(STR) % Interactive +% +% Inputs : +% X, Y : Coordinates +% TXT : Strings +% +% Outputs : +% T : Object Handles +% WIDTH : x and y Width of ovals +% +% Usage Example : [t] = textoval('Visit to Asia?'); +% +% +% Note : +% See also TEXTBOX + +% Uses : + +% Change History : +% Date Time Prog Note +% 15-Jun-1998 10:36 AM ATC Created under MATLAB 5.1.0.421 + +% ATC = Ali Taylan Cemgil, +% SNN - University of Nijmegen, Department of Medical Physics and Biophysics +% e-mail : cemgil@mbfys.kun.nl + +temp = []; + +switch nargin, + case 1, + str = x; + if ~isa(str,'cell') str=cellstr(str); end; + N = length(str); + wd = zeros(N,2); + for i=1:N, + [x, y] = ginput(1); + tx = text(x,y,str{i},'HorizontalAlignment','center','VerticalAlign','middle'); + [ptc wx wy] = draw_oval(tx, x, y); + wd(i,:) = [wx wy]; + delete(tx); + tx = text(x,y,str{i},'HorizontalAlignment','center','VerticalAlign','middle'); + temp = [temp ; tx ptc]; + end; + case 3, + if ~isa(str,'cell') str=cellstr(str); end; + N = length(str); + wd = zeros(N,2); + for i=1:N, + tx = text(x(i),y(i),str{i},'HorizontalAlignment','center','VerticalAlign','middle'); + [ptc wx wy] = draw_oval(tx, x(i), y(i)); + wd(i,:) = [wx wy]; + delete(tx); + tx = text(x(i),y(i),str{i},'HorizontalAlignment','center','VerticalAlign','middle'); + temp = [temp; tx ptc]; + end; + otherwise, +end; + +if nargout>0, t = temp; end; + +%%%%%%%%% + + +function [ptc, wx, wy] = draw_oval(tx, x, y) +% Draws an oval box around a tex object +sz = get(tx,'Extent'); +wy = sz(4); +wx = max(2/3*sz(3), wy); +wx = 0.5*wx; % KPM +wy = 0.5*wy; +ptc = ellipse(x, y, wx, wy); +set(ptc, 'FaceColor','w'); + + +%%%%%%%%%%%%% + +function [p] = ellipse(x, y, rx, ry, c) +% ELLIPSE Draws Ellipse shaped patch objects +% +% [<P>] = ELLIPSE(X, Y, Rx, Ry, C) +% +% Inputs : +% X : N x 1 vector of x coordinates +% Y : N x 1 vector of y coordinates +% Rx, Ry : Radii +% C : Color index +% +% +% Outputs : +% P = Handles of Ellipse shaped path objects +% +% Usage Example : [] = ellipse(); +% +% +% Note : +% See also + +% Uses : + +% Change History : +% Date Time Prog Note +% 27-May-1998 9:55 AM ATC Created under MATLAB 5.1.0.421 + +% ATC = Ali Taylan Cemgil, +% SNN - University of Nijmegen, Department of Medical Physics and Biophysics +% e-mail : cemgil@mbfys.kun.nl + +if (nargin < 2) error('Usage Example : e = ellipse([0 1],[0 -1],[1 0.5],[2 0.5]); '); end; +if (nargin < 3) rx = 0.1; end; +if (nargin < 4) ry = rx; end; +if (nargin < 5) c = 1; end; + +if length(c)==1, c = ones(size(x)).*c; end; +if length(rx)==1, rx = ones(size(x)).*rx; end; +if length(ry)==1, ry = ones(size(x)).*ry; end; + +n = length(x); +p = zeros(size(x)); +t = 0:pi/30:2*pi; +for i=1:n, + px = rx(i)*cos(t)+x(i); + py = ry(i)*sin(t)+y(i); + p(i) = patch(px,py,c(i)); +end; + +if nargout>0, pp = p; end; + +%%%%% + +function [t, wd] = textbox(x,y,str) +% TEXTBOX Draws A Box around the text +% +% [T, WIDTH] = TEXTBOX(X, Y, STR) +% [..] = TEXTBOX(STR) +% +% Inputs : +% X, Y : Coordinates +% TXT : Strings +% +% Outputs : +% T : Object Handles +% WIDTH : x and y Width of boxes +%% +% Usage Example : t = textbox({'Ali','Veli','49','50'}); +% +% +% Note : +% See also TEXTOVAL + +% Uses : + +% Change History : +% Date Time Prog Note +% 09-Jun-1998 11:43 AM ATC Created under MATLAB 5.1.0.421 + +% ATC = Ali Taylan Cemgil, +% SNN - University of Nijmegen, Department of Medical Physics and Biophysics +% e-mail : cemgil@mbfys.kun.nl + +% See +temp = []; + +switch nargin, + case 1, + str = x; + if ~isa(str,'cell') str=cellstr(str); end; + N = length(str); + wd = zeros(N,2); + for i=1:N, + [x, y] = ginput(1); + tx = text(x,y,str{i},'HorizontalAlignment','center','VerticalAlign','middle'); + [ptc wx wy] = draw_box(tx, x, y); + wd(i,:) = [wx wy]; + delete(tx); + tx = text(x,y,str{i},'HorizontalAlignment','center','VerticalAlign','middle'); + temp = [temp; tx ptc]; + end; + case 3, + if ~isa(str,'cell') str=cellstr(str); end; + N = length(str); + for i=1:N, + tx = text(x(i),y(i),str{i},'HorizontalAlignment','center','VerticalAlign','middle'); + [ptc wx wy] = draw_box(tx, x(i), y(i)); + wd(i,:) = [wx wy]; + delete(tx); + tx = text(x(i),y(i),str{i},'HorizontalAlignment','center','VerticalAlign','middle'); + temp = [temp; tx ptc]; + end; + + otherwise, + +end; + +if nargout>0, t = temp; end; + + +function [ptc, wx, wy] = draw_box(tx, x, y) +% Draws a box around a tex object + sz = get(tx,'Extent'); + wy = 2/3*sz(4); + wx = max(2/3*sz(3), wy); + ptc = patch([x-wx x+wx x+wx x-wx], [y+wy y+wy y-wy y-wy],'w'); + set(ptc, 'FaceColor','w'); + diff --git a/sourcecodes/bnt-master/GraphViz/Old/graphToDot.m b/sourcecodes/bnt-master/GraphViz/Old/graphToDot.m new file mode 100644 index 00000000..1f3d232e --- /dev/null +++ b/sourcecodes/bnt-master/GraphViz/Old/graphToDot.m @@ -0,0 +1,84 @@ +function graphToDot(adj, varargin) +% GRAPHTODOT Makes a GraphViz (AT&T) ile representing an adjacency matrix +% function graphToDot(adj, ...) +% Optional arguments should be passed as name/value pairs [default] +% +% 'filename' - if omitted, writes to 'tmp.dot' +% 'arc_label' - arc_label{i,j} is a string attached to the i-j arc [""] +% 'node_label' - node_label{i} is a string attached to the node i ["i"] +% 'width' - width in inches [10] +% 'height' - height in inches [10] +% 'leftright' - 1 means layout left-to-right, 0 means top-to-bottom [0] +% 'directed' - 1 means use directed arcs, 0 means undirected [1] +% +% For details on graphviz, See http://www.research.att.com/sw/tools/graphviz +% +% See also dot_to_graph and draw_dot +% +% First version written by Kevin Murphy 2002. +% Modified by Leon Peshkin, Jan 2004. + +node_label = []; arc_label = []; % set default args +width = 10; height = 10; +leftright = 0; directed = 1; filename = 'tmp.dot'; + +for i = 1:2:nargin-1 % get optional args + switch varargin{i} + case 'filename', filename = varargin{i+1}; + case 'node_label', node_label = varargin{i+1}; + case 'arc_label', arc_label = varargin{i+1}; + case 'width', width = varargin{i+1}; + case 'height', height = varargin{i+1}; + case 'leftright', leftright = varargin{i+1}; + case 'directed', directed = varargin{i+1}; + end +end + +fid = fopen(filename, 'w'); +if directed + fprintf(fid, 'digraph G {\n'); + arctxt = '->'; + if isempty(arc_label) + labeltxt = ''; + else + labeltxt = '[label="%s"]'; + end +else + fprintf(fid, 'graph G {\n'); + arctxt = '--'; + if isempty(arc_label) + labeltxt = '[dir=none]'; + else + labeltext = '[label="%s",dir=none]'; + end +end +edgeformat = strcat(['%d ',arctxt,' %d ',labeltxt,';\n']); +fprintf(fid, 'center = 1;\n'); +fprintf(fid, 'size=\"%d,%d\";\n', width, height); +if leftright + fprintf(fid, 'rankdir=LR;\n'); +end +Nnds = length(adj); +for node = 1:Nnds % process nodes + if isempty(node_label) + fprintf(fid, '%d;\n', node); + else + fprintf(fid, '%d [ label = "%s" ];\n', node, +node_label{node}); + end +end +for node1 = 1:Nnds % process edges + if directed + arcs = find(adj(node1,:)); % children(adj, node); + else + arcs = find(adj(node1,node1+1:Nnds)); % remove duplicate arcs + end + for node2 = arcs + fprintf(fid, edgeformat, node1, node2); + end +end +fprintf(fid, '}'); +fclose(fid); + + + diff --git a/sourcecodes/bnt-master/GraphViz/Old/pre_pesha_graph_to_dot.m b/sourcecodes/bnt-master/GraphViz/Old/pre_pesha_graph_to_dot.m new file mode 100644 index 00000000..49f226f6 --- /dev/null +++ b/sourcecodes/bnt-master/GraphViz/Old/pre_pesha_graph_to_dot.m @@ -0,0 +1,166 @@ +function graph_to_dot(G, varargin) +% DAG_TO_DOT Make a file representing the directed graph in dotty format. +% dag_to_dot(G, ...) +% +% Optional arguments should be passed as name/value pairs [default] +% +% 'filename' - if omitted, we write to 'tmp.dot', convert this to 'tmp.ps', +% and then call ghostview automatically +% 'arc_label' - arc_label{i,j} is a string attached to the i->j arc. [""] +% 'node_label' - node_label{i} is a string attached to node i. ["i"] +% 'width' - width in inches [10] +% 'height' - height in inches [10] +% 'leftright' - 1 means layout left-to-right, 0 means top-to-bottom [0] +% 'directed' - 1 means use directed arcs, 0 means undirected [1] +% +% For details on dotty, See http://www.research.att.com/sw/tools/graphviz +% +% Example: +% G = rand(5,5); +% names = cell(5,5); +% names{1,2} = 'arc 1-2'; +% graph_to_dot(G, 'arc_label', names) +% or graph_to_dot(G, 'arc_label', 'numbers') % prints value of G(i,j) on i->j arc + +% Kevin Murphy, 1998 + +% set default args +filename = []; +node_label = []; +arc_label = []; +width = 10; +height = 10; +leftright = 0; +directed = 1; +% get optional args +args = varargin; +for i=1:2:length(args) + switch args{i} + case 'filename', filename = args{i+1}; + case 'node_label', node_label = args{i+1}; + case 'arc_label', arc_label = args{i+1}; + case 'width', width = args{i+1}; + case 'height', height = args{i+1}; + case 'leftright', leftright = args{i+1}; + case 'directed', directed = args{i+1}; + end +end + +if isstr(arc_label) & strcmp(arc_label, 'numbers') + N = length(G); + arc_label = cell(N,N); + for i=1:N + for j=1:N + arc_label{i,j} = sprintf('%4.2f', G(i,j)); + end + end +end + +if isempty(filename) + make_file(G, 'tmp.dot', node_label, arc_label, width, height, leftright, directed); + if isunix + !dot -Tps tmp.dot -o tmp.ps + + !gs tmp.ps & + else + dos('dot -Tps tmp.dot -o tmp.ps'); + dos('gsview32 tmp.ps &'); + end +else + + + make_file(G, filename, node_label, arc_label, width, height, leftright, directed); +end + + +%%%%%% + +function make_file(G, filename, node_label, arc_label, width, height, leftright, directed) + +n = length(G); +fid = fopen(filename, 'w'); +if directed + fprintf(fid, 'digraph G {\n'); +else + fprintf(fid, 'graph G {\n'); +end +fprintf(fid, 'center = 1;\n'); +fprintf(fid, 'size=\"%d,%d\";\n', width, height); +if leftright + fprintf(fid, 'rankdir=LR;\n'); +end +for i=1:n + if isempty(node_label) + fprintf(fid, '%d;\n', i); + else + fprintf(fid, '%d [ label = "%s" ];\n', i, node_label{i}); + end +end +if directed + for i=1:n + cs = children(G,i); + for j=1:length(cs) + c = cs(j); + if isempty(arc_label) + fprintf(fid, '%d -> %d;\n', i, c); + else + fprintf(fid, '%d -> %d [label="%s"];\n', i, c, arc_label{i,c}); + end + end + end +else + for i=1:n + ns = intersect(neighbors(G,i), i+1:n); % remove duplicate arcs + for j=1:length(ns) + c = ns(j); + if isempty(arc_label) + fprintf(fid, '%d -- %d [dir=none];\n', i, c); + else + fprintf(fid, '%d -- %d [label="%s",dir=none];\n', i, c, arc_label{i,c}); + end + end + end +end +fprintf(fid, '\n}'); +fclose(fid); + + + +%%%%%%%%%%%%%%% + +function cs = children(adj_mat, i, t) +% CHILDREN Return the indices of a node's children in sorted order +% c = children(adj_mat, i, t) +% +% t is an optional argument: if present, dag is assumed to be a 2-slice DBN + +if nargin < 3 + cs = find(adj_mat(i,:)); +else + if t==1 + cs = find(adj_mat(i,:)); + else + ss = length(adj_mat)/2; + j = i+ss; + cs = find(adj_mat(j,:)) + (t-2)*ss; + end +end + +%%%%%%%%%%%% + +function ps = parents(adj_mat, i) +% PARENTS Return the list of parents of node i +% ps = parents(adj_mat, i) + +ps = find(adj_mat(:,i))'; + +%%%%%%%%%%%%% + +function ns = neighbors(adj_mat, i) +% NEIGHBORS Find the parents and children of a node in a graph. +% ns = neighbors(adj_mat, i) + +ns = union(children(adj_mat, i), parents(adj_mat, i)); + + + diff --git a/sourcecodes/bnt-master/GraphViz/README.txt b/sourcecodes/bnt-master/GraphViz/README.txt new file mode 100644 index 00000000..4ae15fac --- /dev/null +++ b/sourcecodes/bnt-master/GraphViz/README.txt @@ -0,0 +1,16 @@ +Graph visualization (automatic layout) functions +------------------------------------------------ + +This directory contains code to automatically layout and visualize +graphs. It provides a matlab interface to the graphviz program: + http://www.research.att.com/sw/tools/graphviz +Written by Kevin Murphy, Leon Peshkin, Tom Minka. + +draw_graph was written by Ali Taylan Cemgil, and is entirely +self-contained matlab: it does not need graphviz, but produces lower +quality results. +http://www.mbfys.kun.nl/~cemgil/matlab/layout.html + +See also the following URLs for other graph layout programs: + http://www.ics.uci.edu/~eppstein/gina/gdraw.html + http://www.cwi.nl/InfoVisu/ diff --git a/sourcecodes/bnt-master/GraphViz/approxeq.m b/sourcecodes/bnt-master/GraphViz/approxeq.m new file mode 100644 index 00000000..559efc5e --- /dev/null +++ b/sourcecodes/bnt-master/GraphViz/approxeq.m @@ -0,0 +1,21 @@ +function p = approxeq(a, b, tol, rel) +% APPROXEQ Are a and b approximately equal (to within a specified tolerance)? +% p = approxeq(a, b, thresh) +% 'tol' defaults to 1e-3. +% p(i) = 1 iff abs(a(i) - b(i)) < thresh +% +% p = approxeq(a, b, thresh, 1) +% p(i) = 1 iff abs(a(i)-b(i))/abs(a(i)) < thresh + +if nargin < 3, tol = 1e-2; end +if nargin < 4, rel = 0; end + +a = a(:); +b = b(:); +d = abs(a-b); +if rel + p = ~any( (d ./ (abs(a)+eps)) > tol); +else + p = ~any(d > tol); +end + diff --git a/sourcecodes/bnt-master/GraphViz/arrow.m b/sourcecodes/bnt-master/GraphViz/arrow.m new file mode 100644 index 00000000..4c5c1852 --- /dev/null +++ b/sourcecodes/bnt-master/GraphViz/arrow.m @@ -0,0 +1,1460 @@ +function [h,yy,zz] = arrow(varargin) +% ARROW Draw a line with an arrowhead. +% +% ARROW(Start,Stop) draws a line with an arrow from Start to Stop (points +% should be vectors of length 2 or 3, or matrices with 2 or 3 +% columns), and returns the graphics handle of the arrow(s). +% +% ARROW uses the mouse (click-drag) to create an arrow. +% +% ARROW DEMO & ARROW DEMO2 show 3-D & 2-D demos of the capabilities of ARROW. +% +% ARROW may be called with a normal argument list or a property-based list. +% ARROW(Start,Stop,Length,BaseAngle,TipAngle,Width,Page,CrossDir) is +% the full normal argument list, where all but the Start and Stop +% points are optional. If you need to specify a later argument (e.g., +% Page) but want default values of earlier ones (e.g., TipAngle), +% pass an empty matrix for the earlier ones (e.g., TipAngle=[]). +% +% ARROW('Property1',PropVal1,'Property2',PropVal2,...) creates arrows with the +% given properties, using default values for any unspecified or given as +% 'default' or NaN. Some properties used for line and patch objects are +% used in a modified fashion, others are passed directly to LINE, PATCH, +% or SET. For a detailed properties explanation, call ARROW PROPERTIES. +% +% Start The starting points. B +% Stop The end points. /|\ ^ +% Length Length of the arrowhead in pixels. /|||\ | +% BaseAngle Base angle in degrees (ADE). //|||\\ L| +% TipAngle Tip angle in degrees (ABC). ///|||\\\ e| +% Width Width of the base in pixels. ////|||\\\\ n| +% Page Use hardcopy proportions. /////|D|\\\\\ g| +% CrossDir Vector || to arrowhead plane. //// ||| \\\\ t| +% NormalDir Vector out of arrowhead plane. /// ||| \\\ h| +% Ends Which end has an arrowhead. //<----->|| \\ | +% ObjectHandles Vector of handles to update. / base ||| \ V +% E angle||<-------->C +% ARROW(H,'Prop1',PropVal1,...), where H is a |||tipangle +% vector of handles to previously-created arrows ||| +% and/or line objects, will update the previously- ||| +% created arrows according to the current view -->|A|<-- width +% and any specified properties, and will convert +% two-point line objects to corresponding arrows. ARROW(H) will update +% the arrows if the current view has changed. Root, figure, or axes +% handles included in H are replaced by all descendant Arrow objects. +% +% A property list can follow any specified normal argument list, e.g., +% ARROW([1 2 3],[0 0 0],36,'BaseAngle',60) creates an arrow from (1,2,3) to +% the origin, with an arrowhead of length 36 pixels and 60-degree base angle. +% +% Normally, an ARROW is a PATCH object, so any valid PATCH property/value pairs +% can be passed, e.g., ARROW(Start,Stop,'EdgeColor','r','FaceColor','g'). +% ARROW will use LINE objects when requested by ARROW(...,'Type','line') or, +% using LINE property/value pairs, ARROW(Start,Stop,'Type','line','Color','b'). +% +% The basic arguments or properties can generally be vectorized to create +% multiple arrows with the same call. This is done by passing a property +% with one row per arrow, or, if all arrows are to have the same property +% value, just one row may be specified. +% +% You may want to execute AXIS(AXIS) before calling ARROW so it doesn't change +% the axes on you; ARROW determines the sizes of arrow components BEFORE the +% arrow is plotted, so if ARROW changes axis limits, arrows may be malformed. +% +% This version of ARROW uses features of MATLAB 6.x and is incompatible with +% earlier MATLAB versions (ARROW for MATLAB 4.2c is available separately); +% some problems with perspective plots still exist. + +% Copyright (c)1995-2016, Dr. Erik A. Johnson <JohnsonE@usc.edu>, 5/25/2016 +% http://www.usc.edu/civil_eng/johnsone/ + +% Revision history: +% 5/25/16 EAJ Add documentation of 'Type','line' +% Add documentation of how to set color +% Add 'Color' property (which sets both 'EdgeColor' and 'FaceColor' for patch objects) +% 5/24/16 EAJ Remove 'EraseMode' in HG2 +% 7/16/14 EAJ R2014b HandleGraphics2 compatibility +% 7/14/14 EAJ 5/20/13 patch extension didn't work right in HG2 +% so break the arrow along its length instead +% 5/20/13 EAJ Extend patch line one more segment so EPS/PDF printed versions +% have nice rounded tips when the LineWidth is wider +% 2/06/13 EAJ Add ShortenLength property to shorten length if arrow is short +% 1/24/13 EAJ Remove some old comments. +% 5/20/09 EAJ Fix view direction in (3D) demo. +% 6/26/08 EAJ Replace eval('trycmd','catchcmd') with try, trycmd; catch, +% catchcmd; end; -- break's MATLAB 5 compatibility. +% 8/26/03 EAJ Eliminate OpenGL attempted fix since it didn't fix anyway. +% 11/15/02 EAJ Accomodate how MATLAB 6.5 handles NaN and logicals +% 7/28/02 EAJ Tried (but failed) work-around for MATLAB 6.x / OpenGL bug +% if zero 'Width' or not double-ended +% 11/10/99 EAJ Add logical() to eliminate zero index problem in MATLAB 5.3. +% 11/10/99 EAJ Corrected warning if axis limits changed on multiple axes. +% 11/10/99 EAJ Update e-mail address. +% 2/10/99 EAJ Some documentation updating. +% 2/24/98 EAJ Fixed bug if Start~=Stop but both colinear with viewpoint. +% 8/14/97 EAJ Added workaround for MATLAB 5.1 scalar logical transpose bug. +% 7/21/97 EAJ Fixed a few misc bugs. +% 7/14/97 EAJ Make arrow([],'Prop',...) do nothing (no old handles) +% 6/23/97 EAJ MATLAB 5 compatible version, release. +% 5/27/97 EAJ Added Line Arrows back in. Corrected a few bugs. +% 5/26/97 EAJ Changed missing Start/Stop to mouse-selected arrows. +% 5/19/97 EAJ MATLAB 5 compatible version, beta. +% 4/13/97 EAJ MATLAB 5 compatible version, alpha. +% 1/31/97 EAJ Fixed bug with multiple arrows and unspecified Z coords. +% 12/05/96 EAJ Fixed one more bug with log plots and NormalDir specified +% 10/24/96 EAJ Fixed bug with log plots and NormalDir specified +% 11/13/95 EAJ Corrected handling for 'reverse' axis directions +% 10/06/95 EAJ Corrected occasional conflict with SUBPLOT +% 4/24/95 EAJ A major rewrite. +% Fall 94 EAJ Original code. + +% Things to be done: +% - in the arrow_clicks section, prompt by printing to the screen so that +% the user knows what's going on; also make sure the figure is brought +% to the front. +% - segment parsing, computing, and plotting into separate subfunctions +% - change computing from Xform to Camera paradigms +% + this will help especially with 3-D perspective plots +% + if the WarpToFill section works right, remove warning code +% + when perpsective works properly, remove perspective warning code +% - add cell property values and struct property name/values (like get/set) +% - get rid of NaN as the "default" data label +% + perhaps change userdata to a struct and don't include (or leave +% empty) the values specified as default; or use a cell containing +% an empty matrix for a default value +% - add functionality of GET to retrieve current values of ARROW properties +% +% New list of things to be done: +% - rewrite as a graphics or class object that updates itself in real time +% (but have a 'Static' or 'DoNotUpdate' property to avoid updating) + +% Permission is granted to distribute ARROW with the toolboxes for the book +% "Solving Solid Mechanics Problems with MATLAB 5", by F. Golnaraghi et al. +% (Prentice Hall, 1999). + +% Permission is granted to Dr. Josef Bigun to distribute ARROW with his +% software to reproduce the figures in his image analysis text. + +% global variable initialization +persistent ARROW_PERSP_WARN ARROW_STRETCH_WARN ARROW_AXLIMITS ARROW_AX +if isempty(ARROW_PERSP_WARN ), ARROW_PERSP_WARN =1; end; +if isempty(ARROW_STRETCH_WARN), ARROW_STRETCH_WARN=1; end; + +% Handle callbacks +if (nargin>0 & isstr(varargin{1}) & strcmp(lower(varargin{1}),'callback')), + arrow_callback(varargin{2:end}); return; +end; + +% Are we doing the demo? +c = sprintf('\n'); +if (nargin==1 & isstr(varargin{1})), + arg1 = lower(varargin{1}); + if strncmp(arg1,'prop',4), arrow_props; + elseif strncmp(arg1,'demo',4) + clf reset + demo_info = arrow_demo; + if ~strncmp(arg1,'demo2',5), + hh=arrow_demo3(demo_info); + else, + hh=arrow_demo2(demo_info); + end; + if (nargout>=1), h=hh; end; + elseif strncmp(arg1,'fixlimits',3), + arrow_fixlimits(ARROW_AX,ARROW_AXLIMITS); + ARROW_AXLIMITS=[]; ARROW_AX=[]; + elseif strncmp(arg1,'help',4), + disp(help(mfilename)); + else, + error([upper(mfilename) ' got an unknown single-argument string ''' deblank(arg1) '''.']); + end; + return; +end; + +% Check # of arguments +if (nargout>3), error([upper(mfilename) ' produces at most 3 output arguments.']); end; + +% find first property number +firstprop = nargin+1; +for k=1:length(varargin), if ~isnumeric(varargin{k}) && ~all(ishandle(varargin{k})), firstprop=k; break; end; end; %eaj 5/24/16 for k=1:length(varargin), if ~isnumeric(varargin{k}), firstprop=k; break; end; end; +lastnumeric = firstprop-1; + +% check property list +if (firstprop<=nargin), + for k=firstprop:2:nargin, + curarg = varargin{k}; + if ~isstr(curarg) | sum(size(curarg)>1)>1, + error([upper(mfilename) ' requires that a property name be a single string.']); + end; + end; + if (rem(nargin-firstprop,2)~=1), + error([upper(mfilename) ' requires that the property ''' ... + varargin{nargin} ''' be paired with a property value.']); + end; +end; + +% default output +if (nargout>0), h=[]; end; +if (nargout>1), yy=[]; end; +if (nargout>2), zz=[]; end; + +% set values to empty matrices +start = []; +stop = []; +len = []; +baseangle = []; +tipangle = []; +wid = []; +page = []; +crossdir = []; +ends = []; +shorten = []; +ax = []; +oldh = []; +ispatch = []; +defstart = [NaN NaN NaN]; +defstop = [NaN NaN NaN]; +deflen = 16; +defbaseangle = 90; +deftipangle = 16; +defwid = 0; +defpage = 0; +defcrossdir = [NaN NaN NaN]; +defends = 1; +defshorten = 0; +defoldh = []; +defispatch = 1; + +% The 'Tag' we'll put on our arrows +ArrowTag = 'Arrow'; + +% check for oldstyle arguments +if (firstprop==2), + % assume arg1 is a set of handles + oldh = varargin{1}(:); + if isempty(oldh), return; end; +elseif (firstprop>9), + error([upper(mfilename) ' takes at most 8 non-property arguments.']); +elseif (firstprop>2), + {start,stop,len,baseangle,tipangle,wid,page,crossdir}; + args = [varargin(1:firstprop-1) cell(1,length(ans)-(firstprop-1))]; + [start,stop,len,baseangle,tipangle,wid,page,crossdir] = deal(args{:}); +end; + +% parse property pairs +extraprops={}; +for k=firstprop:2:nargin, + prop = varargin{k}; + val = varargin{k+1}; + prop = [lower(prop(:)') ' ']; + if strncmp(prop,'start' ,5), start = val; + elseif strncmp(prop,'stop' ,4), stop = val; + elseif strncmp(prop,'len' ,3), len = val(:); + elseif strncmp(prop,'base' ,4), baseangle = val(:); + elseif strncmp(prop,'tip' ,3), tipangle = val(:); + elseif strncmp(prop,'wid' ,3), wid = val(:); + elseif strncmp(prop,'page' ,4), page = val; + elseif strncmp(prop,'cross' ,5), crossdir = val; + elseif strncmp(prop,'norm' ,4), if (isstr(val)), crossdir=val; else, crossdir=val*sqrt(-1); end; + elseif strncmp(prop,'end' ,3), ends = val; + elseif strncmp(prop,'shorten',5), shorten = val; + elseif strncmp(prop,'object' ,6), oldh = val(:); + elseif strncmp(prop,'handle' ,6), oldh = val(:); + elseif strncmp(prop,'type' ,4), ispatch = val; + elseif strncmp(prop,'userd' ,5), %ignore it + else, + % make sure it is a valid patch or line property + try + get(0,['DefaultPatch' varargin{k}]); + catch + errstr = lasterr; + try + get(0,['DefaultLine' varargin{k}]); + catch + errstr(1:max(find(errstr==char(13)|errstr==char(10)))) = ''; + error([upper(mfilename) ' got ' errstr]); + end + end; + extraprops={extraprops{:},varargin{k},val}; + end; +end; + +% Check if we got 'default' values +start = arrow_defcheck(start ,defstart ,'Start' ); +stop = arrow_defcheck(stop ,defstop ,'Stop' ); +len = arrow_defcheck(len ,deflen ,'Length' ); +baseangle = arrow_defcheck(baseangle,defbaseangle,'BaseAngle' ); +tipangle = arrow_defcheck(tipangle ,deftipangle ,'TipAngle' ); +wid = arrow_defcheck(wid ,defwid ,'Width' ); +crossdir = arrow_defcheck(crossdir ,defcrossdir ,'CrossDir' ); +page = arrow_defcheck(page ,defpage ,'Page' ); +ends = arrow_defcheck(ends ,defends ,'' ); +shorten = arrow_defcheck(shorten ,defshorten ,'' ); +oldh = arrow_defcheck(oldh ,[] ,'ObjectHandles'); +ispatch = arrow_defcheck(ispatch ,defispatch ,'' ); + +% check transpose on arguments +[m,n]=size(start ); if any(m==[2 3])&(n==1|n>3), start = start'; end; +[m,n]=size(stop ); if any(m==[2 3])&(n==1|n>3), stop = stop'; end; +[m,n]=size(crossdir); if any(m==[2 3])&(n==1|n>3), crossdir = crossdir'; end; + +% convert strings to numbers +if ~isempty(ends) & isstr(ends), + endsorig = ends; + [m,n] = size(ends); + col = lower([ends(:,1:min(3,n)) ones(m,max(0,3-n))*' ']); + ends = NaN*ones(m,1); + oo = ones(1,m); + ii=find(all(col'==['non']'*oo)'); if ~isempty(ii), ends(ii)=ones(length(ii),1)*0; end; + ii=find(all(col'==['sto']'*oo)'); if ~isempty(ii), ends(ii)=ones(length(ii),1)*1; end; + ii=find(all(col'==['sta']'*oo)'); if ~isempty(ii), ends(ii)=ones(length(ii),1)*2; end; + ii=find(all(col'==['bot']'*oo)'); if ~isempty(ii), ends(ii)=ones(length(ii),1)*3; end; + if any(isnan(ends)), + ii = min(find(isnan(ends))); + error([upper(mfilename) ' does not recognize ''' deblank(endsorig(ii,:)) ''' as a valid ''Ends'' value.']); + end; +else, + ends = ends(:); +end; +if ~isempty(ispatch) & isstr(ispatch), + col = lower(ispatch(:,1)); + patchchar='p'; linechar='l'; defchar=' '; + mask = col~=patchchar & col~=linechar & col~=defchar; + if any(mask), + error([upper(mfilename) ' does not recognize ''' deblank(ispatch(min(find(mask)),:)) ''' as a valid ''Type'' value.']); + end; + ispatch = (col==patchchar)*1 + (col==linechar)*0 + (col==defchar)*defispatch; +else, + ispatch = ispatch(:); +end; +oldh = oldh(:); + +% check object handles +if ~all(ishandle(oldh)), error([upper(mfilename) ' got invalid object handles.']); end; + +% expand root, figure, and axes handles +if ~isempty(oldh), + ohtype = get(oldh,'Type'); + mask = strcmp(ohtype,'root') | strcmp(ohtype,'figure') | strcmp(ohtype,'axes'); + if any(mask), + oldh = num2cell(oldh); + for ii=find(mask)', + oldh(ii) = {findobj(oldh{ii},'Tag',ArrowTag)}; + end; + oldh = cat(1,oldh{:}); + if isempty(oldh), return; end; % no arrows to modify, so just leave + end; +end; + +% largest argument length +[mstart,junk]=size(start); [mstop,junk]=size(stop); [mcrossdir,junk]=size(crossdir); +argsizes = [length(oldh) mstart mstop ... + length(len) length(baseangle) length(tipangle) ... + length(wid) length(page) mcrossdir length(ends) length(shorten)]; +args=['length(ObjectHandle) '; ... + '#rows(Start) '; ... + '#rows(Stop) '; ... + 'length(Length) '; ... + 'length(BaseAngle) '; ... + 'length(TipAngle) '; ... + 'length(Width) '; ... + 'length(Page) '; ... + '#rows(CrossDir) '; ... + '#rows(Ends) '; ... + 'length(ShortenLength) ']; +if (any(imag(crossdir(:))~=0)), + args(9,:) = '#rows(NormalDir) '; +end; +if isempty(oldh), + narrows = max(argsizes); +else, + narrows = length(oldh); +end; +if (narrows<=0), narrows=1; end; + +% Check size of arguments +ii = find((argsizes~=0)&(argsizes~=1)&(argsizes~=narrows)); +if ~isempty(ii), + s = args(ii',:); + while ((size(s,2)>1)&((abs(s(:,size(s,2)))==0)|(abs(s(:,size(s,2)))==abs(' ')))), + s = s(:,1:size(s,2)-1); + end; + s = [ones(length(ii),1)*[upper(mfilename) ' requires that '] s ... + ones(length(ii),1)*[' equal the # of arrows (' num2str(narrows) ').' c]]; + s = s'; + s = s(:)'; + s = s(1:length(s)-1); + error(setstr(s)); +end; + +% check element length in Start, Stop, and CrossDir +if ~isempty(start), + [m,n] = size(start); + if (n==2), + start = [start NaN*ones(m,1)]; + elseif (n~=3), + error([upper(mfilename) ' requires 2- or 3-element Start points.']); + end; +end; +if ~isempty(stop), + [m,n] = size(stop); + if (n==2), + stop = [stop NaN*ones(m,1)]; + elseif (n~=3), + error([upper(mfilename) ' requires 2- or 3-element Stop points.']); + end; +end; +if ~isempty(crossdir), + [m,n] = size(crossdir); + if (n<3), + crossdir = [crossdir NaN*ones(m,3-n)]; + elseif (n~=3), + if (all(imag(crossdir(:))==0)), + error([upper(mfilename) ' requires 2- or 3-element CrossDir vectors.']); + else, + error([upper(mfilename) ' requires 2- or 3-element NormalDir vectors.']); + end; + end; +end; + +% fill empty arguments +if isempty(start ), start = [Inf Inf Inf]; end; +if isempty(stop ), stop = [Inf Inf Inf]; end; +if isempty(len ), len = Inf; end; +if isempty(baseangle ), baseangle = Inf; end; +if isempty(tipangle ), tipangle = Inf; end; +if isempty(wid ), wid = Inf; end; +if isempty(page ), page = Inf; end; +if isempty(crossdir ), crossdir = [Inf Inf Inf]; end; +if isempty(ends ), ends = Inf; end; +if isempty(shorten ), shorten = Inf; end; +if isempty(ispatch ), ispatch = Inf; end; + +% expand single-column arguments +o = ones(narrows,1); +if (size(start ,1)==1), start = o * start ; end; +if (size(stop ,1)==1), stop = o * stop ; end; +if (length(len )==1), len = o * len ; end; +if (length(baseangle )==1), baseangle = o * baseangle ; end; +if (length(tipangle )==1), tipangle = o * tipangle ; end; +if (length(wid )==1), wid = o * wid ; end; +if (length(page )==1), page = o * page ; end; +if (size(crossdir ,1)==1), crossdir = o * crossdir ; end; +if (length(ends )==1), ends = o * ends ; end; +if (length(shorten )==1), shorten = o * shorten ; end; +if (length(ispatch )==1), ispatch = o * ispatch ; end; +ax = repmat(gca,narrows,1); %eaj 7/16/14 ax=gca; if ~isnumeric(ax), ax=double(ax); end; ax=o*ax; + +% if we've got handles, get the defaults from the handles +if ~isempty(oldh), + for k=1:narrows, + oh = oldh(k); + ud = get(oh,'UserData'); + ax(k) = get(oh,'Parent'); %eaj 7/16/14 get(oh,'Parent'); if ~isnumeric(ans), double(ans); end; ax(k)=ans; + ohtype = get(oh,'Type'); + if strcmp(get(oh,'Tag'),ArrowTag), % if it's an arrow already + if isinf(ispatch(k)), ispatch(k)=strcmp(ohtype,'patch'); end; + % arrow UserData format: [start' stop' len base tip wid page crossdir' ends shorten] + start0 = ud(1:3); + stop0 = ud(4:6); + if (isinf(len(k))), len(k) = ud( 7); end; + if (isinf(baseangle(k))), baseangle(k) = ud( 8); end; + if (isinf(tipangle(k))), tipangle(k) = ud( 9); end; + if (isinf(wid(k))), wid(k) = ud(10); end; + if (isinf(page(k))), page(k) = ud(11); end; + if (isinf(crossdir(k,1))), crossdir(k,1) = ud(12); end; + if (isinf(crossdir(k,2))), crossdir(k,2) = ud(13); end; + if (isinf(crossdir(k,3))), crossdir(k,3) = ud(14); end; + if (isinf(ends(k))), ends(k) = ud(15); end; + if (isinf(shorten(k))), shorten(k) = ud(16); end; + elseif strcmp(ohtype,'line')|strcmp(ohtype,'patch'), % it's a non-arrow line or patch + convLineToPatch = 1; %set to make arrow patches when converting from lines. + if isinf(ispatch(k)), ispatch(k)=convLineToPatch|strcmp(ohtype,'patch'); end; + x=get(oh,'XData'); x=x(~isnan(x(:))); if isempty(x), x=NaN; end; + y=get(oh,'YData'); y=y(~isnan(y(:))); if isempty(y), y=NaN; end; + z=get(oh,'ZData'); z=z(~isnan(z(:))); if isempty(z), z=NaN; end; + start0 = [x(1) y(1) z(1) ]; + stop0 = [x(end) y(end) z(end)]; + else, + error([upper(mfilename) ' cannot convert ' ohtype ' objects.']); + end; + ii=find(isinf(start(k,:))); if ~isempty(ii), start(k,ii)=start0(ii); end; + ii=find(isinf(stop( k,:))); if ~isempty(ii), stop( k,ii)=stop0( ii); end; + end; +end; + +% convert Inf's to NaN's +start( isinf(start )) = NaN; +stop( isinf(stop )) = NaN; +len( isinf(len )) = NaN; +baseangle( isinf(baseangle)) = NaN; +tipangle( isinf(tipangle )) = NaN; +wid( isinf(wid )) = NaN; +page( isinf(page )) = NaN; +crossdir( isinf(crossdir )) = NaN; +ends( isinf(ends )) = NaN; +shorten( isinf(shorten )) = NaN; +ispatch( isinf(ispatch )) = NaN; + +% set up the UserData data (here so not corrupted by log10's and such) +ud = [start stop len baseangle tipangle wid page crossdir ends shorten]; + +% Set Page defaults +page = ~isnan(page) & trueornan(page); + +% Get axes limits, range, min; correct for aspect ratio and log scale +axm = zeros(3,narrows); +axr = zeros(3,narrows); +axrev = zeros(3,narrows); +ap = zeros(2,narrows); +xyzlog = zeros(3,narrows); +limmin = zeros(2,narrows); +limrange = zeros(2,narrows); +oldaxlims = zeros(6,narrows); +oneax = all(ax==ax(1)); +if (oneax), + T = zeros(4,4); + invT = zeros(4,4); +else, + T = zeros(16,narrows); + invT = zeros(16,narrows); +end; +axnotdone = true(size(ax)); +while (any(axnotdone)), + ii = find(axnotdone,1); + curax = ax(ii); + curpage = page(ii); + % get axes limits and aspect ratio + axl = [get(curax,'XLim'); get(curax,'YLim'); get(curax,'ZLim')]; + ax==curax; oldaxlims(:,ans)=repmat(reshape(axl',[],1),1,sum(ans)); + % get axes size in pixels (points) + u = get(curax,'Units'); + axposoldunits = get(curax,'Position'); + really_curpage = curpage & strcmp(u,'normalized'); + if (really_curpage), + curfig = get(curax,'Parent'); + pu = get(curfig,'PaperUnits'); + set(curfig,'PaperUnits','points'); + pp = get(curfig,'PaperPosition'); + set(curfig,'PaperUnits',pu); + set(curax,'Units','pixels'); + curapscreen = get(curax,'Position'); + set(curax,'Units','normalized'); + curap = pp.*get(curax,'Position'); + else, + set(curax,'Units','pixels'); + curapscreen = get(curax,'Position'); + curap = curapscreen; + end; + set(curax,'Units',u); + set(curax,'Position',axposoldunits); + % handle non-stretched axes position + str_stretch = { 'DataAspectRatioMode' ; ... + 'PlotBoxAspectRatioMode' ; ... + 'CameraViewAngleMode' }; + str_camera = { 'CameraPositionMode' ; ... + 'CameraTargetMode' ; ... + 'CameraViewAngleMode' ; ... + 'CameraUpVectorMode' }; + notstretched = strcmp(get(curax,str_stretch),'manual'); + manualcamera = strcmp(get(curax,str_camera),'manual'); + if ~arrow_WarpToFill(notstretched,manualcamera,curax), + % give a warning that this has not been thoroughly tested + if 0 & ARROW_STRETCH_WARN, + ARROW_STRETCH_WARN = 0; + strs = {str_stretch{1:2},str_camera{:}}; + strs = [char(ones(length(strs),1)*sprintf('\n ')) char(strs)]'; + warning([upper(mfilename) ' may not yet work quite right ' ... + 'if any of the following are ''manual'':' strs(:).']); + end; + % find the true pixel size of the actual axes + texttmp = text(axl(1,[1 2 2 1 1 2 2 1]), ... + axl(2,[1 1 2 2 1 1 2 2]), ... + axl(3,[1 1 1 1 2 2 2 2]),''); + set(texttmp,'Units','points'); + textpos = get(texttmp,'Position'); + delete(texttmp); + textpos = cat(1,textpos{:}); + textpos = max(textpos(:,1:2)) - min(textpos(:,1:2)); + % adjust the axes position + if (really_curpage), + % adjust to printed size + textpos = textpos * min(curap(3:4)./textpos); + curap = [curap(1:2)+(curap(3:4)-textpos)/2 textpos]; + else, + % adjust for pixel roundoff + textpos = textpos * min(curapscreen(3:4)./textpos); + curap = [curap(1:2)+(curap(3:4)-textpos)/2 textpos]; + end; + end; + if ARROW_PERSP_WARN & ~strcmp(get(curax,'Projection'),'orthographic'), + ARROW_PERSP_WARN = 0; + warning([upper(mfilename) ' does not yet work right for 3-D perspective projection.']); + end; + % adjust limits for log scale on axes + curxyzlog = strcmp(get(curax,{'XScale' 'YScale' 'ZScale'})','log'); + if (any(curxyzlog)), + ii = find([curxyzlog;curxyzlog]); + if (any(axl(ii)<=0)), + error([upper(mfilename) ' does not support non-positive limits on log-scaled axes.']); + else, + axl(ii) = log10(axl(ii)); + end; + end; + % correct for 'reverse' direction on axes; + curreverse = strcmp(get(curax,{'XDir' 'YDir' 'ZDir'})','reverse'); + ii = find(curreverse); + if ~isempty(ii), + axl(ii,[1 2])=-axl(ii,[2 1]); + end; + % compute the range of 2-D values + try, curT=get(curax,'Xform'); catch, num2cell(get(curax,'View')); curT=viewmtx(ans{:}); end; + lim = curT*[0 1 0 1 0 1 0 1;0 0 1 1 0 0 1 1;0 0 0 0 1 1 1 1;1 1 1 1 1 1 1 1]; + lim = lim(1:2,:)./([1;1]*lim(4,:)); + curlimmin = min(lim')'; + curlimrange = max(lim')' - curlimmin; + curinvT = inv(curT); + if (~oneax), + curT = curT.'; + curinvT = curinvT.'; + curT = curT(:); + curinvT = curinvT(:); + end; + % check which arrows to which cur corresponds + ii = find((ax==curax)&(page==curpage)); + oo = ones(1,length(ii)); + axr(:,ii) = diff(axl')' * oo; + axm(:,ii) = axl(:,1) * oo; + axrev(:,ii) = curreverse * oo; + ap(:,ii) = curap(3:4)' * oo; + xyzlog(:,ii) = curxyzlog * oo; + limmin(:,ii) = curlimmin * oo; + limrange(:,ii) = curlimrange * oo; + if (oneax), + T = curT; + invT = curinvT; + else, + T(:,ii) = curT * oo; + invT(:,ii) = curinvT * oo; + end; + axnotdone(ii) = zeros(1,length(ii)); +end; + +% correct for log scales +curxyzlog = xyzlog.'; +ii = find(curxyzlog(:)); +if ~isempty(ii), + start( ii) = real(log10(start( ii))); + stop( ii) = real(log10(stop( ii))); + if (all(imag(crossdir)==0)), % pulled (ii) subscript on crossdir, 12/5/96 eaj + crossdir(ii) = real(log10(crossdir(ii))); + end; +end; + +% correct for reverse directions +ii = find(axrev.'); +if ~isempty(ii), + start( ii) = -start( ii); + stop( ii) = -stop( ii); + crossdir(ii) = -crossdir(ii); +end; + +% transpose start/stop values +start = start.'; +stop = stop.'; + +% take care of defaults, page was done above +ii=find(isnan(start(:) )); if ~isempty(ii), start(ii) = axm(ii)+axr(ii)/2; end; +ii=find(isnan(stop(:) )); if ~isempty(ii), stop(ii) = axm(ii)+axr(ii)/2; end; +ii=find(isnan(crossdir(:) )); if ~isempty(ii), crossdir(ii) = zeros(length(ii),1); end; +ii=find(isnan(len )); if ~isempty(ii), len(ii) = ones(length(ii),1)*deflen; end; +ii=find(isnan(baseangle )); if ~isempty(ii), baseangle(ii) = ones(length(ii),1)*defbaseangle; end; +ii=find(isnan(tipangle )); if ~isempty(ii), tipangle(ii) = ones(length(ii),1)*deftipangle; end; +ii=find(isnan(wid )); if ~isempty(ii), wid(ii) = ones(length(ii),1)*defwid; end; +ii=find(isnan(ends )); if ~isempty(ii), ends(ii) = ones(length(ii),1)*defends; end; +ii=find(isnan(shorten )); if ~isempty(ii), shorten(ii) = ones(length(ii),1)*defshorten; end; + +% transpose rest of values +len = len.'; +baseangle = baseangle.'; +tipangle = tipangle.'; +wid = wid.'; +page = page.'; +crossdir = crossdir.'; +ends = ends.'; +shorten = shorten.'; +ax = ax.'; + +% given x, a 3xN matrix of points in 3-space; +% want to convert to X, the corresponding 4xN 2-space matrix +% +% tmp1=[(x-axm)./axr; ones(1,size(x,1))]; +% if (oneax), X=T*tmp1; +% else, tmp1=[tmp1;tmp1;tmp1;tmp1]; tmp1=T.*tmp1; +% tmp2=zeros(4,4*N); tmp2(:)=tmp1(:); +% X=zeros(4,N); X(:)=sum(tmp2)'; end; +% X = X ./ (ones(4,1)*X(4,:)); + +% for all points with start==stop, start=stop-(verysmallvalue)*(up-direction); +ii = find(all(start==stop)); +if ~isempty(ii), + % find an arrowdir vertical on screen and perpendicular to viewer + % transform to 2-D + tmp1 = [(stop(:,ii)-axm(:,ii))./axr(:,ii);ones(1,length(ii))]; + if (oneax), twoD=T*tmp1; + else, tmp1=[tmp1;tmp1;tmp1;tmp1]; tmp1=T(:,ii).*tmp1; + tmp2=zeros(4,4*length(ii)); tmp2(:)=tmp1(:); + twoD=zeros(4,length(ii)); twoD(:)=sum(tmp2)'; end; + twoD=twoD./(ones(4,1)*twoD(4,:)); + % move the start point down just slightly + tmp1 = twoD + [0;-1/1000;0;0]*(limrange(2,ii)./ap(2,ii)); + % transform back to 3-D + if (oneax), threeD=invT*tmp1; + else, tmp1=[tmp1;tmp1;tmp1;tmp1]; tmp1=invT(:,ii).*tmp1; + tmp2=zeros(4,4*length(ii)); tmp2(:)=tmp1(:); + threeD=zeros(4,length(ii)); threeD(:)=sum(tmp2)'; end; + start(:,ii) = (threeD(1:3,:)./(ones(3,1)*threeD(4,:))).*axr(:,ii)+axm(:,ii); +end; + +% compute along-arrow points +% transform Start points + tmp1=[(start-axm)./axr;ones(1,narrows)]; + if (oneax), X0=T*tmp1; + else, tmp1=[tmp1;tmp1;tmp1;tmp1]; tmp1=T.*tmp1; + tmp2=zeros(4,4*narrows); tmp2(:)=tmp1(:); + X0=zeros(4,narrows); X0(:)=sum(tmp2)'; end; + X0=X0./(ones(4,1)*X0(4,:)); +% transform Stop points + tmp1=[(stop-axm)./axr;ones(1,narrows)]; + if (oneax), Xf=T*tmp1; + else, tmp1=[tmp1;tmp1;tmp1;tmp1]; tmp1=T.*tmp1; + tmp2=zeros(4,4*narrows); tmp2(:)=tmp1(:); + Xf=zeros(4,narrows); Xf(:)=sum(tmp2)'; end; + Xf=Xf./(ones(4,1)*Xf(4,:)); +% compute pixel distance between points + D = sqrt(sum(((Xf(1:2,:)-X0(1:2,:)).*(ap./limrange)).^2)); + D = D + (D==0); %eaj new 2/24/98 +% shorten the length if requested % added 2/6/2013 + numends = (ends==1) + (ends==2) + 2*(ends==3); + mask = shorten & D<len.*numends; + len(mask) = D(mask) ./ numends(mask); +% compute and modify along-arrow distances + len1 = len; + len2 = len - (len.*tan(tipangle/180*pi)-wid/2).*tan((90-baseangle)/180*pi); + slen0 = zeros(1,narrows); + slen1 = len1 .* ((ends==2)|(ends==3)); + slen2 = len2 .* ((ends==2)|(ends==3)); + len0 = zeros(1,narrows); + len1 = len1 .* ((ends==1)|(ends==3)); + len2 = len2 .* ((ends==1)|(ends==3)); + % for no start arrowhead + ii=find((ends==1)&(D<len2)); + if ~isempty(ii), + slen0(ii) = D(ii)-len2(ii); + end; + % for no end arrowhead + ii=find((ends==2)&(D<slen2)); + if ~isempty(ii), + len0(ii) = D(ii)-slen2(ii); + end; + len1 = len1 + len0; + len2 = len2 + len0; + slen1 = slen1 + slen0; + slen2 = slen2 + slen0; + % note: the division by D below will probably not be accurate if both + % of the following are true: + % 1. the ratio of the line length to the arrowhead + % length is large + % 2. the view is highly perspective. +% compute stoppoints + tmp1=X0.*(ones(4,1)*(len0./D))+Xf.*(ones(4,1)*(1-len0./D)); + if (oneax), tmp3=invT*tmp1; + else, tmp1=[tmp1;tmp1;tmp1;tmp1]; tmp1=invT.*tmp1; + tmp2=zeros(4,4*narrows); tmp2(:)=tmp1(:); + tmp3=zeros(4,narrows); tmp3(:)=sum(tmp2)'; end; + stoppoint = tmp3(1:3,:)./(ones(3,1)*tmp3(4,:)).*axr+axm; +% compute tippoints + tmp1=X0.*(ones(4,1)*(len1./D))+Xf.*(ones(4,1)*(1-len1./D)); + if (oneax), tmp3=invT*tmp1; + else, tmp1=[tmp1;tmp1;tmp1;tmp1]; tmp1=invT.*tmp1; + tmp2=zeros(4,4*narrows); tmp2(:)=tmp1(:); + tmp3=zeros(4,narrows); tmp3(:)=sum(tmp2)'; end; + tippoint = tmp3(1:3,:)./(ones(3,1)*tmp3(4,:)).*axr+axm; +% compute basepoints + tmp1=X0.*(ones(4,1)*(len2./D))+Xf.*(ones(4,1)*(1-len2./D)); + if (oneax), tmp3=invT*tmp1; + else, tmp1=[tmp1;tmp1;tmp1;tmp1]; tmp1=invT.*tmp1; + tmp2=zeros(4,4*narrows); tmp2(:)=tmp1(:); + tmp3=zeros(4,narrows); tmp3(:)=sum(tmp2)'; end; + basepoint = tmp3(1:3,:)./(ones(3,1)*tmp3(4,:)).*axr+axm; +% compute startpoints + tmp1=X0.*(ones(4,1)*(1-slen0./D))+Xf.*(ones(4,1)*(slen0./D)); + if (oneax), tmp3=invT*tmp1; + else, tmp1=[tmp1;tmp1;tmp1;tmp1]; tmp1=invT.*tmp1; + tmp2=zeros(4,4*narrows); tmp2(:)=tmp1(:); + tmp3=zeros(4,narrows); tmp3(:)=sum(tmp2)'; end; + startpoint = tmp3(1:3,:)./(ones(3,1)*tmp3(4,:)).*axr+axm; +% compute stippoints + tmp1=X0.*(ones(4,1)*(1-slen1./D))+Xf.*(ones(4,1)*(slen1./D)); + if (oneax), tmp3=invT*tmp1; + else, tmp1=[tmp1;tmp1;tmp1;tmp1]; tmp1=invT.*tmp1; + tmp2=zeros(4,4*narrows); tmp2(:)=tmp1(:); + tmp3=zeros(4,narrows); tmp3(:)=sum(tmp2)'; end; + stippoint = tmp3(1:3,:)./(ones(3,1)*tmp3(4,:)).*axr+axm; +% compute sbasepoints + tmp1=X0.*(ones(4,1)*(1-slen2./D))+Xf.*(ones(4,1)*(slen2./D)); + if (oneax), tmp3=invT*tmp1; + else, tmp1=[tmp1;tmp1;tmp1;tmp1]; tmp1=invT.*tmp1; + tmp2=zeros(4,4*narrows); tmp2(:)=tmp1(:); + tmp3=zeros(4,narrows); tmp3(:)=sum(tmp2)'; end; + sbasepoint = tmp3(1:3,:)./(ones(3,1)*tmp3(4,:)).*axr+axm; + +% compute cross-arrow directions for arrows with NormalDir specified +if (any(imag(crossdir(:))~=0)), + ii = find(any(imag(crossdir)~=0)); + crossdir(:,ii) = cross((stop(:,ii)-start(:,ii))./axr(:,ii), ... + imag(crossdir(:,ii))).*axr(:,ii); +end; + +% compute cross-arrow directions +basecross = crossdir + basepoint; +tipcross = crossdir + tippoint; +sbasecross = crossdir + sbasepoint; +stipcross = crossdir + stippoint; +ii = find(all(crossdir==0)|any(isnan(crossdir))); +if ~isempty(ii), + numii = length(ii); + % transform start points + tmp1 = [basepoint(:,ii) tippoint(:,ii) sbasepoint(:,ii) stippoint(:,ii)]; + tmp1 = (tmp1-axm(:,[ii ii ii ii])) ./ axr(:,[ii ii ii ii]); + tmp1 = [tmp1; ones(1,4*numii)]; + if (oneax), X0=T*tmp1; + else, tmp1=[tmp1;tmp1;tmp1;tmp1]; tmp1=T(:,[ii ii ii ii]).*tmp1; + tmp2=zeros(4,16*numii); tmp2(:)=tmp1(:); + X0=zeros(4,4*numii); X0(:)=sum(tmp2)'; end; + X0=X0./(ones(4,1)*X0(4,:)); + % transform stop points + tmp1 = [(2*stop(:,ii)-start(:,ii)-axm(:,ii))./axr(:,ii);ones(1,numii)]; + tmp1 = [tmp1 tmp1 tmp1 tmp1]; + if (oneax), Xf=T*tmp1; + else, tmp1=[tmp1;tmp1;tmp1;tmp1]; tmp1=T(:,[ii ii ii ii]).*tmp1; + tmp2=zeros(4,16*numii); tmp2(:)=tmp1(:); + Xf=zeros(4,4*numii); Xf(:)=sum(tmp2)'; end; + Xf=Xf./(ones(4,1)*Xf(4,:)); + % compute perpendicular directions + pixfact = ((limrange(1,ii)./limrange(2,ii)).*(ap(2,ii)./ap(1,ii))).^2; + pixfact = [pixfact pixfact pixfact pixfact]; + pixfact = [pixfact;1./pixfact]; + [dummyval,jj] = max(abs(Xf(1:2,:)-X0(1:2,:))); + jj1 = ((1:4)'*ones(1,length(jj))==ones(4,1)*jj); + jj2 = ((1:4)'*ones(1,length(jj))==ones(4,1)*(3-jj)); + jj3 = jj1(1:2,:); + Xf(jj1)=Xf(jj1)+(Xf(jj1)-X0(jj1)==0); %eaj new 2/24/98 + Xp = X0; + Xp(jj2) = X0(jj2) + ones(sum(jj2(:)),1); + Xp(jj1) = X0(jj1) - (Xf(jj2)-X0(jj2))./(Xf(jj1)-X0(jj1)) .* pixfact(jj3); + % inverse transform the cross points + if (oneax), Xp=invT*Xp; + else, tmp1=[Xp;Xp;Xp;Xp]; tmp1=invT(:,[ii ii ii ii]).*tmp1; + tmp2=zeros(4,16*numii); tmp2(:)=tmp1(:); + Xp=zeros(4,4*numii); Xp(:)=sum(tmp2)'; end; + Xp=(Xp(1:3,:)./(ones(3,1)*Xp(4,:))).*axr(:,[ii ii ii ii])+axm(:,[ii ii ii ii]); + basecross(:,ii) = Xp(:,0*numii+(1:numii)); + tipcross(:,ii) = Xp(:,1*numii+(1:numii)); + sbasecross(:,ii) = Xp(:,2*numii+(1:numii)); + stipcross(:,ii) = Xp(:,3*numii+(1:numii)); +end; + +% compute all points +% compute start points + axm11 = [axm axm axm axm axm axm axm axm axm axm axm]; + axr11 = [axr axr axr axr axr axr axr axr axr axr axr]; + st = [stoppoint tippoint basepoint sbasepoint stippoint startpoint stippoint sbasepoint basepoint tippoint stoppoint]; + tmp1 = (st - axm11) ./ axr11; + tmp1 = [tmp1; ones(1,size(tmp1,2))]; + if (oneax), X0=T*tmp1; + else, tmp1=[tmp1;tmp1;tmp1;tmp1]; tmp1=[T T T T T T T T T T T].*tmp1; + tmp2=zeros(4,44*narrows); tmp2(:)=tmp1(:); + X0=zeros(4,11*narrows); X0(:)=sum(tmp2)'; end; + X0=X0./(ones(4,1)*X0(4,:)); +% compute stop points + tmp1 = ([start tipcross basecross sbasecross stipcross stop stipcross sbasecross basecross tipcross start] ... + - axm11) ./ axr11; + tmp1 = [tmp1; ones(1,size(tmp1,2))]; + if (oneax), Xf=T*tmp1; + else, tmp1=[tmp1;tmp1;tmp1;tmp1]; tmp1=[T T T T T T T T T T T].*tmp1; + tmp2=zeros(4,44*narrows); tmp2(:)=tmp1(:); + Xf=zeros(4,11*narrows); Xf(:)=sum(tmp2)'; end; + Xf=Xf./(ones(4,1)*Xf(4,:)); +% compute lengths + len0 = len.*((ends==1)|(ends==3)).*tan(tipangle/180*pi); + slen0 = len.*((ends==2)|(ends==3)).*tan(tipangle/180*pi); + le = [zeros(1,narrows) len0 wid/2 wid/2 slen0 zeros(1,narrows) -slen0 -wid/2 -wid/2 -len0 zeros(1,narrows)]; + aprange = ap./limrange; + aprange = [aprange aprange aprange aprange aprange aprange aprange aprange aprange aprange aprange]; + D = sqrt(sum(((Xf(1:2,:)-X0(1:2,:)).*aprange).^2)); + Dii=find(D==0); if ~isempty(Dii), D=D+(D==0); le(Dii)=zeros(1,length(Dii)); end; %should fix DivideByZero warnings + tmp1 = X0.*(ones(4,1)*(1-le./D)) + Xf.*(ones(4,1)*(le./D)); +% inverse transform + if (oneax), tmp3=invT*tmp1; + else, tmp1=[tmp1;tmp1;tmp1;tmp1]; tmp1=[invT invT invT invT invT invT invT invT invT invT invT].*tmp1; + tmp2=zeros(4,44*narrows); tmp2(:)=tmp1(:); + tmp3=zeros(4,11*narrows); tmp3(:)=sum(tmp2)'; end; + pts = tmp3(1:3,:)./(ones(3,1)*tmp3(4,:)) .* axr11 + axm11; + +% correct for ones where the crossdir was specified +ii = find(~(all(crossdir==0)|any(isnan(crossdir)))); +if ~isempty(ii), + D1 = [pts(:,1*narrows+ii)-pts(:,9*narrows+ii) ... + pts(:,2*narrows+ii)-pts(:,8*narrows+ii) ... + pts(:,3*narrows+ii)-pts(:,7*narrows+ii) ... + pts(:,4*narrows+ii)-pts(:,6*narrows+ii) ... + pts(:,6*narrows+ii)-pts(:,4*narrows+ii) ... + pts(:,7*narrows+ii)-pts(:,3*narrows+ii) ... + pts(:,8*narrows+ii)-pts(:,2*narrows+ii) ... + pts(:,9*narrows+ii)-pts(:,1*narrows+ii)]/2; + ii = ii'*ones(1,8) + ones(length(ii),1)*[1:4 6:9]*narrows; + ii = ii(:)'; + pts(:,ii) = st(:,ii) + D1; +end; + + +% readjust for reverse directions +iicols=(1:narrows)'; iicols=iicols(:,ones(1,11)); iicols=iicols(:).'; +tmp1=axrev(:,iicols); +ii = find(tmp1(:)); if ~isempty(ii), pts(ii)=-pts(ii); end; + +% change from starting/ending at the stop point to doing it at the midpoint %eaj 7/14/2014 +(pts(:,2*narrows+1:3*narrows)+pts(:,3*narrows+1:4*narrows))/2; %eaj 7/14/2014 +pts = [ans pts(:,[3*narrows+1:end narrows+1:3*narrows]) ans]; %eaj 7/14/2014 + +% readjust for log scale on axes +tmp1=xyzlog(:,iicols); +ii = find(tmp1(:)); if ~isempty(ii), pts(ii)=10.^pts(ii); end; + +% compute the x,y,z coordinates of the patches; +ii = narrows*(0:size(pts,2)/narrows-1)'*ones(1,narrows) + ones(size(pts,2)/narrows,1)*(1:narrows); +ii = ii(:)'; +x = zeros(size(pts,2)/narrows,narrows); +y = zeros(size(pts,2)/narrows,narrows); +z = zeros(size(pts,2)/narrows,narrows); +x(:) = pts(1,ii)'; +y(:) = pts(2,ii)'; +z(:) = pts(3,ii)'; + +% do the output +if (nargout<=1), +% % create or modify the patches + newpatch = trueornan(ispatch) & (isempty(oldh)|~strcmp(get(oldh,'Type'),'patch')); + newline = ~trueornan(ispatch) & (isempty(oldh)|~strcmp(get(oldh,'Type'),'line')); + if isempty(oldh), H=zeros(narrows,1); else, H=oldh; end; +% % make or modify the arrows + for k=1:narrows, + if all(isnan(ud(k,[3 6])))&arrow_is2DXY(ax(k)), zz=[]; else, zz=z(:,k); end; + xx=x(:,k); yy=y(:,k); + if (0), % this fix didn't work, so let's not use it -- 8/26/03 + % try to work around a MATLAB 6.x OpenGL bug -- 7/28/02 + mask=any([ones(1,2+size(zz,2));diff([xx yy zz],[],1)],2); + xx=xx(mask); yy=yy(mask); if ~isempty(zz), zz=zz(mask); end; + end; + % plot the patch or line + if newpatch(k) || trueornan(ispatch(k)) %eaj 7/14/2014, 5/25/2016 + % patch is closed so don't need endpoints %eaj 7/14/2014 + if ~isempty(xx), xx(end)=[]; end; %eaj 7/14/2014 + if ~isempty(yy), yy(end)=[]; end; %eaj 7/14/2014 + if ~isempty(zz), zz(end)=[]; end; %eaj 7/14/2014 + end %eaj 7/14/2014 + xyz = {'XData',xx,'YData',yy,'ZData',zz,'Tag',ArrowTag}; + if newpatch(k)|newline(k), + if newpatch(k), + H(k) = patch(xyz{:}); + else, + H(k) = line(xyz{:}); + end; + if ~isempty(oldh), arrow_copyprops(oldh(k),H(k)); end; + else, + if strcmp(get(H(k),'Type'),'patch') %eaj 5/25/16 if ispatch(k) + xyz = {xyz{:},'CData',[]}; + end; + set(H(k),xyz{:}); + end; + end; + if ~isempty(oldh), delete(oldh(oldh~=H)); end; +% % additional properties + set(H,'Clipping','off'); + set(H,{'UserData'},num2cell(ud,2)); + if length(extraprops)>0 + ii = find(strcmpi(extraprops(1:2:end),'color')); %eaj 5/25/16 + ispatch = strcmp(get(H,'Type'),'patch'); + %eaj start 5/25/16 + while ~isempty(ii) && any(ispatch) + if ii>1, set(H,extraprops{1:2*ii-2}); end; + c = extraprops{2*ii}; + extraprops(1:2*ii) = []; + ii(1) = []; + if all(ispatch) || ischar(c)&&size(c,1)==1 || isnumeric(c)&&isequal(size(c),[1 3]) + set(H,'EdgeColor',c,'FaceColor',c) + elseif iscell(c) && numel(c)~=numel(H) + set(H(ispatch),'EdgeColor',c(ispatch),'FaceColor',c(ispatch)); + set(H(~ispatch),'Color',c(~ispatch)); + elseif isnumeric(c) && isequal(size(c),[numel(H) 3]) + set(H(ispatch),'EdgeColor',num2cell(c(ispatch,:),2),'FaceColor',num2cell(c(ispatch,:),2)); + set(H(~ispatch),'Color',num2cell(c(~ispatch,:),2)); + else + warning('ignoring unknown or invalid ''Color'' specification'); + end + end + if ~isempty(extraprops) + %eaj end 5/25/16 + set(H,extraprops{:}); + end %eaj 5/25/16 + end + % handle choosing arrow Start and/or Stop locations if unspecified + [H,oldaxlims,errstr] = arrow_clicks(H,ud,x,y,z,ax,oldaxlims); + if ~isempty(errstr), error([upper(mfilename) ' got ' errstr]); end; + % set the output + if (nargout>0), h=H; end; + % make sure the axis limits did not change + if isempty(oldaxlims), + ARROW_AXLIMITS = []; + ARROW_AX = []; + else, + lims = get(ax(:),{'XLim','YLim','ZLim'})'; + lims = reshape(cat(2,lims{:}),6,size(lims,2)); + mask = arrow_is2DXY(ax(:)); + oldaxlims(5:6,mask) = lims(5:6,mask); + % store them for possible restoring + mask = any(oldaxlims~=lims,1); ARROW_AX=ax(mask); ARROW_AXLIMITS=oldaxlims(:,mask); + if any(mask), + warning(arrow_warnlimits(ARROW_AX,narrows)); + end; + end; +else, + % don't create the patch, just return the data + h=x; + yy=y; + zz=z; +end; + + + +function out = arrow_defcheck(in,def,prop) +% check if we got 'default' values + out = in; + if ~isstr(in), return; end; + if size(in,1)==1 & strncmp(lower(in),'def',3), + out = def; + elseif ~isempty(prop), + error([upper(mfilename) ' does not recognize ''' in(:)' ''' as a valid ''' prop ''' string.']); + end; + + + +function [H,oldaxlims,errstr] = arrow_clicks(H,ud,x,y,z,ax,oldaxlims) +% handle choosing arrow Start and/or Stop locations if necessary + errstr = ''; + if isempty(H)|isempty(ud)|isempty(x), return; end; + % determine which (if any) need Start and/or Stop + needStart = all(isnan(ud(:,1:3)'))'; + needStop = all(isnan(ud(:,4:6)'))'; + mask = any(needStart|needStop); + if ~any(mask), return; end; + ud(~mask,:)=[]; ax(:,~mask)=[]; + x(:,~mask)=[]; y(:,~mask)=[]; z(:,~mask)=[]; + % make them invisible for the time being + set(H,'Visible','off'); + % save the current axes and limits modes; set to manual for the time being + oldAx = gca; + limModes=get(ax(:),{'XLimMode','YLimMode','ZLimMode'}); + set(ax(:),{'XLimMode','YLimMode','ZLimMode'},{'manual','manual','manual'}); + % loop over each arrow that requires attention + jj = find(mask); + for ii=1:length(jj), + h = H(jj(ii)); + axes(ax(ii)); + % figure out correct call + if needStart(ii), prop='Start'; else, prop='Stop'; end; + [wasInterrupted,errstr] = arrow_click(needStart(ii)&needStop(ii),h,prop,ax(ii)); + % handle errors and control-C + if wasInterrupted, + delete(H(jj(ii:end))); + H(jj(ii:end))=[]; + oldaxlims(jj(ii:end),:)=[]; + break; + end; + end; + % restore the axes and limit modes + axes(oldAx); + set(ax(:),{'XLimMode','YLimMode','ZLimMode'},limModes); + +function [wasInterrupted,errstr] = arrow_click(lockStart,H,prop,ax) +% handle the clicks for one arrow + fig = get(ax,'Parent'); + % save some things + oldFigProps = {'Pointer','WindowButtonMotionFcn','WindowButtonUpFcn'}; + oldFigValue = get(fig,oldFigProps); + oldArrowProps = {'EraseMode'}; + if ~isnumeric(fig), oldArrowProps={}; end %eaj 5/24/16 % only use in HG2 + oldArrowValue = get(H,oldArrowProps); + if isnumeric(fig), %eaj 5/24/16 + set(H,'EraseMode','background'); %because 'xor' makes shaft invisible unless Width>1 -- only use in HG2 + end %eaj 5/24/16 + global ARROW_CLICK_H ARROW_CLICK_PROP ARROW_CLICK_AX ARROW_CLICK_USE_Z + ARROW_CLICK_H=H; ARROW_CLICK_PROP=prop; ARROW_CLICK_AX=ax; + ARROW_CLICK_USE_Z=~arrow_is2DXY(ax)|~arrow_planarkids(ax); + set(fig,'Pointer','crosshair'); + % set up the WindowButtonMotion so we can see the arrow while moving around + set(fig,'WindowButtonUpFcn','set(gcf,''WindowButtonUpFcn'','''')', ... + 'WindowButtonMotionFcn',''); + if ~lockStart, + set(H,'Visible','on'); + set(fig,'WindowButtonMotionFcn',[mfilename '(''callback'',''motion'');']); + end; + % wait for the button to be pressed + [wasKeyPress,wasInterrupted,errstr] = arrow_wfbdown(fig); + % if we wanted to click-drag, set the Start point + if lockStart & ~wasInterrupted, + pt = arrow_point(ARROW_CLICK_AX,ARROW_CLICK_USE_Z); + feval(mfilename,H,'Start',pt,'Stop',pt); + set(H,'Visible','on'); + ARROW_CLICK_PROP='Stop'; + set(fig,'WindowButtonMotionFcn',[mfilename '(''callback'',''motion'');']); + % wait for the mouse button to be released + try + waitfor(fig,'WindowButtonUpFcn',''); + catch + errstr = lasterr; + wasInterrupted = 1; + end; + end; + if ~wasInterrupted, feval(mfilename,'callback','motion'); end; + % restore some things + set(gcf,oldFigProps,oldFigValue); + set(H,oldArrowProps,oldArrowValue); + +function arrow_callback(varargin) +% handle redrawing callbacks + if nargin==0, return; end; + str = varargin{1}; + if ~isstr(str), error([upper(mfilename) ' got an invalid Callback command.']); end; + s = lower(str); + if strcmp(s,'motion'), + % motion callback + global ARROW_CLICK_H ARROW_CLICK_PROP ARROW_CLICK_AX ARROW_CLICK_USE_Z + feval(mfilename,ARROW_CLICK_H,ARROW_CLICK_PROP,arrow_point(ARROW_CLICK_AX,ARROW_CLICK_USE_Z)); + drawnow; + else, + error([upper(mfilename) ' does not recognize ''' str(:).' ''' as a valid Callback option.']); + end; + +function out = arrow_point(ax,use_z) +% return the point on the given axes + if nargin==0, ax=gca; end; + if nargin<2, use_z=~arrow_is2DXY(ax)|~arrow_planarkids(ax); end; + out = get(ax,'CurrentPoint'); + out = out(1,:); + if ~use_z, out=out(1:2); end; + +function [wasKeyPress,wasInterrupted,errstr] = arrow_wfbdown(fig) +% wait for button down ignoring object ButtonDownFcn's + if nargin==0, fig=gcf; end; + errstr = ''; + % save ButtonDownFcn values + objs = findobj(fig); + buttonDownFcns = get(objs,'ButtonDownFcn'); + mask=~strcmp(buttonDownFcns,''); objs=objs(mask); buttonDownFcns=buttonDownFcns(mask); + set(objs,'ButtonDownFcn',''); + % save other figure values + figProps = {'KeyPressFcn','WindowButtonDownFcn'}; + figValue = get(fig,figProps); + % do the real work + set(fig,'KeyPressFcn','set(gcf,''KeyPressFcn'','''',''WindowButtonDownFcn'','''');', ... + 'WindowButtonDownFcn','set(gcf,''WindowButtonDownFcn'','''')'); + lasterr(''); + try + waitfor(fig,'WindowButtonDownFcn',''); + wasInterrupted = 0; + catch + wasInterrupted = 1; + end + wasKeyPress = ~wasInterrupted & strcmp(get(fig,'KeyPressFcn'),''); + if wasInterrupted, errstr=lasterr; end; + % restore ButtonDownFcn and other figure values + set(objs,'ButtonDownFcn',buttonDownFcns); + set(fig,figProps,figValue); + + + +function [out,is2D] = arrow_is2DXY(ax) +% check if axes are 2-D X-Y plots + % may not work for modified camera angles, etc. + out = false(size(ax)); % 2-D X-Y plots + is2D = out; % any 2-D plots + views = get(ax(:),{'View'}); + views = cat(1,views{:}); + out(:) = abs(views(:,2))==90; + is2D(:) = out(:) | all(rem(views',90)==0)'; + +function out = arrow_planarkids(ax) +% check if axes descendents all have empty ZData (lines,patches,surfaces) + out = true(size(ax)); + allkids = get(ax(:),{'Children'}); + for k=1:length(allkids), + kids = get([findobj(allkids{k},'flat','Type','line') + findobj(allkids{k},'flat','Type','patch') + findobj(allkids{k},'flat','Type','surface')],{'ZData'}); + for j=1:length(kids), + if ~isempty(kids{j}), out(k)=logical(0); break; end; + end; + end; + + + +function arrow_fixlimits(ax,lims) +% reset the axis limits as necessary + if isempty(ax) || isempty(lims), disp([upper(mfilename) ' does not remember any axis limits to reset.']); end; + for k=1:numel(ax), + if any(get(ax(k),'XLim')~=lims(1:2,k)'), set(ax(k),'XLim',lims(1:2,k)'); end; + if any(get(ax(k),'YLim')~=lims(3:4,k)'), set(ax(k),'YLim',lims(3:4,k)'); end; + if any(get(ax(k),'ZLim')~=lims(5:6,k)'), set(ax(k),'ZLim',lims(5:6,k)'); end; + end; + + + +function out = arrow_WarpToFill(notstretched,manualcamera,curax) +% check if we are in "WarpToFill" mode. + out = strcmp(get(curax,'WarpToFill'),'on'); + % 'WarpToFill' is undocumented, so may need to replace this by + % out = ~( any(notstretched) & any(manualcamera) ); + + + +function out = arrow_warnlimits(ax,narrows) +% create a warning message if we've changed the axis limits + msg = ''; + switch (numel(ax)) + case 1, msg=''; + case 2, msg='on two axes '; + otherwise, msg='on several axes '; + end; + msg = [upper(mfilename) ' changed the axis limits ' msg ... + 'when adding the arrow']; + if (narrows>1), msg=[msg 's']; end; + out = [msg '.' sprintf('\n') ' Call ' upper(mfilename) ... + ' FIXLIMITS to reset them now.']; + + + +function arrow_copyprops(fm,to) +% copy line properties to patches + props = {'EraseMode','LineStyle','LineWidth','Marker','MarkerSize',... + 'MarkerEdgeColor','MarkerFaceColor','ButtonDownFcn', ... + 'Clipping','DeleteFcn','BusyAction','HandleVisibility', ... + 'Selected','SelectionHighlight','Visible'}; + if ~isnumeric(findobj('Type','root')), props(strcmp(props,'EraseMode'))=[]; end; %eaj 5/24/16 + lineprops = {'Color', props{:}}; + patchprops = {'EdgeColor',props{:}}; + patch2props = {'FaceColor',patchprops{:}}; + fmpatch = strcmp(get(fm,'Type'),'patch'); + topatch = strcmp(get(to,'Type'),'patch'); + set(to( fmpatch& topatch),patch2props,get(fm( fmpatch& topatch),patch2props)); %p->p + set(to(~fmpatch&~topatch),lineprops, get(fm(~fmpatch&~topatch),lineprops )); %l->l + set(to( fmpatch&~topatch),lineprops, get(fm( fmpatch&~topatch),patchprops )); %p->l + set(to(~fmpatch& topatch),patchprops, get(fm(~fmpatch& topatch),lineprops) ,'FaceColor','none'); %l->p + + + +function arrow_props +% display further help info about ARROW properties + c = sprintf('\n'); + disp([c ... + 'ARROW Properties: Default values are given in [square brackets], and other' c ... + ' acceptable equivalent property names are in (parenthesis).' c c ... + ' Start The starting points. For N arrows, B' c ... + ' this should be a Nx2 or Nx3 matrix. /|\ ^' c ... + ' Stop The end points. For N arrows, this /|||\ |' c ... + ' should be a Nx2 or Nx3 matrix. //|||\\ L|' c ... + ' Length Length of the arrowhead (in pixels on ///|||\\\ e|' c ... + ' screen, points on a page). [16] (Len) ////|||\\\\ n|' c ... + ' BaseAngle Angle (degrees) of the base angle /////|D|\\\\\ g|' c ... + ' ADE. For a simple stick arrow, use //// ||| \\\\ t|' c ... + ' BaseAngle=TipAngle. [90] (Base) /// ||| \\\ h|' c ... + ' TipAngle Angle (degrees) of tip angle ABC. //<----->|| \\ |' c ... + ' [16] (Tip) / base ||| \ V' c ... + ' Width Width of the base in pixels. Not E angle ||<-------->C' c ... + ' the ''LineWidth'' prop. [0] (Wid) |||tipangle' c ... + ' Page If provided, non-empty, and not NaN, |||' c ... + ' this causes ARROW to use hardcopy |||' c ... + ' rather than onscreen proportions. A' c ... + ' This is important if screen aspect --> <-- width' c ... + ' ratio and hardcopy aspect ratio are ----CrossDir---->' c ... + ' vastly different. []' c... + ' CrossDir A vector giving the direction towards which the fletches' c ... + ' on the arrow should go. [computed such that it is perpen-' c ... + ' dicular to both the arrow direction and the view direction' c ... + ' (i.e., as if it was pasted on a normal 2-D graph)] (Note' c ... + ' that CrossDir is a vector. Also note that if an axis is' c ... + ' plotted on a log scale, then the corresponding component' c ... + ' of CrossDir must also be set appropriately, i.e., to 1 for' c ... + ' no change in that direction, >1 for a positive change, >0' c ... + ' and <1 for negative change.)' c ... + ' NormalDir A vector normal to the fletch direction (CrossDir is then' c ... + ' computed by the vector cross product [Line]x[NormalDir]). []' c ... + ' (Note that NormalDir is a vector. Unlike CrossDir,' c ... + ' NormalDir is used as is regardless of log-scaled axes.)' c ... + ' Ends Set which end has an arrowhead. Valid values are ''none'',' c ... + ' ''stop'', ''start'', and ''both''. [''stop''] (End)' c... + ' ShortenLength Shorten length of arrowhead(s) if line is too short' c ... + ' ObjectHandles Vector of handles to previously-created arrows to be' c ... + ' updated or line objects to be converted to arrows.' c ... + ' [] (Object,Handle)' c ... + ' Type ''patch'' creates the arrow with a PATCH object (the default)' c ... + ' and ''line'' creates it with a LINE object [''patch''].' c ... + ' Color For patch arrows (the default), set both ''FaceColor'' and' c ... + ' ''EdgeColor'' to the given value. For line arrows, set' c ... + ' the ''Color'' property to the given value.' c ... + ]); + + + +function out = arrow_demo + % demo + % create the data + [x,y,z] = peaks; + [ddd,out.iii]=max(z(:)); + out.axlim = [min(x(:)) max(x(:)) min(y(:)) max(y(:)) min(z(:)) max(z(:))]; + + % modify it by inserting some NaN's + [m,n] = size(z); + m = floor(m/2); + n = floor(n/2); + z(1:m,1:n) = NaN*ones(m,n); + + % graph it + clf('reset'); + out.hs=surf(x,y,z); + out.x=x; out.y=y; out.z=z; + xlabel('x'); ylabel('y'); + +function h = arrow_demo3(in) + % set the view + axlim = in.axlim; + axis(axlim); + zlabel('z'); + %set(in.hs,'FaceColor','interp'); + view(3); % view(viewmtx(-37.5,30,20)); + title(['Demo of the capabilities of the ARROW function in 3-D']); + + % Normal blue arrow + h1 = feval(mfilename,[axlim(1) axlim(4) 4],[-.8 1.2 4], ... + 'EdgeColor','b','FaceColor','b'); + + % Normal white arrow, clipped by the surface + h2 = feval(mfilename,axlim([1 4 6]),[0 2 4]); + t=text(-2.4,2.7,7.7,'arrow clipped by surf'); + + % Baseangle<90 + h3 = feval(mfilename,[3 .125 3.5],[1.375 0.125 3.5],30,50); + t2=text(3.1,.125,3.5,'local maximum'); + + % Baseangle<90, fill and edge colors different + h4 = feval(mfilename,axlim(1:2:5)*.5,[0 0 0],36,60,25, ... + 'EdgeColor','b','FaceColor','c'); + t3=text(axlim(1)*.5,axlim(3)*.5,axlim(5)*.5-.75,'origin'); + set(t3,'HorizontalAlignment','center'); + + % Baseangle>90, black fill + h5 = feval(mfilename,[-2.9 2.9 3],[-1.3 .4 3.2],30,120,[],6, ... + 'EdgeColor','r','FaceColor','k','LineWidth',2); + + % Baseangle>90, no fill + h6 = feval(mfilename,[-2.9 2.9 1.3],[-1.3 .4 1.5],30,120,[],6, ... + 'EdgeColor','r','FaceColor','none','LineWidth',2); + + % Stick arrow + h7 = feval(mfilename,[-1.6 -1.65 -6.5],[0 -1.65 -6.5],[],16,16); + t4=text(-1.5,-1.65,-7.25,'global mininum'); + set(t4,'HorizontalAlignment','center'); + + % Normal, black fill + h8 = feval(mfilename,[-1.4 0 -7.2],[-1.4 0 -3],'FaceColor','k'); + t5=text(-1.5,0,-7.75,'local minimum'); + set(t5,'HorizontalAlignment','center'); + + % Gray fill, crossdir specified, 'LineStyle' -- + h9 = feval(mfilename,[-3 2.2 -6],[-3 2.2 -.05],36,[],27,6,[],[0 -1 0], ... + 'EdgeColor','k','FaceColor',.75*[1 1 1],'LineStyle','--'); + + % a series of normal arrows, linearly spaced, crossdir specified + h10y=(0:4)'/3; + h10 = feval(mfilename,[-3*ones(size(h10y)) h10y -6.5*ones(size(h10y))], ... + [-3*ones(size(h10y)) h10y -.05*ones(size(h10y))], ... + 12,[],[],[],[],[0 -1 0]); + + % a series of normal arrows, linearly spaced + h11x=(1:.33:2.8)'; + h11 = feval(mfilename,[h11x -3*ones(size(h11x)) 6.5*ones(size(h11x))], ... + [h11x -3*ones(size(h11x)) -.05*ones(size(h11x))]); + + % series of magenta arrows, radially oriented, crossdir specified + h12x=2; h12y=-3; h12z=axlim(5)/2; h12xr=1; h12zr=h12z; ir=.15;or=.81; + h12t=(0:11)'/6*pi; + h12 = feval(mfilename, ... + [h12x+h12xr*cos(h12t)*ir h12y*ones(size(h12t)) ... + h12z+h12zr*sin(h12t)*ir],[h12x+h12xr*cos(h12t)*or ... + h12y*ones(size(h12t)) h12z+h12zr*sin(h12t)*or], ... + 10,[],[],[],[], ... + [-h12xr*sin(h12t) zeros(size(h12t)) h12zr*cos(h12t)],... + 'FaceColor','none','EdgeColor','m'); + + % series of normal arrows, tangentially oriented, crossdir specified + or13=.91; h13t=(0:.5:12)'/6*pi; + locs = [h12x+h12xr*cos(h13t)*or13 h12y*ones(size(h13t)) h12z+h12zr*sin(h13t)*or13]; + h13 = feval(mfilename,locs(1:end-1,:),locs(2:end,:),6); + + % arrow with no line ==> oriented downwards + h14 = feval(mfilename,[3 3 .100001],[3 3 .1],30); + t6=text(3,3,3.6,'no line'); set(t6,'HorizontalAlignment','center'); + + % arrow with arrowheads at both ends + h15 = feval(mfilename,[-.5 -3 -3],[1 -3 -3],'Ends','both','FaceColor','g', ... + 'Length',20,'Width',3,'CrossDir',[0 0 1],'TipAngle',25); + + h=[h1;h2;h3;h4;h5;h6;h7;h8;h9;h10;h11;h12;h13;h14;h15]; + +function h = arrow_demo2(in) + axlim = in.axlim; + dolog = 1; + if (dolog), set(in.hs,'YData',10.^get(in.hs,'YData')); end; + shading('interp'); + view(2); + title(['Demo of the capabilities of the ARROW function in 2-D']); + hold on; [C,H]=contour(in.x,in.y,in.z,20,'-'); hold off; + for k=H', + set(k,'ZData',(axlim(6)+1)*ones(size(get(k,'XData'))),'Color','k'); + if (dolog), set(k,'YData',10.^get(k,'YData')); end; + end; + if (dolog), axis([axlim(1:2) 10.^axlim(3:4)]); set(gca,'YScale','log'); + else, axis(axlim(1:4)); end; + + % Normal blue arrow + start = [axlim(1) axlim(4) axlim(6)+2]; + stop = [in.x(in.iii) in.y(in.iii) axlim(6)+2]; + if (dolog), start(:,2)=10.^start(:,2); stop(:,2)=10.^stop(:,2); end; + h1 = feval(mfilename,start,stop,'EdgeColor','b','FaceColor','b'); + + % three arrows with varying fill, width, and baseangle + start = [-3 -3 10; -3 -1.5 10; -1.5 -3 10]; + stop = [-.03 -.03 10; -.03 -1.5 10; -1.5 -.03 10]; + if (dolog), start(:,2)=10.^start(:,2); stop(:,2)=10.^stop(:,2); end; + h2 = feval(mfilename,start,stop,24,[90;60;120],[],[0;0;4],'Ends',str2mat('both','stop','stop')); + set(h2(2),'EdgeColor',[0 .35 0],'FaceColor',[0 .85 .85]); + set(h2(3),'EdgeColor','r','FaceColor',[1 .5 1]); + h=[h1;h2]; + +function out = trueornan(x) +if isempty(x), + out=x; +else, + out = isnan(x); + out(~out) = x(~out); +end; diff --git a/sourcecodes/bnt-master/GraphViz/dot_to_graph.m b/sourcecodes/bnt-master/GraphViz/dot_to_graph.m new file mode 100644 index 00000000..05b47480 --- /dev/null +++ b/sourcecodes/bnt-master/GraphViz/dot_to_graph.m @@ -0,0 +1,121 @@ +function [Adj, labels, x, y] = dot_to_graph(filename) +% [Adj, labels, x, y] = dot_to_graph(filename) +% Extract a matrix representation, node labels, and node position coordinates +% from a file in GraphViz format http://www.research.att.com/sw/tools/graphviz +% +% INPUTS: +% 'filename' - the file in DOT format containing the graph layout. +% OUTPUT: +% 'Adj' - an adjacency matrix representation of the graph in 'filename'; +% 'labels' - a character array with the names of the nodes of the graph; +% 'x' - a row vector with the x-coordinates of the nodes in 'filename'; +% 'y' - a row vector with the y-coordinates of the nodes in 'filename'. +% +% WARNINGS: not guaranted to parse ANY GraphViz file. Debugged on undirected +% sample graphs from GraphViz(Heawood, Petersen, ER, ngk10_4, process). +% Complaines about RecursionLimit set only to 500 on huge graphs. +% Ignores singletons (disjoint nodes). +% Sample DOT code "ABC.dot", read by [Adj, labels, x, y] = dot_to_graph('ABC.dot') +% digraph G { +% A [pos="28,31"]; +% B [pos="74,87"]; +% A -- B [pos="e,61,71 41,47 46,53 50,58 55,64"]; +% } +% last modified: Jan 2004 +% by Alexi Savov: asavov @wustl.edu | http://artsci.wustl.edu/~azsavov +% Leon Peshkin: pesha @ai.mit.edu | http://www.ai.mit.edu/~pesha +% Tom Minka + +if ~exist(filename) % Checks whether the specified file exists. + error('* * * File does not exist or could not be found. * * *'); +end; + +lines = textread(filename,'%s','delimiter','\n','commentstyle','c'); % Read file into cell array +dot_lines = strvcat(lines); % of lines, ignoring C-style comments + +if findstr(dot_lines(1,:), 'graph ') == [] % Is this a DOT file ? + error('* * * File does not appear to be in valid DOT format. * * *'); +end; + +Nlns = size(dot_lines,1); % The number of lines; +nodes = {}; +unread = 1:Nlns; % 'unread' list of lines which has not been examined yet +edge_id = 1; +Adj = []; +for line_ndx = 1:Nlns % This section sets the adjacency matrix A(Lnode,Rnode) = edge_id. + line = dot_lines(line_ndx,:); + Ddash_pos = strfind(line, ' -- ') + 1; % double dash positions + arrow_pos = strfind(line, ' -> ') + 1; % arrow dash positions + tokens = strread(line,'%s','delimiter',' "'); + left_bound = 1; + for dash_pos = [Ddash_pos arrow_pos]; % if empty - not a POS line + Lnode = sscanf(line(left_bound:dash_pos -2), '%s'); + Rnode = sscanf(line(dash_pos +3 : length(line)-1),'%s',1); + Lndx = strmatch(Lnode, nodes, 'exact'); + Rndx = strmatch(Rnode, nodes, 'exact'); + if isempty(Lndx) % extend our list of nodes + nodes{end+1} = Lnode; + Lndx = length(nodes); + end + if isempty(Rndx) + nodes{end+1} = Rnode; + Rndx = length(nodes); + end + Adj(Lndx, Rndx) = edge_id; + if ismember(dash_pos, Ddash_pos) % The edge is undirected, A(Rndx,LndxL) is also set to 1; + Adj(Rndx, Lndx) = edge_id; + end + edge_id = edge_id + 1; + left_bound = dash_pos + 3; + unread = setdiff(unread, line_ndx); + end +end +Nvrt = length(nodes); % number of vertices we found [Do we ever have singleton vertices ???] +% nodes = strvcat(nodes); % convert to the searchable array +x = zeros(1, Nvrt); +y = zeros(1, Nvrt); +labels = nodes; +% Find node's position coordinates if they are contained in 'filename'. +for line_ndx = unread % Look for node's coordinates among the 'unread' lines. + line = dot_lines(line_ndx,:); + bra_pos = strfind(line, '['); % has to have "[" if it has the label + lst_node = 0; + for node = 1:Nvrt % look through the list of nodes + % THE NEXT STATEMENT we assume no node is substring of any other node + lbl_pos = strfind(line, nodes{node}); + if (~isempty(lbl_pos) & ~isempty(bra_pos) & (x(node) == 0)) % make sure we have not seen it + if (lbl_pos(1) < bra_pos(1)) % label has to be to the left of bracket + lst_node = node; + end + end + end + if lst_node + pos_pos = strfind(line, 'pos'); % position of the "pos" + if ~isempty(pos_pos) % this line contains SOME position + [node_pos] = sscanf(line(pos_pos:end), ' pos = "%d,%d"')'; + x(lst_node) = node_pos(1); + y(lst_node) = node_pos(2); + end + % minka + label_pos = strfind(line, 'label'); % position of the "label" + if ~isempty(label_pos) + label_end = strfind(line(label_pos:end),','); + labels{lst_node} = unquote(line(label_pos+(6:label_end(1)-2))); + end + end +end + +if (isempty(find(x)) & (nargout > 2)) % If coordinates were requested, but not found in 'filename'. + warning('File does not contain node coordinates.'); +end; +if ~(size(Adj,1)==size(Adj,2)) % Make sure Adj is a square matrix. ? + Adj = eye(max(size(Adj)),size(Adj,1))*Adj*eye(size(Adj,2),max(size(Adj))); +end; +x = .9*(x-min(x))/range(x)+.05; % normalise and push off margins +y = .9*(y-min(y))/range(y)+.05; + + + +function s = unquote(s) + +s = strrep(s,'"',''); diff --git a/sourcecodes/bnt-master/GraphViz/draw_dbn.m b/sourcecodes/bnt-master/GraphViz/draw_dbn.m new file mode 100644 index 00000000..89bf2b13 --- /dev/null +++ b/sourcecodes/bnt-master/GraphViz/draw_dbn.m @@ -0,0 +1,99 @@ +function [x, y, h] = draw_dbn(adj, inter, flip_intra, K, labels, node_t, x, y) +% DRAW_LAYOUT_DBN Draws a layout for a Dynamical Belief Network +% +% [<X1, Y1, X2, Y2>] = DRAW_LAYOUT_DBN(INTRA, INTER, <FLIP_FLAG, K, LABELS, ISBOX, X1, Y1>) +% +% Inputs : +% INTRA, INTER : Adjacency matrices +% FLIP_FLAG : Transposes the DAG layout obtained from INTRA connections +% If X1, Y1 are specified, FLIP_FLAG has no effect. +% K : Unfold K times <Default = 2> +% LABELS - if -1, we use 1:N*K +% Rest : See DRAW_LAYOUT +% +% Outputs : +% Xi, Yi : Coordinates of nodes (for i'th timeslice) on the unit square +% H : Object Handles +% +% Usage Example : draw_layout_dbn(intra, inter, 1); +% draw_layout_dbn(intra, inter); +% +% Note : +% See also DRAW_GRAPH + +% Uses : DRAW_GRAPH + +% Change History : +% Date Time Prog Note +% 17-Apr-2000 1:02 PM ATC Created under MATLAB 5.3.1.29215a (R11.1) + +% ATC = Ali Taylan Cemgil, +% SNN - University of Nijmegen, Department of Medical Physics and Biophysics +% e-mail : cemgil@mbfys.kun.nl + +N = size(adj,1); +if nargin<3, + flip_intra = 0; +end; + +if nargin<4, + K = 2; +end; + +if K<2 | K>7, error('2<=K<=7 must hold..'); end; + + +if nargin<5 +% labels = cellstr(char(zeros(N,1)+double('+'))); +% labels = cellstr(int2str((1:N)')); + labels = cellstr(char((0:N-1)'+double('a'))); +end; + +if nargin<6, + node_t = zeros(N,1); +% node_t = rand(N,1) > 0.5; +end; + +if nargin<7, + [x1 y1] = make_layout(adj); + if flip_intra, tmp = x1; x1 = y1; y1 = tmp; end; +end; + +mid = round(K/2); + + +xi = x1(:)-1; +x = []; +y = repmat(y1(:), [K 1]); +node_t2 = repmat(node_t(:), [K 1]); + +if isa(labels,'double') & labels==-1 % KPM + lb = num2strcell(1:N*K); +else + lb = {}; + for i=1:K, + labels1 = labels(:); + if i==mid, str = ''; else str = sprintf('%+d',i-mid); end; + for i=1:N, + labels1{i} = [labels1{i} '(t' str ')']; + end; + lb = [lb; labels1(:)]; + end; +end + +dag = zeros(N*K); + +for i=1:K, + xi = xi+1; + x = [x; xi]; + + idx = ((i-1)*N+1):i*N; + dag(idx,idx) = adj; + if i<K, + dag(idx,idx+N) = inter; + end; +end; + +[x, y, h] = draw_graph(dag, lb, node_t2, x/K, y); + + diff --git a/sourcecodes/bnt-master/GraphViz/draw_dbn_test.m b/sourcecodes/bnt-master/GraphViz/draw_dbn_test.m new file mode 100644 index 00000000..7d7c2367 --- /dev/null +++ b/sourcecodes/bnt-master/GraphViz/draw_dbn_test.m @@ -0,0 +1,68 @@ +% TEST_LAYOUT_DBN Script to test some DBN layouts +% + +% Change History : +% Date Time Prog Note +% 17-Apr-2000 2:40 PM ATC Created under MATLAB 5.3.1.29215a (R11.1) + +% ATC = Ali Taylan Cemgil, +% SNN - University of Nijmegen, Department of Medical Physics and Biophysics +% e-mail : cemgil@mbfys.kun.nl + +disp('draw mhmm1') +clf +set(gcf, 'pos', [0 0 1024 600]); + +intra = zeros(3); +intra(1,[2 3]) = 1; +intra(2,3) = 1; +inter = zeros(3); +inter(1,1) = 1; +n = 3; +dnodes = [1 2]; +isbox = zeros(n,1); isbox(dnodes) = 1; +unfold = 4; +draw_dbn(intra, inter, 0, unfold, {'Q', 'M', 'Y'}, isbox); + + +pause +clf +disp('draw water1') +bnet = mk_water_dbn; +unfold = 3; +flip = 1; +[dummyx, dummyy, h] = draw_dbn(bnet.intra, bnet.inter, flip, unfold); + +col = rand(size(h,1),3); +for i=1:length(h), + col = rand(1,3); + % patches + set(h(i,2),'facecolor', col); drawnow; + % text + set(h(i,1),'color', 1-col); drawnow; +end; + + +pause +clf +disp('draw BAT static') +% This requires BNT + +%sz = get(0, 'ScreenSize'); +%sv = get(gcf, 'pos'); +%set(gcf, 'units','pix','pos', sz); +[bnet, names] = mk_bat_dbn; +N = size(bnet.intra,1); +G = [bnet.intra bnet.inter; + zeros(N,N) bnet.intra]; +names2 = names; +for i=1:N + names2{i} = sprintf('%s(1)', names{i}); + names2{i+N} = sprintf('%s(2)', names{i}); +end +draw_graph(G, names2); + +pause +disp('draw bat dbn') +clf +draw_dbn(bnet.intra, bnet.inter, 0, 2, names2); diff --git a/sourcecodes/bnt-master/GraphViz/draw_dot.m b/sourcecodes/bnt-master/GraphViz/draw_dot.m new file mode 100644 index 00000000..9624172c --- /dev/null +++ b/sourcecodes/bnt-master/GraphViz/draw_dot.m @@ -0,0 +1,124 @@ +function draw_dot(adj,varargin); +%DRAW_DOT Draw a graph. +% DRAW_DOT(ADJ) plots the graph ADJ in the current figure window, using +% 'neato' to optimize the layout. +% +% Optional arguments can be passed as name/value pairs: [default] +% +% 'isbox' - a vector specifying which nodes should be boxed [0] +% 'rotate' - rotate the graph so that nodes are vertically aligned [1] +% 'tolerance' - alignment tolerance for 'rotate' [0.001] +% 'start' - a random seed (to select different solutions) +% 'options' - a string of command-line options for 'neato' [''] +% All of the optional arguments to graph_to_dot are also supported, such as +% 'node_label'. +% +% See also GRAPH_TO_DOT. +% +% Example: +% size=15; Adj = rand(size) > .8; +% Adj2 = triu(Adj,1)+ triu(Adj,1)' + diag(zeros(size,1)); +% draw_dot(Adj2) + +% Original: Leon Peshkin +% Modified by Tom Minka + +% minka +N = size(adj,1); +unique_labels = cellstr(num2str((1:N)','%-1d')); +labels = unique_labels; +isbox = zeros(N,1); +rotate_flag = 1; +tolerance = 0.001; +options = ''; +for i = 1:2:length(varargin) + switch varargin{i} + case 'node_label', labels = varargin{i+1}; + % replace with unique labels + varargin{i+1} = unique_labels; + case 'isbox', isbox = varargin{i+1}; + case 'rotate', rotate_flag = varargin{i+1}; + case 'tolerance', tolerance = varargin{i+1}; + case 'start', start = varargin{i+1}; + options = [options ' -Gstart=' num2str(start)]; + case 'options', options = [options ' ' varargin{i+1}]; + end +end + +if ispc, shell = 'dos'; else, shell = 'unix'; end % Which OS ? + +cmdline = strcat(shell,'(''neato -V'')'); +status = eval(cmdline); +%[status, result] = dos('neato -V'); % request version to check NEATO +if status == 1, fprintf('Complaining \n'); exit, end + +tmpDOTfile = '_GtDout.dot'; % to be platform independant no use of directories +tmpLAYOUT = '_LAYout.dot'; +graph_to_dot(adj > 0, 'filename', tmpDOTfile, 'node_label', unique_labels, varargin{:}); % save in file + +cmdline = strcat([shell '(''neato -Tdot ' tmpDOTfile options ' -o ' tmpLAYOUT ''')']); % preserve trailing spaces +status = eval(cmdline); % get NEATO todo layout + +[adj, permuted_labels, x, y] = dot_to_graph(tmpLAYOUT); % load layout +delete(tmpLAYOUT); delete(tmpDOTfile); % clean up temporary files + +% permute the original arguments to match permuted_labels. +order = []; +for i = 1:length(permuted_labels) + j = strmatch(permuted_labels{i},unique_labels,'exact'); + order(i) = j(1); +end +labels = labels(order); +isbox = isbox(order); +if rotate_flag + [x,y] = best_rotation(x,y,tolerance); +end + +figure(1); clf; axis square % now plot +[x, y, h] = draw_graph(adj>0, labels, isbox, x, y, varargin{:}); + + +function [x,y] = best_rotation(x,y,h) +% Rotate the points to maximize the horizontal and vertical alignment. +% Written by Tom Minka. + +xm = mean(x); +ym = mean(y); +xr = max(x)-min(x); +yr = max(y)-min(y); +x = (x-xm)/xr; +y = (y-ym)/yr; + +xy = [x(:) y(:)]; +if 1 + angle = fminbnd(@rotation_cost,-pi/4,pi/4,[],xy,h); +else + angles = linspace(-pi/4,pi/4,40); + e = []; + for i = 1:length(angles) + e(i) = rotation_cost(angles(i),xy,h); + end + %figure(2) + %plot(angles*180/pi,e) + angle = angles(argmin(e)); +end +%angle*180/pi +c = cos(angle); s = sin(angle); +xy = xy*[c s; -s c]; + +x = xy(:,1)*xr+xm; +y = xy(:,2)*yr+ym; + + +function e = rotation_cost(angle,xy,h) +% xy is 2-column matrix. +% e is small if many x's and y's are aligned. + +c = cos(angle); s = sin(angle); +xy = xy*[c s; -s c]; +dx = sqdist(xy(:,1)',xy(:,1)'); +dy = sqdist(xy(:,2)',xy(:,2)'); +dx = setdiag(dx,Inf); +dy = setdiag(dy,Inf); +e = sum(exp(-dx(:)/h))+sum(exp(-dy(:)/h)); +e = -e; diff --git a/sourcecodes/bnt-master/GraphViz/draw_graph.m b/sourcecodes/bnt-master/GraphViz/draw_graph.m new file mode 100644 index 00000000..be9a5b5b --- /dev/null +++ b/sourcecodes/bnt-master/GraphViz/draw_graph.m @@ -0,0 +1,335 @@ +function [x, y, h] = draw_graph(adj, labels, node_t, x, y, varargin) +% DRAW_LAYOUT Draws a layout for a graph +% +% [X, Y, H] = DRAW_LAYOUT(ADJ, <LABELS, ISBOX, X, Y>) +% +% Inputs : +% ADJ : Adjacency matrix (source, sink) +% LABELS : Cell array containing labels <Default : '1':'N'> +% ISBOX : 1 if node is a box, 0 if oval <Default : zeros> +% X, Y, : Coordinates of nodes on the unit square <Default : calls make_layout> +% +% Outputs : +% X, Y : Coordinates of nodes on the unit square +% H : Object handles +% +% Usage Example : [x, y] = draw_layout([0 1;0 0], {'Hidden','Visible'}, [1 0]'); +% +% h(i,1) is the text handle - color +% h(i,2) is the circle handle - facecolor +% +% See also MAKE_LAYOUT + +% Change History : +% Date Time Prog Note +% 13-Apr-2000 9:06 PM ATC Created under MATLAB 5.3.1.29215a (R11.1) +% +% ATC = Ali Taylan Cemgil, +% SNN - University of Nijmegen, Department of Medical Physics and Biophysics +% e-mail : cemgil@mbfys.kun.nl + +adj = double(adj); +N = size(adj,1); +if nargin<2, + labels = cellstr(int2str((1:N)')); +end + +if nargin<3, + node_t = zeros(N,1); +else + node_t = node_t(:); +end; + +axis([0 1 0 1]); +set(gca,'XTick',[],'YTick',[],'box','on'); +% axis('square'); +%colormap(flipud(gray)); + +if nargin<4, + [x y] = make_layout(adj); +end; + +idx1 = find(node_t==0); h1 = []; wd1=[]; +if ~isempty(idx1) + [h1 wd1] = textoval(x(idx1), y(idx1), labels(idx1), varargin{:}); +end; + +idx2 = find(node_t~=0); h2 = []; wd2 = []; +if ~isempty(idx2) + [h2 wd2] = textbox(x(idx2), y(idx2), labels(idx2), varargin{:}); +end; + +wd = zeros(size(wd1,1)+size(wd2,1),2); +if ~isempty(idx1), wd(idx1, :) = wd1; end; +if ~isempty(idx2), wd(idx2, :) = wd2; end; + +% coloring +color.box = 'black'; +color.text = color.box; +color.edge = [1 1 1]*3/4; +%color.edge = 'green'; +if ~isempty(idx1) + set(h1(:,1),'Color',color.text) + set(h1(:,2),'EdgeColor',color.box) +end +if ~isempty(idx2) + set(h2(:,1),'Color',color.text) + set(h2(:,2),'EdgeColor',color.box) +end + +% bug: this code assumes [x y] is the center of each box and oval, which +% isn't exactly true. +h_edge = []; +for i=1:N, + j = find(adj(i,:)==1); + for k=j, + if x(k)-x(i)==0, + sign = 1; + if y(i)>y(k), alpha = -pi/2; else alpha = pi/2; end; + else + alpha = atan((y(k)-y(i))/(x(k)-x(i))); + if x(i)<x(k), sign = 1; else sign = -1; end; + end; + dy1 = sign.*wd(i,2).*sin(alpha); dx1 = sign.*wd(i,1).*cos(alpha); + dy2 = sign.*wd(k,2).*sin(alpha); dx2 = sign.*wd(k,1).*cos(alpha); + if adj(k,i)==0, % if directed edge + h = arrow([x(i)+dx1 y(i)+dy1],[x(k)-dx2 y(k)-dy2],'BaseAngle',30); + set(h, 'FaceColor', color.edge) + set(h, 'EdgeColor', color.edge) + else + h = line([x(i)+dx1 x(k)-dx2],[y(i)+dy1 y(k)-dy2]); + set(h, 'Color', color.edge) + adj(k,i)=-1; % Prevent drawing lines twice + end; + h_edge = [h_edge h]; + end; +end; + +if nargout>2, + h = zeros(length(wd),2); + if ~isempty(idx1), + h(idx1,:) = h1; + end; + if ~isempty(idx2), + h(idx2,:) = h2; + end; +end; + +%%%%% + +function [t, wd] = textoval(x, y, str, varargin) +% TEXTOVAL Draws an oval around text objects +% +% [T, WIDTH] = TEXTOVAL(X, Y, STR) +% [..] = TEXTOVAL(STR) % Interactive +% +% Inputs : +% X, Y : Coordinates +% TXT : Strings +% +% Outputs : +% T : Object Handles +% WIDTH : x and y Width of ovals +% +% Usage Example : [t] = textoval('Visit to Asia?'); +% +% +% Note : +% See also TEXTBOX + +% Uses : + +% Change History : +% Date Time Prog Note +% 15-Jun-1998 10:36 AM ATC Created under MATLAB 5.1.0.421 +% 12-Mar-2004 10:00 AM minka Changed placement/sizing. +% +% ATC = Ali Taylan Cemgil, +% SNN - University of Nijmegen, Department of Medical Physics and Biophysics +% e-mail : cemgil@mbfys.kun.nl + +temp = []; +textProperties = {'BackgroundColor','Color','FontAngle','FontName','FontSize','FontUnits','FontWeight','Rotation'}; +varargin = argfilter(varargin,textProperties); + +if nargin == 1 + str = x; +end +if ~isa(str,'cell') str=cellstr(str); end; +N = length(str); +wd = zeros(N,2); +for i=1:N, + if nargin == 1 + [x, y] = ginput(1); + end + tx = text(x(i),y(i),str{i},'HorizontalAlignment','center',varargin{:}); + % minka + [ptc wx wy] = draw_oval(tx); + wd(i,:) = [wx wy]; + % draw_oval will paint over the text, so need to redraw it + delete(tx); + tx = text(x(i),y(i),str{i},'HorizontalAlignment','center',varargin{:}); + temp = [temp; tx ptc]; +end +if nargout>0, t = temp; end; + +%%%%%%%%% + + +function [ptc, wx, wy] = draw_oval(tx, x, y) +% Draws an oval box around a tex object +sz = get(tx,'Extent'); +% minka +wy = 2/3*sz(4); +wx = 2/3*sz(3); +x = sz(1)+sz(3)/2; +y = sz(2)+sz(4)/2; +ptc = ellipse(x, y, wx, wy); +set(ptc, 'FaceColor','w'); + + +%%%%%%%%%%%%% + +function [p] = ellipse(x, y, rx, ry, c) +% ELLIPSE Draws Ellipse shaped patch objects +% +% [<P>] = ELLIPSE(X, Y, Rx, Ry, C) +% +% Inputs : +% X : N x 1 vector of x coordinates +% Y : N x 1 vector of y coordinates +% Rx, Ry : Radii +% C : Color index +% +% +% Outputs : +% P = Handles of Ellipse shaped path objects +% +% Usage Example : [] = ellipse(); +% +% +% Note : +% See also + +% Uses : + +% Change History : +% Date Time Prog Note +% 27-May-1998 9:55 AM ATC Created under MATLAB 5.1.0.421 + +% ATC = Ali Taylan Cemgil, +% SNN - University of Nijmegen, Department of Medical Physics and Biophysics +% e-mail : cemgil@mbfys.kun.nl + +if (nargin < 2) error('Usage Example : e = ellipse([0 1],[0 -1],[1 0.5],[2 0.5]); '); end; +if (nargin < 3) rx = 0.1; end; +if (nargin < 4) ry = rx; end; +if (nargin < 5) c = 1; end; + +if length(c)==1, c = ones(size(x)).*c; end; +if length(rx)==1, rx = ones(size(x)).*rx; end; +if length(ry)==1, ry = ones(size(x)).*ry; end; + +n = length(x); +p = zeros(size(x)); +t = 0:pi/30:2*pi; +for i=1:n, + px = rx(i)*cos(t)+x(i); + py = ry(i)*sin(t)+y(i); + p(i) = patch(px,py,c(i)); +end; + +if nargout>0, pp = p; end; + +%%%%% + +function [t, wd] = textbox(x,y,str,varargin) +% TEXTBOX Draws A Box around the text +% +% [T, WIDTH] = TEXTBOX(X, Y, STR) +% [..] = TEXTBOX(STR) +% +% Inputs : +% X, Y : Coordinates +% TXT : Strings +% +% Outputs : +% T : Object Handles +% WIDTH : x and y Width of boxes +%% +% Usage Example : t = textbox({'Ali','Veli','49','50'}); +% +% +% Note : +% See also TEXTOVAL + +% Uses : + +% Change History : +% Date Time Prog Note +% 09-Jun-1998 11:43 AM ATC Created under MATLAB 5.1.0.421 +% 12-Mar-2004 10:00 AM minka Changed placement/sizing. +% +% ATC = Ali Taylan Cemgil, +% SNN - University of Nijmegen, Department of Medical Physics and Biophysics +% e-mail : cemgil@mbfys.kun.nl + +temp = []; +textProperties = {'BackgroundColor','Color','FontAngle','FontName','FontSize','FontUnits','FontWeight','Rotation'}; +varargin = argfilter(varargin,textProperties); + +if nargin == 1 + str = x; +end +if ~isa(str,'cell') str=cellstr(str); end; +N = length(str); +wd = zeros(N,2); +for i=1:N, + if nargin == 1 + [x, y] = ginput(1); + end + tx = text(x(i),y(i),str{i},'HorizontalAlignment','center',varargin{:}); + % minka + [ptc wx wy] = draw_box(tx); + wd(i,:) = [wx wy]; + % draw_box will paint over the text, so need to redraw it + delete(tx); + tx = text(x(i),y(i),str{i},'HorizontalAlignment','center',varargin{:}); + temp = [temp; tx ptc]; +end; + +if nargout>0, t = temp; end; + + +function [ptc, wx, wy] = draw_box(tx) +% Draws a box around a text object +sz = get(tx,'Extent'); +% minka +wy = 1/2*sz(4); +wx = 1/2*sz(3); +x = sz(1)+sz(3)/2; +y = sz(2)+sz(4)/2; +ptc = patch([x-wx x+wx x+wx x-wx], [y+wy y+wy y-wy y-wy],'w'); +set(ptc, 'FaceColor','w'); + + + +function args = argfilter(args,keep) +%ARGFILTER Remove unwanted arguments. +% ARGFILTER(ARGS,KEEP), where ARGS = {'arg1',value1,'arg2',value2,...}, +% returns a new argument list where only the arguments named in KEEP are +% retained. KEEP is a character array or cell array of strings. + +% Written by Tom Minka + +if ischar(keep) + keep = cellstr(keep); +end +i = 1; +while i < length(args) + if ~ismember(args{i},keep) + args = args(setdiff(1:length(args),[i i+1])); + else + i = i + 2; + end +end diff --git a/sourcecodes/bnt-master/GraphViz/draw_graph_test.m b/sourcecodes/bnt-master/GraphViz/draw_graph_test.m new file mode 100644 index 00000000..0d3aa186 --- /dev/null +++ b/sourcecodes/bnt-master/GraphViz/draw_graph_test.m @@ -0,0 +1,50 @@ +% TEST_LAYOUT Script to test some bayesian net layouts +% + +% Change History : +% Date Time Prog Note +% 13-Apr-2000 10:40 PM ATC Created under MATLAB 5.3.1.29215a (R11.1) + +% ATC = Ali Taylan Cemgil, +% SNN - University of Nijmegen, Department of Medical Physics and Biophysics +% e-mail : cemgil@mbfys.kun.nl + +%bnet = mk_asia_bnet; +%draw_graph(bnet.dag); + +% Make the following network (from Jensen (1996) p84 fig 4.17) +% 1 +% / | \ +% 2 3 4 +% | | | +% 5 6 7 +% \/ \/ +% 8 9 +% where all arcs point downwards + +disp('plot directed') +clf; + +N = 9; +dag = zeros(N,N); +dag(1,2)=1; dag(1,3)=1; dag(1,4)=1; +dag(2,5)=1; dag(3,6)=1; dag(4,7)=1; +dag(5,8)=1; dag(6,8)=1; dag(6,9)=1; dag(7,9) = 1; + +draw_graph(dag); + +pause +clf +disp('plot undirected') +udag = [dag+dag']; +draw_graph(udag); + +pause +clf +disp('plot mixed') +mg = [dag]; +mg(2,1) = 1; mg(8,5) = 1; +draw_graph(mg); + + + diff --git a/sourcecodes/bnt-master/GraphViz/draw_hmm.m b/sourcecodes/bnt-master/GraphViz/draw_hmm.m new file mode 100644 index 00000000..e517789c --- /dev/null +++ b/sourcecodes/bnt-master/GraphViz/draw_hmm.m @@ -0,0 +1,117 @@ +function draw_hmm(A, varargin) +% DRAW_HMM Make a picture of the HMM using dotty +% function draw_hmm(A, ...) +% +% For details on dotty, see http://www.research.att.com/sw/tools/graphviz +% +% If A(i,j) > thresh, we draw and arc from state i to state j. +% +% Optional arguments (name/value pairs) [default] +% +% thresh - [1e-1] +% obsprob - If B(i,o) > 0, we include "o" in the name of state i. +% e.g., if state 5 emits 1,3,7, its label becomes "5: 1 3 7". +% startprob - ifstartprob(i) > 0, the state name will be prefixed with "+". +% endprob - if endprob(i) > 0, the state name will be appended with "-". +% filename - if [], we write to 'tmp.dot', convert this to 'tmp.ps' +% using 'dot -Tps tmp.dot -o tmp.ps', and then call ghostview to display the result. +% dot and gv must be on your system path. +% If filename ~= [], we just generate the dot file, and do not +% convert it to postscript or call ghostview. + +[thresh, B, startprob, endprob, filename] = ... + process_options(varargin, 'thresh', 1e-1, 'obsprob', [], 'startprob', [], 'endprob', [], ... + 'filename', []); + +Q = length(A); + +arclabel = cell(Q,Q); +G = zeros(Q,Q); +for i=1:Q + for j=1:Q + if A(i,j) < thresh + arclabel{i,j} = ''; + else + G(i,j) = 1; + arclabel{i,j} = sprintf('%5.3f', A(i,j)); + end + end +end + + +nodelabel = cell(1,Q); +for i=1:Q + % annotate start/stop states + if ~isempty(startprob) & ~approxeq(startprob(i), 0) + start = '+'; + else + start = ''; + end + if ~isempty(endprob) & ~approxeq(hmm.endprob(i), 0) + stop = '-'; + else + stop = ''; + end + label = sprintf('%s%d%s :', start, i, stop); + + if ~isempty(B) + output_label = mk_output_label(B); + label = strcat(label, output_label); + end + + nodelabel{i} = label; +end + + +if isempty(filename) + filename = 'tmp.dot'; + %mkdot(G, filename, arclabel, nodelabel) + graph_to_dot(G, 'filename', filename, 'arc_label', arclabel, 'node_label', nodelabel); + fprintf('converting from .ps to .dot\n') + !dot -Tps tmp.dot -o tmp.ps + !gv tmp.ps & +else + graph_to_dot(G, 'filename', filename, 'arc_label', arclabel, 'node_label', nodelabel); + %mkdot(G, filename, arclabel, nodelabel) +end + + +%%%%%%%%% + +function label = mk_output_label(B) + +[Q O] = size(B); +label = ''; + +if 0 + % print most probable symbols + for i=1:Q + m = max(B(i,:)); + ndx = find(abs(B(i,:) - repmat(m,1,O)) < 1e-2); + %ndx = find(B(i,:)==m); + %label = sprintf('%d,', ndx); + end +end + +if 0 + % print prob distrib over all symbols + for o=1:O + if approxeq(B(i,o), 0) + % + else + label = strcat(label, sprintf('%d(%3.2f),', o, B(i,o))); + end + end +end + +if 1 + % print all non-zero symbols + chars = ['a' 'b' 'c']; + for o=1:O + if approxeq(B(i,o), 0) + % + else + label = strcat(label, sprintf('%s', chars(o))); + end + end +end diff --git a/sourcecodes/bnt-master/GraphViz/editGraphGUI.m b/sourcecodes/bnt-master/GraphViz/editGraphGUI.m new file mode 100644 index 00000000..45de6497 --- /dev/null +++ b/sourcecodes/bnt-master/GraphViz/editGraphGUI.m @@ -0,0 +1,16 @@ +function g +%here is how one creates a function ("callback") which does something +%(prints the node label) when you click on the node's text in Matlab figure. +% +% Leon Peshkin http://www.ai.mit.edu/~pesha +% +%draw_graph(...) + + % "gca" is the current "axes" object, parent of all objects in figure + % "gcbo" is the handle of the object whose callback is being executed + % "findall" gives handles to all elements of a given type in the figure +text_elms = findall(gca,'Type','text'); +for ndx = 1:length(text_elms) + callbk = 'my_call(str2num(get(gcbo,''String'')))'; + set(text_elms(ndx), 'ButtonDownFcn', callbk); % assume the node label is a number +end diff --git a/sourcecodes/bnt-master/GraphViz/graph_to_dot.m b/sourcecodes/bnt-master/GraphViz/graph_to_dot.m new file mode 100644 index 00000000..c9f692d1 --- /dev/null +++ b/sourcecodes/bnt-master/GraphViz/graph_to_dot.m @@ -0,0 +1,86 @@ +function graph_to_dot(adj, varargin) +%GRAPH_TO_DOT Makes a GraphViz (AT&T) file representing an adjacency matrix +% graph_to_dot(adj, ...) writes to the specified filename. +% +% Optional arguments can be passed as name/value pairs: [default] +% +% 'filename' - if omitted, writes to 'tmp.dot' +% 'arc_label' - arc_label{i,j} is a string attached to the i-j arc [""] +% 'node_label' - node_label{i} is a string attached to the node i ["i"] +% 'width' - width in inches [10] +% 'height' - height in inches [10] +% 'leftright' - 1 means layout left-to-right, 0 means top-to-bottom [0] +% 'directed' - 1 means use directed arcs, 0 means undirected [1] +% +% For details on graphviz, See http://www.research.att.com/sw/tools/graphviz +% +% See also dot_to_graph and draw_dot. + +% First version written by Kevin Murphy 2002. +% Modified by Leon Peshkin, Jan 2004. +% Bugfix by Tom Minka, Mar 2004. + +node_label = []; arc_label = []; % set default args +width = 10; height = 10; +leftright = 0; directed = 1; filename = 'tmp.dot'; + +for i = 1:2:nargin-1 % get optional args + switch varargin{i} + case 'filename', filename = varargin{i+1}; + case 'node_label', node_label = varargin{i+1}; + case 'arc_label', arc_label = varargin{i+1}; + case 'width', width = varargin{i+1}; + case 'height', height = varargin{i+1}; + case 'leftright', leftright = varargin{i+1}; + case 'directed', directed = varargin{i+1}; + end +end +% minka +if ~directed + adj = triu(adj | adj'); +end + +fid = fopen(filename, 'w'); +if directed + fprintf(fid, 'digraph G {\n'); + arctxt = '->'; + if isempty(arc_label) + labeltxt = ''; + else + labeltxt = '[label="%s"]'; + end +else + fprintf(fid, 'graph G {\n'); + arctxt = '--'; + if isempty(arc_label) + labeltxt = '[dir=none]'; + else + labeltext = '[label="%s",dir=none]'; + end +end +edgeformat = strcat(['%d ',arctxt,' %d ',labeltxt,';\n']); +fprintf(fid, 'center = 1;\n'); +fprintf(fid, 'size=\"%d,%d\";\n', width, height); +if leftright + fprintf(fid, 'rankdir=LR;\n'); +end +Nnds = length(adj); +for node = 1:Nnds % process nodes + if isempty(node_label) + fprintf(fid, '%d;\n', node); + else + fprintf(fid, '%d [ label = "%s" ];\n', node, node_label{node}); + end +end +for node1 = 1:Nnds % process edges + arcs = find(adj(node1,:)); % children(adj, node); + for node2 = arcs + if ~isempty(arc_label) + fprintf(fid, edgeformat,node1,node2,arc_label{node1,node2}); + else + fprintf(fid, edgeformat, node1, node2); + end + end +end +fprintf(fid, '}'); +fclose(fid); diff --git a/sourcecodes/bnt-master/GraphViz/make_layout.m b/sourcecodes/bnt-master/GraphViz/make_layout.m new file mode 100644 index 00000000..69740b76 --- /dev/null +++ b/sourcecodes/bnt-master/GraphViz/make_layout.m @@ -0,0 +1,172 @@ +function [x, y] = make_layout(adj) + +%function [x, y] = layout_dag(adj) +% MAKE_LAYOUT Creates a layout from an adjacency matrix +% +% [X, Y] = MAKE_LAYOUT(ADJ) +% +% Inputs : +% ADJ = adjacency matrix (source, sink) +% +% Outputs : +% X, Y : Positions of nodes +% +% Usage Example : [X, Y] = make_layout(adj); +% +% +% Note : Uses some very simple heuristics, so any other +% algorithm would create a nicer layout +% +% See also + +% Uses : + +% Change History : +% Date Time Prog Note +% 13-Apr-2000 8:25 PM ATC Created under MATLAB 5.3.1.29215a (R11.1) + +% ATC = Ali Taylan Cemgil, +% SNN - University of Nijmegen, Department of Medical Physics and Biophysics +% e-mail : cemgil@mbfys.kun.nl + +N = size(adj,1); +tps = toposort(adj); + +if ~isempty(tps), % is directed ? + level = zeros(1,N); + for i=tps, + idx = find(adj(:,i)); + if ~isempty(idx), + l = max(level(idx)); + level(i)=l+1; + end; + end; +else + level = poset(adj,1)'-1; +end; + +y = (level+1)./(max(level)+2); +y = 1-y; +x = zeros(size(y)); +for i=0:max(level), + idx = find(level==i); + offset = (rem(i,2)-0.5)/10; + x(idx) = (1:length(idx))./(length(idx)+1)+offset; +end; + +%%%%%%% + +function [depth] = poset(adj, root) +% POSET Identify a partial ordering among the nodes of a graph +% +% [DEPTH] = POSET(ADJ,ROOT) +% +% Inputs : +% ADJ : Adjacency Matrix +% ROOT : Node to start with +% +% Outputs : +% DEPTH : Depth of the Node +% +% Usage Example : [depth] = poset(adj,12); +% +% +% Note : All Nodes must be connected +% See also + +% Uses : + +% Change History : +% Date Time Prog Note +% 17-Jun-1998 12:01 PM ATC Created under MATLAB 5.1.0.421 + +% ATC = Ali Taylan Cemgil, +% SNN - University of Nijmegen, Department of Medical Physics and Biophysics +% e-mail : cemgil@mbfys.kun.nl + +adj = adj+adj'; + +N = size(adj,1); +depth = zeros(N,1); +depth(root) = 1; +queue = root; + +while 1, + if isempty(queue), + if all(depth), break; + else + root = find(depth==0); + root = root(1); + depth(root) = 1; + queue = root; + end; + end; + r = queue(1); queue(1) = []; + idx = find(adj(r,:)); + idx2 = find(~depth(idx)); + idx = idx(idx2); + queue = [queue idx]; + depth(idx) = depth(r)+1; +end; + +%%%%%%%%% + +function [seq] = toposort(adj) +% TOPOSORT A Topological ordering of nodes in a directed graph +% +% [SEQ] = TOPOSORT(ADJ) +% +% Inputs : +% ADJ : Adjacency Matrix. +% ADJ(i,j)==1 ==> there exists a directed edge +% from i to j +% +% Outputs : +% SEQ : A topological ordered sequence of nodes. +% empty matrix if graph contains cycles. +% +% Usage Example : +% N=5; +% [l,u] = lu(rand(N)); +% adj = ~diag(ones(1,N)) & u>0.5; +% seq = toposort(adj); +% +% +% Note : +% See also + +% Uses : + +% Change History : +% Date Time Prog Note +% 18-May-1998 4:44 PM ATC Created under MATLAB 5.1.0.421 + +% ATC = Ali Taylan Cemgil, +% SNN - University of Nijmegen, Department of Medical Physics and Biophysics +% e-mail : cemgil@mbfys.kun.nl + +N = size(adj); +indeg = sum(adj,1); +outdeg = sum(adj,2); +seq = []; + +for i=1:N, + % Find nodes with indegree 0 + idx = find(indeg==0); + % If can't find than graph contains a cycle + if isempty(idx), + seq = []; + break; + end; + % Remove the node with the max number of connections + [dummy idx2] = max(outdeg(idx)); + indx = idx(idx2); + seq = [seq, indx]; + indeg(indx)=-1; + idx = find(adj(indx,:)); + indeg(idx) = indeg(idx)-1; +end; + + + + diff --git a/sourcecodes/bnt-master/GraphViz/my_call.m b/sourcecodes/bnt-master/GraphViz/my_call.m new file mode 100644 index 00000000..7059d1fc --- /dev/null +++ b/sourcecodes/bnt-master/GraphViz/my_call.m @@ -0,0 +1,3 @@ +function my_call(value) +fprintf('%d \n', value); % might check here whether this is a label at all + % since we get here by clicking on ANY text in figure diff --git a/sourcecodes/bnt-master/GraphViz/process_options.m b/sourcecodes/bnt-master/GraphViz/process_options.m new file mode 100644 index 00000000..5e17eb89 --- /dev/null +++ b/sourcecodes/bnt-master/GraphViz/process_options.m @@ -0,0 +1,132 @@ +% PROCESS_OPTIONS - Processes options passed to a Matlab function. +% This function provides a simple means of +% parsing attribute-value options. Each option is +% named by a unique string and is given a default +% value. +% +% Usage: [var1, var2, ..., varn[, unused]] = ... +% process_options(args, ... +% str1, def1, str2, def2, ..., strn, defn) +% +% Arguments: +% args - a cell array of input arguments, such +% as that provided by VARARGIN. Its contents +% should alternate between strings and +% values. +% str1, ..., strn - Strings that are associated with a +% particular variable +% def1, ..., defn - Default values returned if no option +% is supplied +% +% Returns: +% var1, ..., varn - values to be assigned to variables +% unused - an optional cell array of those +% string-value pairs that were unused; +% if this is not supplied, then a +% warning will be issued for each +% option in args that lacked a match. +% +% Examples: +% +% Suppose we wish to define a Matlab function 'func' that has +% required parameters x and y, and optional arguments 'u' and 'v'. +% With the definition +% +% function y = func(x, y, varargin) +% +% [u, v] = process_options(varargin, 'u', 0, 'v', 1); +% +% calling func(0, 1, 'v', 2) will assign 0 to x, 1 to y, 0 to u, and 2 +% to v. The parameter names are insensitive to case; calling +% func(0, 1, 'V', 2) has the same effect. The function call +% +% func(0, 1, 'u', 5, 'z', 2); +% +% will result in u having the value 5 and v having value 1, but +% will issue a warning that the 'z' option has not been used. On +% the other hand, if func is defined as +% +% function y = func(x, y, varargin) +% +% [u, v, unused_args] = process_options(varargin, 'u', 0, 'v', 1); +% +% then the call func(0, 1, 'u', 5, 'z', 2) will yield no warning, +% and unused_args will have the value {'z', 2}. This behaviour is +% useful for functions with options that invoke other functions +% with options; all options can be passed to the outer function and +% its unprocessed arguments can be passed to the inner function. + +% Copyright (C) 2002 Mark A. Paskin +% +% This program is free software; you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation; either version 2 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, but +% WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +% General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program; if not, write to the Free Software +% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +% USA. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +function [varargout] = process_options(args, varargin) + +% Check the number of input arguments +n = length(varargin); +if (mod(n, 2)) + error('Each option must be a string/value pair.'); +end + +% Check the number of supplied output arguments +if (nargout < (n / 2)) + error('Insufficient number of output arguments given'); +elseif (nargout == (n / 2)) + warn = 1; + nout = n / 2; +else + warn = 0; + nout = n / 2 + 1; +end + +% Set outputs to be defaults +varargout = cell(1, nout); +for i=2:2:n + varargout{i/2} = varargin{i}; +end + +% Now process all arguments +nunused = 0; +for i=1:2:length(args) + found = 0; + for j=1:2:n + if strcmpi(args{i}, varargin{j}) + varargout{(j + 1)/2} = args{i + 1}; + found = 1; + break; + end + end + if (~found) + if (warn) + warning(sprintf('Option ''%s'' not used.', args{i})); + args{i} + else + nunused = nunused + 1; + unused{2 * nunused - 1} = args{i}; + unused{2 * nunused} = args{i + 1}; + end + end +end + +% Assign the unused arguments +if (~warn) + if (nunused) + varargout{nout} = unused; + else + varargout{nout} = cell(0); + end +end |
