10

I would like to plot the function f: ℝ² →ℝ, definited by f(x,y)=(xy)/(x^2+y^2). But the following problem comes up:

enter image description here

At (0,0) the function is not continous and therefore it looks kind of jagged. To solve this problem i could force the function to input specific points but i can't find it anywhere an don't know if that is even possible.

Code:

\begin{tikzpicture}[]
\begin{axis}[axis lines=center,
axis on top,
xtick=\empty,
ytick=\empty,
ztick=\empty,
xrange=-2:2,
yrange=-2:2
]
% function
\addplot3[domain=-2:2,y domain=-2:2,colormap/viridis,surf,opacity=0.5,samples = 55]
{(x*y)/(x^2+y^2)};
\end{axis}
\end{tikzpicture}

How do i make this function look smooth? Any help would be greatly appreciated :)

(Just increasing the Samples doesnt do that much, and I run into the following error: TeX capacity exceeded, sorry [main memory size=3000000])

Sebastiano
  • 54,118

3 Answers3

17

The answer to the technical part of the question whether or not one can specify a special value at special points is yes. One possible way to do that is to plot something like

ifthenelse(x^2+y^2>0.05,(x*y)/(x^2+y^2),0.5*sin(2*atan2(y,x)))

which switches the expression to 0.5*sin(2*atan2(y,x)) if you are close to the origin.

The perhaps more interesting question is what to put there, or why I put 0.5*sin(2*atan2(y,x)). I added the explanation in LaTeX.

\documentclass[tikz,border=3mm]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.17}
\begin{document}
\begin{tikzpicture}[]
\begin{axis}[axis lines=center,
axis on top,
xtick=\empty,
ytick=\empty,
ztick=\empty,
xrange=-2:2,
yrange=-2:2
]
% function
\addplot3[domain=-2:2,y domain=-2:2,colormap/viridis,surf,opacity=0.5,samples = 55]
{ifthenelse(x^2+y^2>0.05,(x*y)/(x^2+y^2),0.5*sin(2*atan2(y,x)))};
\end{axis}
\node[align=left,above,text width=10cm] at (current axis.north) 
{In polar coordinates,
\[x=r\,\cos\varphi\quad\mbox{and}\quad y=r\,\sin\varphi\;,\]
such that
\[\frac{x\,y}{x^2+y^2}=\frac{r^2\,\cos\varphi\,\sin\varphi}{r^2}=\cos\varphi\,\sin\varphi\]
with $\varphi=\arctan(y/x)$. So we can replace
\[\frac{x\,y}{x^2+y^2}\to \sin(2\arctan(y/x))/2\;.\]
};
\end{tikzpicture}

\begin{tikzpicture}[]
\begin{axis}[axis lines=center,
axis on top,
xtick=\empty,
ytick=\empty,
ztick=\empty,
xrange=-2:2,
yrange=-2:2
]
% function
\addplot3[domain=-2:2,y domain=-2:2,colormap/viridis,surf,opacity=0.5,samples = 55]
{0.5*sin(2*atan2(y,x))};
\end{axis}

\end{tikzpicture}
\end{document}

enter image description here

As you can see from the lower plot, you do not need x*y/(x^2+y^2) at all, you can plot 0.5*sin(2*atan2(y,x)) over the full domain and get a non-jagged result.

  • 6
    +1: This is much more than LaTeX help :) – Dr. Manuel Kuehner May 30 '20 at 17:00
  • First of all: Thank you :) Very clever usage of polar coordinates. To see my attempt at fixing this problem, with the help of your method, look below. – Wizard of Math May 31 '20 at 10:32
  • 2
    Though your answer is (as always :)) very great, I can't figure the difference between the two plots ^^ – BambOo Jun 01 '20 at 14:40
  • 1
    @BambOo Between which plots? Between the two in the answer? There is none. Between the one by the OP and the ones in the answer? Only a slight difference. There is no "pole", of course. But the value at x=y=0 is undefined. The problem is avoided by letting TikZ decide what atan2(0,0) is. You can choose another prescription, which is what the OP did in their own answer. Neither prescription is "correct". The issue addressed here is to get rid of the fake pole, which the answer does. –  Jun 01 '20 at 14:50
  • 1
    I guess I was wainting for too much difference ^^. Those atan2 confuse me sometimes... but they are very useful to avoid singularities – BambOo Jun 01 '20 at 15:20
  • 1
    @BambOo As I said, there is no singularity (in the sense something/0), it is just that pgfplots thinks there is one simply because the denominator becomes 0 for x=y=0. In the polar representation one can see that the expression is finite for x=y=0. It is, however, not well-defined or uniquely defined as it is basically determined by the phase of the complex number z=0. –  Jun 01 '20 at 15:47
  • 1
    @Schrödinger'scat, I can only agree with you, I actually worked on some trigonometry last week involving those very steps... Some identity between A*cos(x)+B*sin(x) transformed into a single C*sin(x+\phi) :) – BambOo Jun 01 '20 at 15:52
7

There is some jaggedness to the graph when I run it through the computer algebra system (CAS) called SAGE, so you should expect some in pgfplots enter image description here

To increase the precision of the result you can have SAGE generate the x and y coordinates or you can do them yourself. I used the command xcoords = [i for i in srange(-2,2,.06)] but you could just have easily specified xcoords = [-2,-.75,-.1,.1,.36,1,2]. By forcing the pgfplots through SAGE you have more control over the plot. (EDIT: Although the sagetex package is part of the LaTeX distribution, SAGE is not). The easiest way to work with it is through Cocalc. If you are working with mathematical topics this is a good tool to get familiar with.

\documentclass[border=5pt]{standalone}
\usepackage{pgfplots}
\usepackage{sagetex}
\pgfplotsset{compat=1.15} 
\begin{document}
\begin{sagesilent}
xcoords = [i for i in srange(-2,2,.06)]
ycoords = [i for i in srange(-2,2,.05)]

output = ""
output += r"\begin{tikzpicture}[scale=1.0]"
output += r"\begin{axis}[view={30}{45},xmin=%d, xmax=%d, ymin=%d, ymax=%d]"%(-2,2,-2,2)
output += r"\addplot3[colormap/viridis,surf,opacity=0.5,mesh/rows=%d] coordinates {"%(len(ycoords))
# the length of ycoords is the number of y values
for y in ycoords:
    for x in xcoords:
        output += r"(%f, %f, %f) "%(x,y,x*y/(x^2+y^2))

output += r"};"
output += r"\end{axis}"
output += r"\end{tikzpicture}"
\end{sagesilent}
\sagestr{output}
\end{document}

which looks like this:

enter image description here

I thought the plot looked better with just surf

enter image description here

The documentation for SAGE 3d plots is here.

DJP
  • 12,451
  • Thank you a lot :) I have never used or heard of sagetex but i am reading up on it now. I think this is kind of difficult to understand but comes with the benefit that you can tweak a lot of settings which is incredibly useful. – Wizard of Math May 31 '20 at 10:40
  • 1
    There is a free pdf guide that can give you an overview while avoiding the substantial documentation. Posts on this site such as here, here or here can give some ideas of how it can be used, too. – DJP May 31 '20 at 15:41
  • 2
    I put a public version of the tex file (and corresponding pdf) for the above example here: https://share.cocalc.com/share/df81e09e5b8f16f28b3a2e818dcdd4560e7818ae/support/2020-06-03-sagetex-3d/?viewer=share

    I also put a Jupyter notebook in that directory with the plot, in case you want to zoom and rotate it around. No account needed for any of this...

    – William Stein Jun 03 '20 at 21:24
2

I know it is not perfect but...

With the help of @Schrödinger's cat i came up with the following:

The line on the Inputspace that causes the problem is defined by x=y. So using the "ifthenelse" function i made:

if |x-y|< small value, then set output to 0.5

\begin{tikzpicture}[]
\begin{axis}[axis lines=center,
axis on top,
xtick=\empty,
ytick=\empty,
ztick=\empty,
xrange=-2:2,
yrange=-2:2
]
% function
\addplot3[domain=-2:2,y domain=-2:2,colormap/viridis,surf,opacity=0.5,
samples = 55]
{ifthenelse(abs(x-y)<0.1,0.5,0.5*sin(2*atan2(y,x)))};
\end{axis}
\end{tikzpicture}

So that if a input point is close to the line it just sets the output to 0.5. It still doesn't look perfect put if i now increase the resolution the Graph should look at least kind of smooth:

enter image description here