function arc_histmap(variable,results,options) % PURPOSE: produce a map with histogram legend using ArcView shape files % ---------------------------------------------------------------------- % USAGE: arc_histmap(variable,results,options) % where: variable = a variable vector (nobs x 1) or matrix (nobs x nvars) % results = a structure variable returned by shape_read() % options = a structure variable with function options % options.vnames = a string with the variable name or names % e.g. vnames = strvcat('constant','pinstruction','pbuilding','padminist'); % options.cmap = a colormap string, e.g., 'hsv','jet' (default 'hsv') % (see colormap menu in the gui for various options) % options.nbc = # of categories (default = 5) % (see #categories menu in the gui for various options) % options.missing = a vector of 0's and 1's for missing and non-missing observations % 0 = missing, 1 = non-missing % (produces white map polygons for missing values) % options.mapmenu = 1, for a menubar, 0 = default, no menubar % (useful for printing, editing the map) % options.legendmenu = 1, for a menubar, 0 = default, no menubar % (useful for printing, editing the map) % ---------------------------------------------------------------------- % RETURNS: a graphical user interface with the map and histogram legend % as well as menus for: colormap,zoom map,#categories,quit % NOTE: a right-mouse-click on the map polygons presents the data value % associated with the map region on which you clicked % ---------------------------------------------------------------------- % see also: ahape_read(), make_map() % ---------------------------------------------------------------------- [nobsm,nvarsm] = size(variable); missing_vec = ones(nobsm,1); % some error checking if nargin == 3 % user-defined options input if ~isstruct(options) error('arc_histmap: must supply options as a structure variable'); end; fields = fieldnames(options); nf = length(fields); nbc = 5; % defaults cmap = 'hsv'; vnames = 'Variable'; for i=1:nvarsm; vnames = strvcat(vnames,['variable',num2str(i)]); end; vflag = 0; mapmenu = 0; legendmenu = 0; for i=1:nf if strcmp(fields{i},'nbc') nbc = options.nbc; elseif strcmp(fields{i},'cmap') cmap = options.cmap; elseif strcmp(fields{i},'vnames') vnames = options.vnames; [nchk,junk] = size(vnames); if nchk ~= nvarsm error('arc_histmap: wrong number of variable names'); end; vflag = 1; elseif strcmp(fields{i},'mapmenu') mapmenu = options.mapmenu; elseif strcmp(fields{i},'legendmenu'); legendmenu = options.legendmenu; elseif strcmp(fields{i},'missing'); missing_vec = options.missing; end; end; elseif nargin == 2 % set default options nbc = 5; cmap = 'hsv'; vnames = 'Variable'; for i=1:nvarsm; vnames = strvcat(vnames,['variable',num2str(i)]); end; vflag = 0; mapmenu = 0; legendmenu = 0; else error('arc_histmap: Wrong # of input arguments'); end; results.nbc = nbc; results.cmap = cmap; results.vnames = vnames; results.mapmenu = mapmenu; results.legendmenu = legendmenu; results.vindex = 1; results.legend_fig = 0; results.variable = variable; [nobsm,nvarsm] = size(variable); results.nvarsm = nvarsm; results.vflag = vflag; mindex = find(missing_vec == 1); results.svariable = variable; % holds all variables zoomed on the map results.cvariable = variable(:,results.vindex); % holds current variable selection results.missing = missing_vec; results.cmissing = missing_vec; % figure out size of map windows svec = get(0,'ScreenSize'); if svec(3) > 1300 width = 800; height = 800; elseif svec(3) > 1000 width = 650; height = 650; elseif svec(3) == 800 error('arc_histmap: you need a higher screen resolution to use arc_map'); end; results.width = width; results.height = height; % construct a legend for the map % uses results.cvariable results = am_histlegend(results); map_colors = results.map_colors; poly = make_map(results,variable); if vflag == 1 mname = ['Map of ',vnames(results.vindex,:)]; elseif vflag == 0 mname = ['Map of ',vnames(2,:)]; end; if mapmenu == 0 set(poly(1).fig_handle, ... 'Position',[50 100 width height], ... % [left bottom width height] 'MenuBar','none', ... 'NumberTitle','off', ... 'Name',mname); elseif mapmenu == 1 set(poly(1).fig_handle, ... 'Position',[50 100 width height], ... 'NumberTitle','off', ... 'Name',mname); end; axis equal; thandles = zeros(results.npoly,1); hold on; for i=1:results.npoly; for k=1:results.nparts(i); set(poly(i).handles(k),'FaceColor',map_colors(i,:),'Visible','on'); end; end; hold off; hpop = uicontrol('Style', 'popup',... 'String', 'Colormap|hsv|hot|cool|gray|bone|copper|jet|pink|white|autumn|spring|winter|summer',... 'Position', [0 5 75 20],... 'Callback', 'am_histcmap'); % 'TooltipString','Select a color scheme for the map'); % [left bottom width height] spop = uicontrol('Style', 'popup',... 'String', 'Zoom map|select rectangle|zoom out',... 'Position', [76 5 100 20],... 'Callback', 'am_histmap'); % 'TooltipString','Zoom in on a region of the map'); cpop = uicontrol('Style', 'popup',... 'String', '# categories|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20',... 'Position', [176 5 125 20],... 'Callback', 'am_histncat'); % 'TooltipString','Set the # of histogram categories'); vlist = 'Variable|'; if vflag == 1 for i=1:nvarsm; vlist = [vlist vnames(i,:) '|']; end; elseif vflag == 0 for i=1:nvarsm; vlist = [vlist vnames(i+1,:) '|']; end; end; vpop = uicontrol('Style', 'popup',... 'String', vlist,... 'Position', [300 5 150 20],... 'Callback', 'am_histvariable'); % 'TooltipString','Select a variable to map'); qpop = uicontrol('Style', 'popup',... 'String', 'Quit|Close/Exit',... 'Position', [551 5 75 20],... 'Callback', 'am_histquit'); % 'TooltipString','Close the map and histogram windows'); % place a bunch of stuff into the results structure % for use by the sub-functions results.hpop = hpop; results.spop = spop; results.cpop = cpop; results.vpop = vpop; results.qpop = qpop; set(poly(1).fig_handle,'Visible','on'); set(poly(1).fig_handle,'UserData',poly); guidata(hpop, results); guidata(cpop, results); guidata(spop, results); guidata(vpop, results); guidata(qpop, results); % bring legend figure back to the front figure(results.legend_fig); % -------------------------------------------------------------------- % support functions % -------------------------------------------------------------------- % am_histmap, am_histcmap, am_histncat, am_histvariable, am_getinfo, am_histquit % -------------------------------------------------------------------- function poly = make_map(results,data) % PURPOSE: constucts a map using structure variable returned by read_shape() % -------------------------------------------------------------------------- % USAGE: poly = make_map(results,data), % where: results is a structure variable returned by read_shape() % data is the data matrix to be mapped (an input argument to arc_map % functions) % -------------------------------------------------------------------------- % RETURNS: a structure variable with handles to the map polygons % poly(i).handles(k) = a handle to each of (nobs=npoly) polygon regions and its k-parts % (these are patch objects) % poly(1).fig_handle = a handle to a figure containing the map % (use: set(poly(1).fig_handle,'Visible','on') to see the map) % Also sets the UserData field for the patch objects to contain the % associated row of data for this polygon % % -------------------------------------------------------------------------- % NOTES: % 1) to load and plot a map involving npoly=nobs sample data observations % results = shape_read('myarcfile'); % poly = make_map(results,results.data); % set(poly(1).fig_handle,'Visible','on'); % 2) Also you can do the following: % figure(1); % hold on; % h = []; % handles to each polygon % for i=1:results.npoly; % for k=1:results.nparts(i); % mypoly.faces = get(poly(i).handles(k),'Faces'); % mypoly.vertices = get(poly(i).handles(k),'Vertices'); % h(i,k) = patch(mypoly); % end; % end; % 3) to set the facecolor of the polygons, using the handles h % for i=1:npoly; % for k=1:results(i).nparts; % set(h(i,k),'FaceColor',[0 1 1]); % end; % end; x = results.x; y = results.y; poly(1).fig_handle = figure('Visible','off'); handles = polyplot(x,y,'fill',[0 0 0]); % Process chunks separated by NaN ................. in = [0; find(isnan(x)); length(x)+1]; n = length(in)-1; cnt = 1; jj = 1; while (jj <= n) ii = in(jj)+1:in(jj+1)-1; ii = [ii ii(1)]; xx = x(ii); yy = y(ii); if results.nparts(cnt) == 1 poly(cnt).handles(1) = handles(jj); cmenu = uicontextmenu; set(poly(cnt).handles(1),'UIContextMenu',cmenu); hi = uimenu(cmenu,'Label',[num2str(cnt) ') ' num2str(data(cnt,1))]); set(poly(cnt).handles(1),'UserData',hi); cnt = cnt+1; jj = jj+1; else for k=1:results.nparts(cnt); poly(cnt).handles(k) = handles(jj); cmenu = uicontextmenu; set(poly(cnt).handles(k),'UIContextMenu',cmenu); hi = uimenu(cmenu,'Label',[num2str(cnt) ') ' num2str(data(cnt,1))]); set(poly(cnt).handles(k),'UserData',hi); jj = jj+1; end; cnt = cnt+1; end; end; function [handles] = polyplot(x,y,a1,a2) % POLYPLOT Plotting or filling polygons. % L = POLYPLOT(X,Y) plots polygon(s) % concatenated into coordinate vectors X, Y. % If X, Y consist of coordinates of several % polygons they must be separated by NaN: % X = [X1 NaN X2 NaN X3 ...]. In this case each % polygon is "closed" and plotted separately. % L is a vector of handles of lines defining % polygon boundaries, one handle per line. % L = POLYPLOT(X,Y,C) also specifies line color. % C can be a letter such as 'w', 'y', 'c', etc., % a 1 by 3 vector in RGB format or a string of % such letters, like 'rgby' or n by 3 matrix. % In the latter case this string or matrix plays the % role of color order for succession of polygons. % If the number of polygons is more than number of % colors, colors are cyclically repeated. % % P = POLYPLOT(X,Y,'fill',C) fills polygons % creating a patch rather than a line and returns % patch handles P. % % This program can also fill non-simply connected % polygons, such as ones with holes. It checks % the direction of each polygons separated by % NaN in coordinate vectors. If the contour is % clock-wise (signed area is negative) then it % interprets such a polygon as a "hole" and fills % it with the background color. % Copyright (c) 1995 by Kirill K. Pankratov, % kirill@plume.mit.edu. % 06/25/95, 09/07/95 % May call AREA function. % Handle input .................................... is_patch = 0; clr = get(gca,'colororder'); if nargin>2 lm = min(length(a1),4); names = ['fill '; 'patch']; is_patch = all(a1(1:lm)==names(1,1:lm)); is_patch = is_patch | all(a1(1:lm)==names(2,1:lm)); if is_patch if nargin>3, clr = a2; end else clr = a1; end end if isstr(clr), clr=clr(:); end nclr = size(clr,1); x = x(:); y = y(:); % Check hold state ............ if ~ishold, newplot, end % Setup a call ................ if is_patch call = 'patch'; cpn = 'facecolor'; else call = 'line'; cpn = 'color'; end % call = ['p(jj)=' call '(''xdata'',xx,''ydata'',yy);']; % call % Get color for "holes" polygons .................. clrh = get(gca,'color'); if strcmp(clrh,'none'), clrh = get(gcf,'color'); end % Process chunks separated by NaN ................. in = [0; find(isnan(x)); length(x)+1]; n = length(in)-1; for jj=1:n ii = in(jj)+1:in(jj+1)-1; ii = [ii ii(1)]; xx = x(ii); yy = y(ii); % Check area a(jj) = area(xx,yy); % Create the patch or line handles(jj) = patch(xx,yy,[1 0 0]); ic = rem(jj-1,nclr)+1; set(handles(jj),cpn,clr(ic,:)) end % If non-simply-connected patch, fill "holes" with % background color ............................... if is_patch & n>1 % Find which polygons are inside which holes = find(a<0); % Set color set(handles(holes),'FaceColor',clrh) end function a = area(x,y) % AREA Area of a planar polygon. % AREA(X,Y) Calculates the area of a 2-dimensional % polygon formed by vertices with coordinate vectors % X and Y. The result is direction-sensitive: the % area is positive if the bounding contour is counter- % clockwise and negative if it is clockwise. % % See also TRAPZ. % Copyright (c) 1995 by Kirill K. Pankratov, % kirill@plume.mit.edu. % 04/20/94, 05/20/95 % Make polygon closed ............. x = [x(:); x(1)]; y = [y(:); y(1)]; % Calculate contour integral Int -y*dx (same as Int x*dy). lx = length(x); a = -(x(2:lx)-x(1:lx-1))'*(y(1:lx-1)+y(2:lx))/2;