[Tex/LaTex] tikz/pgfplots – Plotting 3D surface with sphere

3dpgfplotspythontikz-pgf

I am trying to solve the following problem: First I would like to produce a surface plot of a function of two variables (in this particular case this surface has a saddle shape). Then I would like to draw a sphere in the same plot in such a way that the sphere is tangent to the surface at a point that can be specified freely. Achieving the first part was not a problem. For the second part, I have so far been able to place something that at least resembles a sphere somewhere in the plot (see below). However, specifying the position of where to put the sphere seems to be done not in relation to the axes that I am plotting in, but some other reference point (so (0,0) does not put the sphere at the origin of the axes).

Has someone got a suggestion for the following questions:
1) How do I make the bounding line of the ball thinner?
2) To make it look like an actual sphere, how could I add grid lines (like longitude and latitude) that are correctly projected?
3) How do I specify the position relative to the axes?

To achieve my actual goal:
4) In order to make the sphere with a given radius tangent at a user-specified point, I guess I have to calculate the position in the axes coordinate system via some external program (python ideally). How do I get that information into LateX?
5) Is there a way to do all this in python alone and get a vector graphic out that looks as great as what you get with tikz?

Sorry for the long post, but answers to at least 1-3 would be much appreciated.

\documentclass{standalone}

\usepackage{amsmath}
\usepackage{pgfplots}
\pgfplotsset{compat=newest}

\begin{document}
    \begin{tikzpicture}
        \begin{axis}
            \addplot3 [
                surf,
                shader=faceted,
                samples=25,
                domain=-4:4,
                y domain=-4:4
                ] {x^2-y^2};
            \filldraw[ball color=white] (-140,1090) circle [radius=0.25cm];
        \end{axis}
   \end{tikzpicture}
\end{document}

enter image description here

Best Answer

I'd recommend asymptote for this. All one has to do is to move to some point on the surface (with coordinates myx and myy in the code below) and then go radius units along the normal of that surface, and to draw a sphere there. (With improved(?) output.)

enter image description here

\documentclass[border=3.14pt]{standalone}
\usepackage{asypictureB}
\begin{document}
\begin{asypicture}{name=AsyPlot}
import three;
import graph3;
import grid3;
import palette;
import solids;
unitsize(1cm);
settings.outformat="pdf";
defaultrender.merge=true;
size(12cm,IgnoreAspect);
currentprojection=perspective(4,-6,4);
real f(pair z) {return 0.1*(z.x^2-z.y^2);}
// adopted from https://tex.stackexchange.com/a/212348/121799   
triple normalf(pair z) {
    static real dx=sqrtEpsilon, dy=dx;
    return (-(f((z.x+dx,z.y))-f((z.x-dx,z.y)))/2dx,
         -(f((z.x,z.y+dy))-f((z.x,z.y-dy)))/2dy,
         1);
    }   
real r1=0.5, myx=-1.0, myy=-2.0; // x-y location of the sphere and radius
triple v1=(myx,myy,f((myx,myy)))+r1*normalf((myx,myy));
triple fs(pair t){ //parametrization of a shifted sphere
  return v1+r1*(cos(t.x)*sin(t.y),sin(t.x)*sin(t.y),cos(t.y));
}
surface s1=surface(fs,(0,0),(2pi,pi),8,Spline);
surface s=surface(f,(-4,-4),(4,4),Spline);
xaxis3(XYZero(extend=true),red,Arrow3);
yaxis3(XYZero(extend=true),red,Arrow3);
zaxis3(XYZero(extend=true),red,Arrow3);
s.colors(palette(s.map(abs),Wheel()));
draw(s,render(compression=Low,merge=true));
draw(s1
  ,gray+opacity(0.25)
  ,render(merge=true), meshpen=0.6*white
);
\end{asypicture}
\end{document}

Just for fun: an animated version, almost impossible to do with pgfplots IMHO.

enter image description here

You can also use pgfplots, but ultimately you will always be limited by the fact that this has no true 3D engine. To make the line thinner, you can adjust line width. To place the sphere in the coordinate system, use axis cs:. (The problem, though, is that the radius does not get translated.) You can draw circles in the plot, the problem is to project on the visible parts. There are ways to achieve this, yet it will not be too easy to marry them to pgfplots. This has to do with the fact that there all sorts of rotated scopes are used, which interfere with the coordinate transformations made by pgfplots.

enter image description here

\documentclass{standalone}

\usepackage{amsmath}
\usepackage{pgfplots}
\pgfplotsset{compat=newest}

\begin{document}
    \begin{tikzpicture}
        \begin{axis}
            \addplot3 [
                surf,
                shader=faceted,
                samples=25,
                domain=-4:4,
                y domain=-4:4
                ] {x^2-y^2};
            \filldraw[ball color=white,line width=0.1pt] (axis
            cs:-1.40,-1.4,0.25) circle [radius=0.25cm];
            \addplot3 [line width=0.1pt,domain=70:250,samples y=0] ({-1.4+0.38*sin(x)},
            {-1.4+0.38*cos(x)},0.25);
        \end{axis}
   \end{tikzpicture}
\end{document}