Search code examples
matlabmatlab-figure

Separating axes from plot area in MATLAB


I find that data points that lie on or near the axes are difficult to see. The obvious fix, of course, is to simply change the plot area using axis([xmin xmax ymin ymax]), but this is not preferable in all cases; for example, if the x axis is time, then moving the minimum x value to -1 to show activity at 0 does not make sense.

Instead, I was hoping to simply move the x and y axes away from the plot area, like I have done here: left: Matlab generated, right: desired (image editing software) left: MATLAB generated, right: desired (image editing software)

Is there a way to automatically do this in MATLAB? I thought there might be a way to do it by using the outerposition axes property (i.e., set it to [0 0 0.9 0.9] and drawing new axes where they originally were?), but I didn't get anywhere with that strategy.


Solution

  • The answers here already show you most of the way - here is the last step to separate the x and y axle as per the example you put together.

    f = figure ( 'color', 'white' );
    % create the axes and set some properties
    ax = axes ( 'parent', f, 'box', 'off', 'nextplot', 'add', 'XMinorTick', 'on', 'YMinorTick', 'on' );
    % plot some data
    plot ( ax, 0:10, [0:10].^2, 'rx-' )
    % modify the x and y limits to below the data (by a small amount)
    ax.XLim(1) = ax.XLim(1)-(ax.XTick(2)-ax.XTick(1))/4;
    ax.YLim(1) = ax.YLim(1)-(ax.YTick(2)-ax.YTick(1))/4;
    % Set the tick direction
    ax.TickDir = 'out';
    % draw the plot to generate the undocumented vertex data var
    drawnow()
    
    %% R2015a
    % X, Y and Z row of the start and end of the individual axle.
    ax.XRuler.Axle.VertexData(1,1) = 0;
    ax.YRuler.Axle.VertexData(2,1) = 0;
    
    
    %% R2015b
    % extract the x axis vertext data
    % X, Y and Z row of the start and end of the individual axle.
    vd = get(ax.XAxis.Axle,'VertexData');
    % reset the zero value
    vd(1,1) = 0;
    % Update the vertex data
    set(ax.XAxis.Axle,'VertexData',vd);
    % repeat for Y (set 2nd row)
    vd = get(ax.YAxis.Axle,'VertexData');
    vd(2,1) = 0;
    set(ax.YAxis.Axle,'VertexData',vd);
    

    Edit: The vertex is something that Matlab recreates whenever the axes/figure changes size or if you zoom or pan for example.

    You can try to counteract this (remember you are using undocumented features here) by adding a listener to attempt to capture this. We can use the MarkedClean event which is called quite a lot of times.

    addlistener ( ax, 'MarkedClean', @(obj,event)resetVertex(ax) );
    

    Where you resetVertex function is something like: (R2015b shown only)

    Edit 2 added the code to turn off the minor ticks below 0.

    function resetVertex ( ax )
      % extract the x axis vertext data
      % X, Y and Z row of the start and end of the individual axle.
      ax.XAxis.Axle.VertexData(1,1) = 0;
      % repeat for Y (set 2nd row)
      ax.YAxis.Axle.VertexData(2,1) = 0;
    
      % You can modify the minor Tick values by modifying the vertex data
      % for them, e.g. remove any minor ticks below 0 
      ax.XAxis.MinorTickChild.VertexData(:,ax.XAxis.MinorTickChild.VertexData(1,:)<0) = [];
      ax.YAxis.MinorTickChild.VertexData(:,ax.YAxis.MinorTickChild.VertexData(2,:)<0) = [];
    end
    

    enter image description here

    Note: this uses undocumented features -> so may only work in certain versions of Matlab (I have added the code for r2015a & r2015b) and Matlab may recreate the vertex data depending on what you do with the plots..