Code covered by the BSD License  

Highlights from
LINEAGE v1.1

image thumbnail

LINEAGE v1.1

by

 

07 Apr 2009 (Updated )

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