Search code examples
matlabmatlab-figure

Get matlab `surf` to plot a function that doesn't exist everywhere in the region


I'm trying to use matlab to create a surface plot of a function that has a limited domain [it's a square root, and the argument goes negative].

x = [-2:0.02:4]
y = [-6:0.1:6]
[X,Y] = meshgrid(x,y)

If I do

surf(X,Y,sqrt(9-(X-1).*(X-1)-Y.*Y/4))

I get an error message because the function is imaginary outside of an ellipse. So I could do

surf(X,Y,real(sqrt(9-(X-1).*(X-1)-Y.*Y/4)))

But then it's 0 outside of the domain. Really I'd like it to just not plot anything at all.

The only idea I have is to modify Y so that for each X, it's limited to the values where the function is defined. But I'd really like a way to say 'just don't plot those parts' so that I don't have to calculate the domain each time.


Solution

  • Exploiting the fact that NaNs are usually ignored by graphical routines, you could use:

    x = [-2:0.02:4];
    y = [-6:0.1:6];
    [X,Y] = meshgrid(x,y);
    clear x y;
    
    W=sqrt(9-(X-1).*(X-1)-Y.*Y/4);
    Z=nan(size(W));
    W_isreal=abs(imag(W))<=eps();
    Z(W_isreal)=real(W(W_isreal));
    clear W W_isreal;
    
    surf(X,Y,Z);
    

    Notice that this approach introduces unsightly artifacts near z=0:

    Result

    A more elegant approach that avoids such gaps near z=0 could be:

    [X,Y,Z]=ellipsoid(1,0,0,3,6,3);
    surf(X,Y,Z);
    zlim([0 Inf]);
    
    % Verify computations
    W=9-(X-1).*(X-1)-Y.*Y/4;
    W_istruenegative=(W<=-1e-6);
    if any(W_istruenegative(:))
      error('Our ellipsoid looks invalid.');
    end
    if any( abs(sqrt(abs(W(:))) - abs(Z(:))) > 1e-6 ) %verify ellipsoid
      error('Our ellipsoid looks invalid.');
    end
    clear W W_istruenegative;
    

    Improved result