# tikz declare function with multiple outputs

Is it possible to declare a function in tikz or pgfplots with multiple outputs?

Consider the case when we want to plot samples from a probability distribution. Usually we could do something like

\documentclass{standalone}
\usepackage{tikz, pgfplots}
\begin{document}
\begin{tikzpicture}[declare function={xfun(\x)=\x; yfun(\y)=\y;}]
\begin{axis}
\addplot [only marks, samples=50] ({xfun(rnd)}, {yfun(rnd)});
\end{axis}
\end{tikzpicture}
\end{document}


However this only works when the probability distribution factorizes as p(x, y) = f(x) g(y), but I want to plot some pdfs that don't. I tried to do

\documentclass{standalone}
\usepackage{tikz, pgfplots}
\begin{document}
\begin{tikzpicture}[declare function={myfun(\x,\y)=\x+\y, \x-\y;}]
\begin{axis}
\addplot [only marks, samples=50] ({myfun(rnd, rnd)});
\end{axis}
\end{tikzpicture}
\end{document}


but that doesn't work.

It is possible to declare such functions with \pgfmathdeclarefunction. Unfortunately, pgfplots won't parse the results in the way one wants, so one needs to extract the x and y components. The good news is that this can be done by appropriately defined functions, too. They are called xcomp2 and ycomp2 since they are the 2d counterparts of the functions xcomp3 and ycomp3 from this experimental library. To illustrate things, I declared a function myfun with myfun(x,y)=(x+y,x-y),

\pgfmathdeclarefunction{myfun}{2}{%
\begingroup%
\pgfmathsetmacro{\myx}{#1+#2}%
\pgfmathsetmacro{\myy}{#1-#2}%
\edef\pgfmathresult{{\myx}{\myy}}%
\pgfmathsmuggle\pgfmathresult\endgroup}


It is used in the MWE

\documentclass[tikz,border=3mm]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.16}
\begin{document}
\pgfmathdeclarefunction{myfun}{2}{%
\begingroup%
\pgfmathsetmacro{\myx}{#1+#2}%
\pgfmathsetmacro{\myy}{#1-#2}%
\edef\pgfmathresult{{\myx}{\myy}}%
\pgfmathsmuggle\pgfmathresult\endgroup}
\pgfmathdeclarefunction{xcomp2}{2}{% x component of a 2-vector
\begingroup%
\pgfmathparse{#1}%
\pgfmathsmuggle\pgfmathresult\endgroup}
\pgfmathdeclarefunction{ycomp2}{2}{% y component of a 2-vector
\begingroup%
\pgfmathparse{#2}%
\pgfmathsmuggle\pgfmathresult\endgroup}
\begin{tikzpicture}
\begin{axis}
\end{axis}
\end{tikzpicture}
\end{document}


P.S. If you could consider posting complete MWEs I suspect other users would be much more willing to upvote your question(s).

• First of all, thank you for this solution. It really makes me think though. Why does one have to do shady stuff pgfmathsmuggle to do the simplest things. I guess I should just do all plots in matplotlib in the future.... Really wish one could just use python code within a latex document... (i know pylatex exists but that's kinda different) – Hyperplane Sep 30 '19 at 17:16
• @Hyperplane \pgfmathsmuggle is not really "shady", it helps keeping things tidy. You may ask why vector-valued functions are not supported "out of the box". The answer may be that no one made a feature request at the pgf github site. – user194703 Sep 30 '19 at 17:22
• @Hyperplane You should look into the sagetex package. This gives you Python and a computer algebra system called SAGE. My answer to the problem Contour plot of arbitrary R^3 function without gnuplot used matplotlib. With a little more work you can push plots through to tikz as well: How to plot this function containing ceiling in TikZ? – DJP Oct 1 '19 at 12:21

Here's a possible implementation using the sagetex package:

\documentclass[border=5pt]{standalone}
\usepackage{sagetex}
\usepackage[usenames,dvipsnames]{xcolor}
\usepackage{pgfplots}
\pgfplotsset{compat=1.15}
\begin{document}
\begin{sagesilent}
LowerX = 0
UpperX = 2
LowerY = -1
UpperY = 1
Scale = 1.2
xscale=1
yscale=1
L = []
####### Create the points ###############
for i in range(0,10):
for j in range(0,10):
r1 = random()
r2 = random()
L += [[r1+r2,r1-r2]]
##### Plot the points in tikz ###########
output = r""
output += r"\begin{tikzpicture}[scale=1]"
output += r"\begin{axis}[xmin=%f,xmax=%f,ymin= %f,ymax=%f]"%(LowerX,UpperX,LowerY, UpperY)
output += r"\addplot[red,only marks,mark options={mark size=.5pt}] coordinates {"
for i in range(0,len(L)-1):
output += r"(%f , %f) "%(L[i][0],L[i][1])
output += r"};"
output += r"\end{axis}"
output += r"\end{tikzpicture}"
\end{sagesilent}
\sagestr{output}
\end{document}


The output, running in Cocalc is:

Since you're working with a CAS, SAGE has lots of different types of random numbers, see here. Note that the sagesilent environment lets you program in Python. The two results are being stored as a list of length 2 inside list L. After the list of points is created, it's just a matter of incorporating them into the tikzpicture. This needs to be done as a string as sagetex involves a 3 step compilation process: first LaTeX must compile, then Sage compiles, then the final compilation involves LaTeX plus SAGE output. If an output string wasn't used, then the first attempt to compile LaTeX would fail as it relies on SAGE results that it needs but doesn't yet have.

The table of contents of the SAGE manual online; from here you can see that SAGE includes lots of open source programs including (quoting from link):

ATLAS — Automatically Tuned Linear Algebra Software.
BLAS — Basic Linear Algebra Subprograms.
FLINT — C library for doing number theory.
GAP — a system for computational discrete algebra, with particular emphasis on computational group theory.
Maxima — system for symbolic and numerical computation.
mpmath — a pure-Python library for multiprecision floating-point arithmetic.
NumPy — numerical linear algebra and other numerical computing capabilities for Python.
Pari/GP — a computer algebra system for fast computations in number theory.
Pynac — a modified version of GiNaC that replaces the dependency on CLN by Python.
R — a language and environment for statistical computing and graphics.
And many more too numerous to list here.


SAGE is not included with LaTeX, so you will either need to download a copy and install it to your computer locally OR, better yet, open a free Cocalc account and do your work in the cloud. In that case, you don't need SAGE on your computer but you will need access to the internet.