Search code examples
matlabmatlab-figureaxisfillellipse

MATLAB: How to maintain aspect ratio of filled ellipses when using "fill" function?


I am plotting filled circles and ellipses on an x-y plot. The ellipses are derived from 2x2 tensor data. The x-direction and y-direction have wildly different units depending on the type of data I am plotting. I want an ellipse to be plotted at some (x,y) location on the plot, but I want the aspect ratio of the plotted ellipse to be maintained regardless of the x and y axis units. Note that axis equal is not an option here because the x and y scales are so different. If I try to do axis equal it just makes the plot really tiny.

Below is a simple example. In this example, the first ellipse is always a perfect circle for reference to see how the figure distorts it. Any help is appreciated.

x = 100*[1 2 3 4]; %x direction is several orders of magnitude larger than y direction
y = [1 2 3 4]; %y direction
data = randn(4,1); %data to fill ellipse (irrelevant to the question)

nrot = 36; %Number of points on each ellipse

for i = 1:4
    %Elements of 2x2 tensor to make the ellipse
    r1 = randn; r2 = randn; r3 = randn; r4 = randn;

    for irot=1:nrot %Loop to get ellipse points

        rot_ang = (irot-1)*360/(nrot-1);
        v = [cosd(rot_ang),sind(rot_ang)]; %Rotating vector components

        if i == 1 %Ensure that the first ellipse is a perfect circle
            r1 = 0; r4 = 0; r3 = r2;
        end

        plot_vec = [r1 r2; r3 r4]*v';

        %x component of ellipse to plot
        ex(irot) = plot_vec(1);

        %y component of ellipse to plot
        ey(irot) = plot_vec(2);  
    end 

    %Plot the ellipse at the x-y location
    xp = x(i)+ex;
    yp = y(i)+ey;

    fill(xp,yp,data(i)); hold on %Plot ellipses filled with "data".


end

%"Axis equal" does not work in this case
%axis equal

Solution

  • It sounds like you want your ellipses to have a displayed data aspect ratio of 1:1, even when the data aspect ratio of the axes is not. One option is to first choose the data aspect ratio you want for your axes, then scale the y values of your ellipses accordingly before translating and plotting them:

    x = 100*[1 2 3 4];
    y = [1 2 3 4];
    aspectRatio = 100;  % Choose an aspect ratio of 100
    data = randn(4, 1);
    nrot = 36;
    
    for i = 1:4
    
      r1 = randn; r2 = randn; r3 = randn; r4 = randn;
    
      for irot = 1:nrot
    
        rot_ang = (irot-1)*360/(nrot-1);
        v = [cosd(rot_ang), sind(rot_ang)];
    
        if i == 1
          r1 = 0; r4 = 0; r3 = r2;
        end
    
        plot_vec = [r1 r2; r3 r4]*v';
        ex(irot) = plot_vec(1);
        ey(irot) = plot_vec(2);
    
      end
    
      xp = x(i)+ex;
      yp = y(i)+ey./aspectRatio;  % Scale ellipse y data by aspect ratio
    
      fill(xp, yp, data(i));
      hold on;
      daspect(gca, [aspectRatio 1 1]);  % Set aspect ratio of axes
    
    end
    

    And here's the resulting plot:

    enter image description here

    The ellipses are small, but if you zoom you'll see they appear to have the correct aspect ratio (i.e. the first looks like a circle).