Code covered by the BSD License  

Highlights from
LINEAGE v1.1

image thumbnail
from LINEAGE v1.1 by Kenneth Eaton
LINEAGE helps visualize the evolution of the code throughout the Peg Solitaire contest

lineage(filePath)
function lineage(filePath)
%LINEAGE   Opens a viewer for the Peg Solitaire contest data.
%   LINEAGE(FILE) opens a viewer for exploring the contest data in the file
%   specified by the string FILE (a relative or absolute file path). If
%   FILE is not specified, LINEAGE will will attempt to load a file called
%   'contest_data.mat' in the current directory.
%
% For a detailed tutorial, please refer to the published documentation.

% Author: Ken Eaton
% Last modified: 4/8/09
%--------------------------------------------------------------------------

  % Check input arguments:

  if (nargin == 0),
    filePath = 'contest_data.mat';
  elseif ~ischar(filePath),
    error('Input argument must be a character string!');
  end

  % Initialize variables used by the nested mouse-based plot navigation
  %   function ("mouse_action"):

  axesPosition = [401 2 399 399];
  isActive = false;
  selection = 'none';
  origin = 0;

  % Initialize the figure:

  screenSize = get(0,'ScreenSize');
  figurePosition = [1+(screenSize(3:4)-[800 600])./2 800 600];
  hFigure = figure('Units','pixels','Position',figurePosition,...
                   'BusyAction','cancel','Color',[0.7 0.7 0.7],...
                   'DockControls','off','HandleVisibility','off',...
                   'IntegerHandle','off','Interruptible','on',...
                   'MenuBar','none','Name','Lineage v1.0',...
                   'NumberTitle','off','Resize','off','Toolbar','none');

  % Initialize the axes:

  hAxes = axes('Parent',hFigure,'Units','pixels',...
               'Position',axesPosition,'DataAspectRatio',[1 1 1],...
               'HandleVisibility','off','NextPlot','add',...
               'PlotBoxAspectRatioMode','manual','Visible','off',...
               'XLim',[0 1],'YLim',[0 1]);

  % Initialize variables for use by GUI components:

  addToPanel = 'top';
  currentDisplay = cell(1,2);

  % Initialize submission data uicontrols (top panel):

  hTop = uipanel('Parent',hFigure,'Units','pixels',...
                 'Position',[1 301 400 300],...
                 'BackgroundColor',[0.4 0.4 0.4],...
                 'BorderType','beveledout','BorderWidth',1,...
                 'HandleVisibility','off','HighlightColor',[1 1 1],...
                 'ShadowColor',[0 0 0]);
  hTopInfo = uicontrol('Style','text','Parent',hTop,'Units','pixels',...
                       'Position',[10 210 300 80],...
                       'BackgroundColor',[0.4 0.4 0.4],...
                       'FontAngle','normal','FontName','FixedWidth',...
                       'FontUnits','pixels','FontSize',10,...
                       'FontWeight','bold','ForegroundColor',[0 1 1],...
                       'HandleVisibility','off',...
                       'HorizontalAlignment','left',...
                       'String','(no submission selected)');
  hTopButton = uicontrol('Style','pushbutton','Parent',hTop,...
                         'Units','pixels','Position',[320 240 70 25],...
                         'BackgroundColor',[0 1 0],...
                         'BusyAction','cancel','Callback',@gui_callback,...
                         'FontAngle','normal','FontName','FixedWidth',...
                         'FontUnits','pixels','FontSize',10,...
                         'FontWeight','normal',...
                         'ForegroundColor',[0 0 0],...
                         'HandleVisibility','off',...
                         'HorizontalAlignment','center',...
                         'Interruptible','off','String','Replace',...
                         'Tag','BUTTON');
  hTopCode = uicontrol('Style','listbox','Parent',hTop,'Units','pixels',...
                       'Position',[5 5 390 200],...
                       'BackgroundColor',[0 0 0],...
                       'Callback',@gui_callback,'FontAngle','normal',...
                       'FontName','FixedWidth','FontUnits','pixels',...
                       'FontSize',10,'FontWeight','normal',...
                       'ForegroundColor',[0 1 1],...
                       'HandleVisibility','off',...
                       'HorizontalAlignment','center','ListboxTop',1,...
                       'Max',2,'Min',0,'SliderStep',[1 3],'String','',...
                       'Tag','LIST','UserData',[],'Value',[]);

  % Initialize submission data uicontrols (bottom panel):

  hBottom = uipanel('Parent',hFigure,'Units','pixels',...
                    'Position',[1 1 400 300],...
                    'BackgroundColor',[0.4 0.4 0.4],...
                    'BorderType','beveledout','BorderWidth',1,...
                    'HandleVisibility','off','HighlightColor',[1 1 1],...
                    'ShadowColor',[0 0 0]);
  hBottomInfo = uicontrol('Style','text','Parent',hBottom,...
                          'Units','pixels','Position',[10 210 300 80],...
                          'BackgroundColor',[0.4 0.4 0.4],...
                          'FontAngle','normal','FontName','FixedWidth',...
                          'FontUnits','pixels','FontSize',10,...
                          'FontWeight','bold','ForegroundColor',[0 1 1],...
                          'HandleVisibility','off',...
                          'HorizontalAlignment','left',...
                          'String','(no submission selected)');
  hBottomButton = uicontrol('Style','pushbutton','Parent',hBottom,...
                            'Units','pixels','Position',[320 240 70 25],...
                            'BackgroundColor',[1 0 0],...
                            'BusyAction','cancel',...
                            'Callback',@gui_callback,...
                            'FontAngle','normal',...
                            'FontName','FixedWidth',...
                            'FontUnits','pixels','FontSize',10,...
                            'FontWeight','normal',...
                            'ForegroundColor',[0 0 0],...
                            'HandleVisibility','off',...
                            'HorizontalAlignment','center',...
                            'Interruptible','off','String','Keep',...
                            'Tag','BUTTON');
  hBottomCode = uicontrol('Style','listbox','Parent',hBottom,...
                          'Units','pixels','Position',[5 5 390 200],...
                          'BackgroundColor',[0 0 0],...
                          'Callback',@gui_callback,'FontAngle','normal',...
                          'FontName','FixedWidth','FontUnits','pixels',...
                          'FontSize',10,'FontWeight','normal',...
                          'ForegroundColor',[0 1 1],...
                          'HandleVisibility','off',...
                          'HorizontalAlignment','center','ListboxTop',1,...
                          'Max',2,'Min',0,'SliderStep',[1 3],...
                          'String','','Tag','LIST','UserData',[],...
                          'Value',[]);

  % Initialize submission data preview:

  hPreview = uipanel('Parent',hFigure,'Units','pixels',...
                     'Position',[401 401 400 200],...
                     'BackgroundColor',[0.4 0.4 0.4],...
                     'BorderType','beveledout','BorderWidth',1,...
                     'HandleVisibility','off','HighlightColor',[1 1 1],...
                     'ShadowColor',[0 0 0]);
  hPreviewInfo = uicontrol('Style','text','Parent',hPreview,...
                           'Units','pixels','Position',[50 60 300 80],...
                           'BackgroundColor',[0.4 0.4 0.4],...
                           'FontAngle','normal','FontName','FixedWidth',...
                           'FontUnits','pixels','FontSize',10,...
                           'FontWeight','bold',...
                           'ForegroundColor',[0 1 1],...
                           'HandleVisibility','off',...
                           'HorizontalAlignment','left','String','');

  % Display loading message:

  hLoading = uicontrol('Style','text','Parent',hFigure,'Units','pixels',...
                       'Position',[550 190 100 20],...
                       'BackgroundColor',[0.7 0.7 0.7],...
                       'FontAngle','normal','FontName','FixedWidth',...
                       'FontUnits','pixels','FontSize',10,...
                       'FontWeight','bold','ForegroundColor',[0 1 1],...
                       'HandleVisibility','off',...
                       'HorizontalAlignment','left','String','Loading...');
  drawnow;

  % Load the data:

  try
    data = load(filePath);
    codeList = data.allLineList;
    data = data.d;
  catch
    delete(hFigure);
    drawnow;
    error('Invalid or corrupt data file!');
  end
  nNodes = numel(data);
  [timestamps,sortIndex] = sort([data.timestamp]);
  data = data(sortIndex);
  ids = [data.id];
  parents = [data.parent];
  [isChild,parents] = ismember(parents,ids);
  metric = [data.score];

  % Initialize data for plotting family groups:

  originIndex = find(~isChild);
  nFamilies = numel(originIndex);
  familyList = cell(1,nFamilies);
  position = zeros(1,nNodes);
  branchEnd = zeros(1,nNodes);
  isImproved = false(1,nNodes);
  offset = 0;

  % Recursively compute the family group data:

  for iFamily = 1:nFamilies,
    familyList{iFamily} = get_children(originIndex(iFamily));
  end
  parents(originIndex) = originIndex;

  % Remove the loading message:

  delete(hLoading);

  % Adjust the time stamps and find the edges of 24 hour blocks:

  timestamps = timestamps-floor(timestamps(1));
  timeEdges = timestamps(1)+(0:7);

  % Set the axes limits and camera properties:

  xLimit = [timeEdges(1) timeEdges(8)];
  yLimit = [min(position)-1 max(position)+1];
  viewAngle = 5;  % in degrees
  cameraPoint = [mean(xLimit) mean(yLimit) 0.5/tan(viewAngle*pi/360)];
  targetPoint = [mean(xLimit) mean(yLimit) 0];
  set(hAxes,'CameraPosition',cameraPoint,'CameraTarget',targetPoint,...
      'CameraUpVectorMode','manual','CameraViewAngle',viewAngle,...
      'DataAspectRatio',[diff(xLimit) diff(yLimit) 1],'XLim',xLimit,...
      'YLim',yLimit);

  % Set the gains for the mouse-based plot navigation:

  panGain = [diff(xLimit) diff(yLimit)]./min(axesPosition(3:4));
  zoomGain = 0.03;

  % Plot the darkness, twilight, and daylight panels:

  patch(timeEdges([1 1 2 2]),yLimit([1 2 2 1]),[0.3 0.3 0.3],...
        'Parent',hAxes,'Clipping','off','HandleVisibility','off');
  patch(timeEdges([2 2 3 3]),yLimit([1 2 2 1]),[0.6 0.6 0.6],...
        'Parent',hAxes,'Clipping','off','HandleVisibility','off');
  patch(timeEdges([3 3 8 8]),yLimit([1 2 2 1]),[1 1 1],...
        'Parent',hAxes,'Clipping','off','HandleVisibility','off');
  line(timeEdges([4 5 6 7; 4 5 6 7]),yLimit([1 1 1 1; 2 2 2 2]),...
       'Parent',hAxes,'Clipping','off','Color',[0 0 0],'LineStyle',':',...
       'HandleVisibility','off');

  % Create the color map for the family group data:

  familyRGB = zeros(nFamilies,3);
  nMembers = cellfun('length',familyList);
  notDeadEnd = (nMembers > 1);
  [temp,sortIndex] = sort(nMembers(notDeadEnd));
  cmap(sortIndex,:) = grayless_color_cube(sum(notDeadEnd));
  familyRGB(notDeadEnd,:) = cmap;

  % Plot the family group data:

  for iFamily = 1:nFamilies,
    familyIndex = familyList{iFamily};
    familyColor = familyRGB(iFamily,:);
    line([timestamps(parents(familyIndex)); ...
          timestamps([1 1],familyIndex)],...
         [position([1 1],familyIndex); branchEnd(familyIndex)],...
         'Parent',hAxes,'Color',familyColor,'Clipping','off',...
         'HandleVisibility','off');
    plot(timestamps(familyIndex),position(familyIndex),'o',...
         'Parent',hAxes,'Clipping','off','HandleVisibility','off',...
         'MarkerEdgeColor','none','MarkerFaceColor',familyColor,...
         'MarkerSize',4);
  end

  % Plot the markers for the improved and best submissions:

  [topScore,topIndex] = min([data.score]);
  isImproved(topIndex) = false;
  plot(timestamps(isImproved),position(isImproved),'s','Parent',hAxes,...
       'Clipping','off','HandleVisibility','off',...
       'MarkerEdgeColor',[0 0 0],'MarkerFaceColor','none','MarkerSize',4);
  plot(timestamps(topIndex),position(topIndex),'p','Parent',hAxes,...
       'Clipping','off','HandleVisibility','off',...
       'MarkerEdgeColor',[0 0 0],'MarkerFaceColor','none','MarkerSize',14);

  % Plot markers for selected files:

  hMarkers = [text(0,0,'\leftarrow 1','Parent',hAxes,'Color',[0 0 0],...
                   'Clipping','off','FontAngle','normal',...
                   'FontName','FixedWidth','FontWeight','normal',...
                   'FontUnits','pixels','FontSize',12,...
                   'HandleVisibility','off',...
                   'HorizontalAlignment','left',...
                   'VerticalAlignment','middle','Visible','off') ...
              text(0,0,'\leftarrow 2','Parent',hAxes,'Color',[0 0 0],...
                   'Clipping','off','FontAngle','normal',...
                   'FontName','FixedWidth','FontWeight','normal',...
                   'FontUnits','pixels','FontSize',12,...
                   'HandleVisibility','off',...
                   'HorizontalAlignment','left',...
                   'VerticalAlignment','middle','Visible','off')];

  % Activate the mouse-based plot navigation:

  set(hFigure,'WindowButtonDownFcn',{@mouse_action; 'down'},...
      'WindowButtonMotionFcn',{@mouse_action; 'none'},...
      'WindowButtonUpFcn',{@mouse_action; 'up'});
  drawnow;

%~~~Begin nested functions~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  %------------------------------------------------------------------------
  function childList = get_children(parentIndex)
  %
  %   Recursive function for finding children.
  %
  %------------------------------------------------------------------------

    childList = parentIndex;
    position(parentIndex) = offset;
    childIndex = find(parents == parentIndex);
    if isempty(childIndex),
      branchEnd(parentIndex) = offset;
      offset = offset+1;
      return;
    end
    [bestScore,bestIndex] = min(metric([childIndex parentIndex]));
    if (bestIndex <= numel(childIndex)),
      isImproved(childIndex(bestIndex)) = true;
    end
    metric(childIndex) = bestScore;
    for iChild = childIndex,
      branchEnd(parentIndex) = offset;
      childList = [childList get_children(iChild)];
    end

  end

  %------------------------------------------------------------------------
  function display_info(hInfo,index)
  %
  %   Function for displaying submission info in a text uicontrol.
  %
  %------------------------------------------------------------------------

    if isempty(index),
      set(hInfo,'String',{});
    else
      displayString = {data(index).title; ...
                       ['  Author: ' data(index).author]; ...
                       ['  Submission time: ' ...
                        datestr(data(index).timestamp,0)]; ...
                       ['  Score: ' num2str(data(index).score)]};
      set(hInfo,'String',displayString);
    end

  end

  %------------------------------------------------------------------------
  function display_code(index)
  %
  %   Function for displaying submission code in a list uicontrol.
  %
  %------------------------------------------------------------------------

%    if strcmp(addToPanel,'top'),
%      set(hTopCode,'ListboxTop',1,'String',codeList(data(index).lines));
%    else
%      set(hBottomCode,'ListboxTop',1,'String',codeList(data(index).lines));
%    end
    codeLines = data(index).lines;
    lineNumbers = cellstr(int2str((1:numel(codeLines)).'));
    if strcmp(addToPanel,'top'),
      hCode = hTopCode;
      hCompareCode = hBottomCode;
      compareIndex = currentDisplay{2};
    else
      hCode = hBottomCode;
      hCompareCode = hTopCode;
      compareIndex = currentDisplay{1};
    end
    if isempty(compareIndex),
      values = [];
    else
      compareLines = data(compareIndex).lines;
      values = find(~ismember(codeLines,compareLines));
      compareValues = find(~ismember(compareLines,codeLines));
      listboxTop = get(hCompareCode,'ListboxTop');
      set(hCompareCode,'UserData',compareValues,'Value',compareValues);
      drawnow;
      set(hCompareCode,'ListboxTop',listboxTop);
    end
    set(hCode,'Max',numel(codeLines),...
        'String',strcat(lineNumbers,{': '},codeList(codeLines).'),...
        'UserData',values,'Value',values);
    drawnow;
    set(hCode,'ListboxTop',1);

  end

  %------------------------------------------------------------------------
  function gui_callback(source,event)
  %
  %   Callback function for GUI controls.
  %
  %------------------------------------------------------------------------

    switch get(source,'Tag'),

      case 'BUTTON',

        if strcmp(addToPanel,'top'),
          addToPanel = 'bottom';
          set(hTopButton,'BackgroundColor',[1 0 0],'String','Keep');
          set(hBottomButton,'BackgroundColor',[0 1 0],'String','Replace');
        else
          addToPanel = 'top';
          set(hTopButton,'BackgroundColor',[0 1 0],'String','Replace');
          set(hBottomButton,'BackgroundColor',[1 0 0],'String','Keep');
        end

      case 'LIST',

        listboxTop = get(source,'ListboxTop');
        set(source,'Value',get(source,'UserData'));
        drawnow;
        set(source,'ListboxTop',listboxTop);

    end

  end

  %------------------------------------------------------------------------
  function mouse_action(source,event,mouseOperation)
  %
  %   Function for mouse-based plot navigation.
  %
  %------------------------------------------------------------------------

    switch mouseOperation,

      case 'none',

        currentPoint = get(source,'CurrentPoint');
        nodeIndex = find_nearest;
        display_info(hPreviewInfo,nodeIndex);
        update_pointer;
        drawnow;

      case 'down',

        if (~isActive),
          isActive = true;
          currentPoint = get(source,'CurrentPoint');
          if within_rectangle(currentPoint,axesPosition),
            selection = get(source,'SelectionType');
            set(source,'WindowButtonMotionFcn',{@mouse_action; 'motion'});
            initialize_mouse;
            update_pointer;
            drawnow;
          else
            isActive = false;
          end
        end

      case 'motion',

        currentPoint = get(source,'CurrentPoint');
        track_mouse;
        drawnow;

      case 'up',

        if isActive,
          currentPoint = get(source,'CurrentPoint');
          track_mouse;
          set(source,'WindowButtonMotionFcn',{@mouse_action; 'none'});
          selection = 'none';
          update_pointer;
          isActive = false;
          drawnow;
        end

    end

    %----------------------------------------------------------------------
    function initialize_mouse
    %
    %   Initialization function for mouse-based plot navigation.
    %
    %----------------------------------------------------------------------

      switch selection,

        case 'normal',  % Left button: pan operation

          cameraPoint = get(hAxes,'CameraPosition');
          targetPoint = get(hAxes,'CameraTarget');
          viewAngle = get(hAxes,'CameraViewAngle');
          origin = currentPoint;

        case 'alt',  % Right button: select operation

          nodeIndex = find_nearest;
          if ~isempty(nodeIndex),
            if strcmp(addToPanel,'top'),
              currentDisplay{1} = nodeIndex;
              hMarker = hMarkers(1);
              display_info(hTopInfo,nodeIndex);
            else
              currentDisplay{2} = nodeIndex;
              hMarker = hMarkers(2);
              display_info(hBottomInfo,nodeIndex);
            end
            set(hMarker,'Visible','on',...
                'Position',[timestamps(nodeIndex) position(nodeIndex)]);
            display_code(nodeIndex);
          end

        case 'extend',  % Middle button: zoom operation

          viewAngle = get(hAxes,'CameraViewAngle');
          origin = currentPoint(2);

        case 'open',  % Double-click any button: reset operation

          viewAngle = 5;  % in degrees
          cameraPoint = [mean(xLimit) mean(yLimit) ...
                         0.5/tan(viewAngle*pi/360)];
          targetPoint = [mean(xLimit) mean(yLimit) 0];
          set(hAxes,'CameraPosition',cameraPoint,...
              'CameraTarget',targetPoint,'CameraViewAngle',viewAngle);

      end

    end

    %----------------------------------------------------------------------
    function track_mouse
    %
    %   Tracking function for mouse-based plot navigation.
    %
    %----------------------------------------------------------------------

      switch selection,

        case 'normal',  % Left button: pan operation

          scaleGain = 2*cameraPoint(3)*tan(viewAngle*pi/360);
          newPoint = targetPoint(1:2)+...
                     scaleGain.*panGain.*(origin-currentPoint);
          newPoint(1) = min(max(newPoint(1),xLimit(1)),xLimit(2));
          newPoint(2) = min(max(newPoint(2),yLimit(1)),yLimit(2));
          newCameraPoint = [newPoint cameraPoint(3)];
          newTargetPoint = [newPoint targetPoint(3)];
          set(hAxes,'CameraPosition',newCameraPoint,...
              'CameraTarget',newTargetPoint);

        case 'extend',  % Middle button: zoom operation

          newViewAngle = viewAngle*2^(zoomGain*(origin-currentPoint(2)));
          newViewAngle = min(max(newViewAngle,0.02),5);
          set(hAxes,'CameraViewAngle',newViewAngle);

      end

    end

    %----------------------------------------------------------------------
    function index = find_nearest
    %
    %   Function for finding the nearest node to the mouse cursor.
    %
    %----------------------------------------------------------------------

      cameraPoint = get(hAxes,'CameraPosition');
      viewAngle = get(hAxes,'CameraViewAngle');
      origin = axesPosition(1:2)+0.5.*axesPosition(3:4);
      scaleGain = 2*cameraPoint(3)*tan(viewAngle*pi/360);
      cursorPoint = cameraPoint(1:2)+...
                    scaleGain.*panGain.*(currentPoint-origin);
      scale = diff(yLimit)/diff(xLimit);
      distances = sqrt((cursorPoint(2)-position).^2+...
                       (scale*(cursorPoint(1)-timestamps)).^2);
      [minValue,minIndex] = min(distances);
      if (minValue <= 1),
        index = minIndex;
      else
        index = [];
      end

    end

    %----------------------------------------------------------------------
    function update_pointer
    %
    %   Updates the pointer to match the current selection.
    %
    %----------------------------------------------------------------------

      o = nan;
      switch selection,

        case 'normal',  % Left button: pan operation

          set(hFigure,'Pointer','custom','PointerShapeHotSpot',[8 8],...
              'PointerShapeCData',...
              [o o o o o o o 2 2 o o o o o o o; ...
               o o o o o o 2 1 1 2 o o o o o o; ...
               o o o o o 2 1 1 1 1 2 o o o o o; ...
               o o o o 2 1 1 1 1 1 1 2 o o o o; ...
               o o o 2 2 2 2 1 1 2 2 2 2 o o o; ...
               o o 2 1 2 o 2 1 1 2 o 2 1 2 o o; ...
               o 2 1 1 2 2 2 1 1 2 2 2 1 1 2 o; ...
               2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2; ...
               2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2; ...
               o 2 1 1 2 2 2 1 1 2 2 2 1 1 2 o; ...
               o o 2 1 2 o 2 1 1 2 o 2 1 2 o o; ...
               o o o 2 2 2 2 1 1 2 2 2 2 o o o; ...
               o o o o 2 1 1 1 1 1 1 2 o o o o; ...
               o o o o o 2 1 1 1 1 2 o o o o o; ...
               o o o o o o 2 1 1 2 o o o o o o; ...
               o o o o o o o 2 2 o o o o o o o]);

        case 'extend',  % Middle button: zoom operation

          set(hFigure,'Pointer','custom','PointerShapeHotSpot',[8 8],...
              'PointerShapeCData',...
              [o o o o o o o 2 2 o o o o o o o; ...
               o o o o o 2 2 1 1 2 2 o o o o o; ...
               o o o 2 2 1 1 1 1 1 1 2 2 o o o; ...
               o o 2 1 1 1 1 1 1 1 1 1 1 2 o o; ...
               o o 2 2 2 2 1 1 1 1 2 2 2 2 o o; ...
               o o o o o 2 1 1 1 1 2 o o o o o; ...
               o o o o o 2 1 1 1 1 2 o o o o o; ...
               o o o o o 2 1 1 1 1 2 o o o o o; ...
               o o o o 2 1 1 1 1 1 1 2 o o o o; ...
               o o o o 2 1 1 1 1 1 1 2 o o o o; ...
               2 2 2 2 2 1 1 1 1 1 1 2 2 2 2 2; ...
               2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2; ...
               o 2 2 1 1 1 1 1 1 1 1 1 1 2 2 o; ...
               o o o 2 2 1 1 1 1 1 1 2 2 o o o; ...
               o o o o o 2 2 1 1 2 2 o o o o o; ...
               o o o o o o o 2 2 o o o o o o o]);

        case 'none',  % No current selection

          if within_rectangle(currentPoint,axesPosition),
            set(hFigure,'Pointer','custom','PointerShapeHotSpot',[8 8],...
                'PointerShapeCData',...
                [o o o 2 2 2 o o o o 2 2 2 o o o; ...
                 o o o 2 1 2 o o o o 2 1 2 o o o; ...
                 o o o 2 1 2 o o o o 2 1 2 o o o; ...
                 2 2 2 2 1 2 o o o o 2 1 2 2 2 2; ...
                 2 1 1 1 1 2 o o o o 2 1 1 1 1 2; ...
                 2 2 2 2 2 2 o o o o 2 2 2 2 2 2; ...
                 o o o o o o o 2 2 o o o o o o o; ...
                 o o o o o o 2 1 1 2 o o o o o o; ...
                 o o o o o o 2 1 1 2 o o o o o o; ...
                 o o o o o o o 2 2 o o o o o o o; ...
                 2 2 2 2 2 2 o o o o 2 2 2 2 2 2; ...
                 2 1 1 1 1 2 o o o o 2 1 1 1 1 2; ...
                 2 2 2 2 1 2 o o o o 2 1 2 2 2 2; ...
                 o o o 2 1 2 o o o o 2 1 2 o o o; ...
                 o o o 2 1 2 o o o o 2 1 2 o o o; ...
                 o o o 2 2 2 o o o o 2 2 2 o o o]);
          else
            set(hFigure,'Pointer','default',...
                'PointerShapeHotSpot','default',...
                'PointerShapeCData','default');
          end

      end

    end

  end

%~~~End nested functions~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

end

%~~~Begin subfunctions~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

%--------------------------------------------------------------------------
function map = grayless_color_cube(N)
%
%   Mimics the colorcube function, with no grays and fewer pure colors.
%
%--------------------------------------------------------------------------

  nSteps = roots([1 0 -1 -N]);
  nSteps = ceil(nSteps(1));
  [R,G,B] = meshgrid(linspace(0,1,nSteps));
  map = [R(:) G(:) B(:)];
  map(1:(nSteps*(nSteps+1)+1):(nSteps^3),:) = [];
  map = map(1:N,:);

end

%--------------------------------------------------------------------------
function isWithin = within_rectangle(point,position)
%
%   Determines if a point is within a rectangular region.
%
%--------------------------------------------------------------------------

  isWithin = ((point(:,1) >= position(1)) & ...
              (point(:,2) >= position(2)) & ...
              (point(:,1) <= position(1)+position(3)) & ...
              (point(:,2) <= position(2)+position(4)));

end

%~~~End subfunctions~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Contact us at files@mathworks.com