2

I'm trying to plot a complex function and to that end I'm using pgfmathdeclarefunction. Still, I'm unable to get it to work, I get the error:

! Illegal parameter number in definition of \pgfmathNi@.

I start wondering whether what I'm trying to do is even possible: to call a function within another function in the definition of pgfmathdeclarefunction. This is the MWE:

\documentclass{standalone}

\usepackage{pgfplots}

\pgfmathdeclarefunction{detG}{8}{%
  \pgfmathparse{#1*(#7*(#4 - #6)*(#2 - #8) - #5*(#2 - #6)*(#4 - #8) + #3*(#2 - #4)*(#6 - #8)) + #3*#5*(#4 - #6)*(#2 - #8) - #3*#7*(#2 - #6)*(#4 - #8) + #5*#7*(#2 - #4)*(#6 - #8)
  }%
}

\pgfmathdeclarefunction{Hii}{8}{%
  \pgfmathparse{#5*#7*#4*(#6 - #8) + #3*#5*(#4 - #6)*#8 + #3*#7*#6*(-#4 + #8)
  }%
}

\pgfmathdeclarefunction{Hji}{8}{%
  \pgfmathparse{#3*#4*(#6 - #8) + #7*(#4 - #6)*#8 + #5*#6*(-#4 + #8)
  }%
}

\pgfmathdeclarefunction{Hki}{8}{%
  \pgfmathparse{#3*#5*(-#4 + #6) + #3*#7*(#4 - #8) + #5*#7*(-#6 + #8)
  }%
}

\pgfmathdeclarefunction{Hli}{8}{%
  \pgfmathparse{#7*(-#4 + #6) + #5*(#4 - #8) + #3*(-#6 + #8)
  }%
}

\pgfmathdeclarefunction{Ni}{10}{%
  \pgfmathparse{Hii(#1,#2,#3,#4,#5,#6,#7,#8) + Hji(#1,#2,#3,#4,#5,#6,#7,#8)*#9 + Hki(#1,#2,#3,#4,#5,#6,#7,#8)*#10 + Hli(#1,#2,#3,#4,#5,#6,#7,#8)*#9*#10
  }%
}


\begin{document}

\begin{tikzpicture}[]
\begin{axis}[]

\addplot3[surf,domain=0:1, samples=20] { Ni(-1,-1,0,-1,0,0,-1,0,x,y) / detG(-1,-1,0,-1,0,0,-1,0)};

\end{axis}

\end{tikzpicture}

\end{document}

EDIT Thanks to the answer provided by @Qrrbrbirlbel I could plot one function. I managed to generalize the code to plot 4 of these functions (very similar). The functions should make a tent, so that each function plotted in its own square domain has a value of 1 at coordinate (0,0). This is the result I have so far, and although it works, there is a lot of repeated code:

4 functions Ni, Nj, Nk, and Nl

and the current code:

\documentclass[tikz]{standalone}
\usepackage{pgfplots}

\pgfmathdeclarefunction{detGi}{8}{%
  \pgfmathparse{-(#1*(#7*(#4-#6)*(#2-#8)-#5*(#2-#6)*(#4-#8)+#3*(#2-#4)*(#6-#8))
    +#3*#5*(#4-#6)*(#2-#8)-#3*#7*(#2-#6)*(#4-#8)+#5*#7*(#2-#4)*(#6-#8))}}

\pgfmathdeclarefunction{detGj}{8}{%
  \pgfmathparse{-(#1*(#7*(#4-#6)*(#2-#8)-#5*(#2-#6)*(#4-#8)+#3*(#2-#4)*(#6-#8))
    +#3*#5*(#4-#6)*(#2-#8)-#3*#7*(#2-#6)*(#4-#8)+#5*#7*(#2-#4)*(#6-#8))}}

\pgfmathdeclarefunction{detGk}{8}{%
  \pgfmathparse{-(#1*(#7*(#4-#6)*(#2-#8)-#5*(#2-#6)*(#4-#8)+#3*(#2-#4)*(#6-#8))
    +#3*#5*(#4-#6)*(#2-#8)-#3*#7*(#2-#6)*(#4-#8)+#5*#7*(#2-#4)*(#6-#8))}}

\pgfmathdeclarefunction{detGl}{8}{%
  \pgfmathparse{-(#1*(#7*(#4-#6)*(#2-#8)-#5*(#2-#6)*(#4-#8)+#3*(#2-#4)*(#6-#8))
    +#3*#5*(#4-#6)*(#2-#8)-#3*#7*(#2-#6)*(#4-#8)+#5*#7*(#2-#4)*(#6-#8))}}

\pgfmathdeclarefunction{Hii}{8}{%
  \pgfmathparse{#5*#7*#4*(#6-#8)+#3*#5*(#4-#6)*#8+#3*#7*#6*(-#4+#8)}}
\pgfmathdeclarefunction{Hji}{8}{%
  \pgfmathparse{#3*#4*(#6-#8)+#7*(#4-#6)*#8+#5*#6*(-#4+#8)}}
\pgfmathdeclarefunction{Hki}{8}{%
  \pgfmathparse{#3*#5*(-#4+#6)+#3*#7*(#4-#8)+#5*#7*(-#6+#8)}}
\pgfmathdeclarefunction{Hli}{8}{%
  \pgfmathparse{#7*(-#4+#6)+#5*(#4-#8)+#3*(-#6+#8)}}

\pgfmathdeclarefunction{Hij}{8}{%
  \pgfmathparse{#1*#7*#6*(#2-#8)+#1*#5*(-#2+#6)*#8+#5*#7*#2*(-#6+#8)}}
\pgfmathdeclarefunction{Hjj}{8}{%
  \pgfmathparse{#5*#6*(#2-#8)+#7*(-#2+#6)*#8+#1*#2*(-#6+#8)}}
\pgfmathdeclarefunction{Hkj}{8}{%
  \pgfmathparse{#1*#5*(#2-#6)+#5*#7*(#6-#8)+#1*#7*(-#2+#8)}}
\pgfmathdeclarefunction{Hlj}{8}{%
  \pgfmathparse{#7*(#2-#6)+#1*(#6-#8)+#5*(-#2+#8)}}

\pgfmathdeclarefunction{Hik}{8}{%
  \pgfmathparse{#3*#7*#2*(#4-#8)+#1*#3*(#2-#4)*#8+#1*#7*#4*(-#2+#8)}}
\pgfmathdeclarefunction{Hjk}{8}{%
  \pgfmathparse{#1*#2*(#4-#8)+#7*(#2-#4)*#8+#3*#4*(-#2+#8)}}
\pgfmathdeclarefunction{Hkk}{8}{%
  \pgfmathparse{#1*#3*(-#2+#4)+#1*#7*(#2-#8)+#3*#7*(-#4+#8)}}
\pgfmathdeclarefunction{Hlk}{8}{%
  \pgfmathparse{#7*(-#2+#4)+#3*(#2-#8)+#1*(-#4+#8)}}

\pgfmathdeclarefunction{Hil}{8}{%
  \pgfmathparse{#1*#5*#4*(#2-#6)+#1*#3*(-#2+#4)*#6+#3*#5*#2*(-#4+#6)}}
\pgfmathdeclarefunction{Hjl}{8}{%
  \pgfmathparse{#3*#4*(#2-#6)+#5*(-#2+#4)*#6+#1*#2*(-#4+#6)}}
\pgfmathdeclarefunction{Hkl}{8}{%
  \pgfmathparse{#1*#3*(#2-#4)+#3*#5*(#4-#6)+#1*#5*(-#2+#6)}}
\pgfmathdeclarefunction{Hll}{8}{%
  \pgfmathparse{#5*(#2-#4)+#1*(#4-#6)+#3*(-#2+#6)}}



\makeatletter
\pgfmathdeclarefunction{Ni}{2}{%
  \begingroup
    \def\vo##1{\pgfkeysvalueof{/pgfplots/helper/##1}}% shortcut for here
    \pgfmathparse{\vo{Hii}+\vo{Hji}*#1+\vo{Hki}*#2+\vo{Hli}*#1*#2}%
    \pgfmathsmuggle\pgfmathresult
  \endgroup
}
\pgfmathdeclarefunction{NiDet}{2}{%
  \begingroup
    \pgfmathNi@{#1}{#2}%
    \pgfmathdivide@{\pgfmathresult}{\pgfkeysvalueof{/pgfplots/helper/detGi}}%
    \pgfmathsmuggle\pgfmathresult
  \endgroup
}

\pgfmathdeclarefunction{Nj}{2}{%
  \begingroup
    \def\vo##1{\pgfkeysvalueof{/pgfplots/helper/##1}}% shortcut for here
    \pgfmathparse{\vo{Hij}+\vo{Hjj}*#1+\vo{Hkj}*#2+\vo{Hlj}*#1*#2}%
    \pgfmathsmuggle\pgfmathresult
  \endgroup
}
\pgfmathdeclarefunction{NjDet}{2}{%
  \begingroup
    \pgfmathNj@{#1}{#2}%
    \pgfmathdivide@{\pgfmathresult}{\pgfkeysvalueof{/pgfplots/helper/detGj}}%
    \pgfmathsmuggle\pgfmathresult
  \endgroup
}

\pgfmathdeclarefunction{Nk}{2}{%
  \begingroup
    \def\vo##1{\pgfkeysvalueof{/pgfplots/helper/##1}}% shortcut for here
    \pgfmathparse{\vo{Hik}+\vo{Hjk}*#1+\vo{Hkk}*#2+\vo{Hlk}*#1*#2}%
    \pgfmathsmuggle\pgfmathresult
  \endgroup
}
\pgfmathdeclarefunction{NkDet}{2}{%
  \begingroup
    \pgfmathNk@{#1}{#2}%
    \pgfmathdivide@{\pgfmathresult}{\pgfkeysvalueof{/pgfplots/helper/detGk}}%
    \pgfmathsmuggle\pgfmathresult
  \endgroup
}

\pgfmathdeclarefunction{Nl}{2}{%
  \begingroup
    \def\vo##1{\pgfkeysvalueof{/pgfplots/helper/##1}}% shortcut for here
    \pgfmathparse{\vo{Hil}+\vo{Hjl}*#1+\vo{Hkl}*#2+\vo{Hll}*#1*#2}%
    \pgfmathsmuggle\pgfmathresult
  \endgroup
}
\pgfmathdeclarefunction{NlDet}{2}{%
  \begingroup
    \pgfmathNl@{#1}{#2}%
    \pgfmathdivide@{\pgfmathresult}{\pgfkeysvalueof{/pgfplots/helper/detGl}}%
    \pgfmathsmuggle\pgfmathresult
  \endgroup
}

\pgfkeys{
  /handlers/.pgfmath/.code=%
    \pgfmathparse{#1}\expandafter\pgfkeys@exp@call\expandafter{\pgfmathresult},
  /handlers/.pgfmath fpu/.code=%
    \begingroup\pgfset{fpu}\pgfmathparse{#1}\expandafter\endgroup
    \expandafter\pgfkeys@exp@call\expandafter{\pgfmathresult}}
\makeatother

\begin{document}
\begin{tikzpicture}
\begin{axis}

% plot Nj in [-1,0]x[0,1]
\pgfplotsset{
  helper/Hij/.initial=0,  helper/Hjj/.initial=0,
  helper/Hkj/.initial=0,  helper/Hlj/.initial=0,
  helper/detGj/.initial=0,
  prepare matrix/.style={
    helper/Hij/.pgfmath fpu={Hij(#1)}, helper/Hjj/.pgfmath fpu={Hjj(#1)},
    helper/Hkj/.pgfmath fpu={Hkj(#1)}, helper/Hlj/.pgfmath fpu={Hlj(#1)},
    helper/detGj/.pgfmath fpu={detGj(#1)}
    }}
  
\addplot3[surf, domain=-1:0, y domain=0:1, samples=20, prepare matrix={-1,0,0,0,0,1,-1,1}]
  {NjDet(x,y)};
  
% plot Ni in [0,1]x[0,1]
\pgfplotsset{
  helper/Hii/.initial=0,  helper/Hji/.initial=0,
  helper/Hki/.initial=0,  helper/Hli/.initial=0,
  helper/detGi/.initial=0,
  prepare matrix/.style={
    helper/Hii/.pgfmath fpu={Hii(#1)}, helper/Hji/.pgfmath fpu={Hji(#1)},
    helper/Hki/.pgfmath fpu={Hki(#1)}, helper/Hli/.pgfmath fpu={Hli(#1)},
    helper/detGi/.pgfmath fpu={detGi(#1)}
    }}
  
\addplot3[surf, domain=0:1, y domain=0:1, samples=20, prepare matrix={0,0,1,0,1,1,0,1}]
  {NiDet(x,y)};
  
  
% plot Nk in [-1,0]x[-1,0]
\pgfplotsset{
  helper/Hik/.initial=0,  helper/Hjk/.initial=0,
  helper/Hkk/.initial=0,  helper/Hlk/.initial=0,
  helper/detGk/.initial=0,
  prepare matrix/.style={
    helper/Hik/.pgfmath fpu={Hik(#1)}, helper/Hjk/.pgfmath fpu={Hjk(#1)},
    helper/Hkk/.pgfmath fpu={Hkk(#1)}, helper/Hlk/.pgfmath fpu={Hlk(#1)},
    helper/detGk/.pgfmath fpu={detGk(#1)}
    }}

\addplot3[surf, domain=-1:0, y domain=-1:0, samples=20, prepare matrix={-1,-1,0,-1,0,0,-1,0}]
  {NkDet(x,y)};
  
% plot Nl in [0,1]x[-1,0]
\pgfplotsset{
  helper/Hil/.initial=0,  helper/Hjl/.initial=0,
  helper/Hkl/.initial=0,  helper/Hll/.initial=0,
  helper/detGl/.initial=0,
  prepare matrix/.style={
    helper/Hil/.pgfmath fpu={Hil(#1)}, helper/Hjl/.pgfmath fpu={Hjl(#1)},
    helper/Hkl/.pgfmath fpu={Hkl(#1)}, helper/Hll/.pgfmath fpu={Hll(#1)},
    helper/detGl/.pgfmath fpu={detGl(#1)}
    }}
  
\addplot3[surf, domain=0:1, y domain=-1:0, samples=20, prepare matrix={0,-1,1,-1,1,0,0,0}]
  {NlDet(x,y)};

  
\end{axis}
\end{tikzpicture}
\end{document}
2
  • Since the det functions are the same, you don't need four of them. You can do helper/detGk/.pgfmath fpu={detG(#1)} and similar for the others, too. I'm surprised that the other functions are very similar but don't just reorder their arguments. I was hoping Hji(1,2,3,4,5,6,7,8) = Hii(3,4,5,6,1,2,7,8) but I guess not … Commented Sep 1, 2022 at 8:37
  • Yes that helped reduce the number of functions to only one detG. Commented Sep 1, 2022 at 10:22

1 Answer 1

3

The #10 won't work (that's a TeX limitation), the PGFmanual states

For functions with more than nine arguments, or functions with a variable number of arguments, these macros are only defined as taking one argument. The public macro expects its arguments to be comma separated, for example, \pgfmathVariableArgs{1.1,3.5,-1.5,2.6}. Each argument is parsed and passed on to the private macro as follows: \pgfmathVariableArgs@{{1.1}{3.5}{-1.5}{2.6}}. This means that some “extra work” will be required to access each argument (although it is a fairly simple task).

It really isn't too hard to convert. For convenience I changed the order of the arguments, they're now Ni(x,y,…).

\makeatletter
\pgfmathdeclarefunction{Ni}{10}{%
  \begingroup
%      \typeout{Input: -#1-}%
      % get the last eight arguments
      \edef\pgfmath@temp{\pgfmath@util@lasteight#1\relax}%
      % and use them with Hii
      \expandafter\pgfmathHii@\pgfmath@temp
      % and save their result
      \let\pgfmath@Hii\pgfmathresult
      % and Hji
      \expandafter\pgfmathHji@\pgfmath@temp
      \let\pgfmath@Hji\pgfmathresult
      % and Hki
      \expandafter\pgfmathHki@\pgfmath@temp
      \let\pgfmath@Hki\pgfmathresult
      % and Hli
      \expandafter\pgfmathHli@\pgfmath@temp
      \let\pgfmath@Hli\pgfmathresult
      %
      % get the first (x)
      \edef\pgfmath@temp{\pgfmath@util@firstofmany#1\relax}%
      % multiply it with Hji
      \pgfmathmultiply@{\pgfmath@temp}{\pgfmath@Hji}%
      \let\pgfmath@Hji\pgfmathresult
      % and Hli
      \pgfmathmultiply@{\pgfmath@temp}{\pgfmath@Hli}%
      \let\pgfmath@Hli\pgfmathresult
      %
      % get the second (y)
      \edef\pgfmath@temp{\pgfmath@util@secondofmany#1\relax}%
      % multiply it with Hki
      \pgfmathmultiply@{\pgfmath@temp}{\pgfmath@Hki}%
      \let\pgfmath@Hki\pgfmathresult
      % and also with Hli (which was already multiplied with the first)
      \pgfmathmultiply@{\pgfmath@temp}{\pgfmath@Hli}%
      \let\pgfmath@Hli\pgfmathresult
      %
      % add it all together (\pgfmathadd@ ...)
      \pgfmathparse{\pgfmath@Hii+\pgfmath@Hji+\pgfmath@Hki+\pgfmath@Hli}%
%      \typeout{Result: \pgfmathresult}%
      \pgfmathsmuggle\pgfmathresult
  \endgroup
}
\def\pgfmath@util@lasteight#1#2#3\relax{#3}%
\def\pgfmath@util@firstofmany#1#2\relax{#1}%
\def\pgfmath@util@secondofmany#1#2#3\relax{#2}%
\makeatother

Basically, we're using three helper macros that return

  • all but the first two
  • just the first (x) or
  • just the second (y)

argument. Since in the first case we have these arguments in the form of {1}{2}{3}{…}{8} we should use them directly with \pgfmathHii or \pgfmathHii@ and we cannot use \pgfmathparse. The rest of the function is just multiplications and additions.

We can then use it as such:

\addplot3[surf, domain=-1:1, y domain=-1:1, samples=41]
  {Ni(abs(x),abs(y),0,0,1,0,1,1,0,1)/det(0,0,1,0,1,1,0,1)};

That said, I think the following approach using pre-calculated values is better, it certainly is faster (factor 3).


Either way, since most of these values are fixed and not dependent on x and y I'd circumvent the problem by using a two-parameter function Nxy(x,y) (and later NxyDet(x,y) that includes the det factor) that uses values stored in some value-keys.

Additionally, instead of storing all eight other parameters, I will precalculate the fixed parts (since neither det, factor, factorx, factory nor factorxy is dependent on x or y).

To make it easier to evaluate and store the returned value in a value-key I'm using a special key handler .pgfmath – or rather .pgfmath fpu because PGFPlots uses fpu internally – that evaluates the given value and returns the result to the key.

The function Nxy just uses these four values and adds those according to your original function

Nxy(x, y) = factor + factorx * x + factory * y + factorxy * x * y

Inside of the defintion of Nxy I define a shortcut macro for \pgfkeysvalueof which will not survive this function definition since it is only defined inside the group.

Since the factor det is also fixed and not dependent of x or y, I'll also provide a NxyDet function that uses our own custom Nxy function and just divides its return by the pre-calculated det value.


When you \pgfdeclare a function{<name>} two macros will be created:

  1. \pgfmath<name> and
  2. \pgfmath<name>@.

The first one is the public interface where we can use any other PGFmath expression, e.g. \pgfmathNxy{1+2}{17/2*sqrt(2)}, which will be evaluated and parsed by PGFmath as usual (and just saves on parsing step compared to \pgfmathparse{Nxy(1+2, 17/2*sqrt(2))}).

The second version only accepts already evaluated parameters (and is used internally by \pgfmath<name>). In the body of \pgfdeclarefunction we actually define the second version which will be wrapped by PGFMath in the first version and we can expect #1 and #2 to be already parsed and evaluated and to be containing only a value.

And, thus, we can use directly \pgfmathNxy@ in NxyDet and save us another parsing step.

We could have just written

\pgfmathparse{Nxy(#1,#2)/\pgfkeysvalueof{/pgfplots/helper/det}}

too and that would work as well.


Instead of .pgfmath fpu we could have used

prepare matrix/.style={
  /utils/exec=\pgfset{fpu}\pgfmathparse{Hii(#1)},
  helper/Hii/.expanded=\pgfmathresult,
  /utils/exec=\pgfmathparse{Hji(#1)},
  helper/Hji/.expanded=\pgfmathresult,
  /utils/exec=\pgfmathparse{Hki(#1)},
  helper/Hki/.expanded=\pgfmathresult,
  /utils/exec=\pgfmathparse{Hli(#1)},
  helper/Hli/.expanded=\pgfmathresult,
  /utils/exec=\pgfmathparse{detG(#1)}\pgfset{fpu=false},
  helper/detG/.expanded=\pgfmathresult,
}

or any other way to calculate five values and store them somewhere like

prepare matrix/.code={
  \pgfset{fpu}%
  \pgfmathsetmacro\myHii{Hii(#1)}%
  \pgfmathsetmacro\myHji{Hji(#1)}%
  \pgfmathsetmacro\myHki{Hki(#1)}%
  \pgfmathsetmacro\myHli{Hli(#1)}%
  \pgfmathsetmacro\mydetG{detG(#1)}%
  \pgfset{fpu=false}%
}

and then juse use these macros but PGFkeys makes it pretty simple in my opinion and then we already have proper namespaced macros/keys.

Code

\documentclass[tikz]{standalone}
\usepackage{pgfplots}
\pgfmathdeclarefunction{det}{8}{%
  \pgfmathparse{-(#1*(#7*(#4-#6)*(#2-#8)-#5*(#2-#6)*(#4-#8)+#3*(#2-#4)*(#6-#8))
    +#3*#5*(#4-#6)*(#2-#8)-#3*#7*(#2-#6)*(#4-#8)+#5*#7*(#2-#4)*(#6-#8))}}
\pgfmathdeclarefunction{Hii}{8}{\pgfmathparse{#5*#7*#4*(#6-#8)+#3*#5*( #4-#6)*#8+#3*#7*#6*(-#4+#8)}}
\pgfmathdeclarefunction{Hij}{8}{\pgfmathparse{#1*#7*#6*(#2-#8)+#1*#5*(-#2+#6)*#8+#5*#7*#2*(-#6+#8)}}
\pgfmathdeclarefunction{Hik}{8}{\pgfmathparse{#3*#7*#2*(#4-#8)+#1*#3*( #2-#4)*#8+#1*#7*#4*(-#2+#8)}}
\pgfmathdeclarefunction{Hil}{8}{\pgfmathparse{#1*#5*#4*(#2-#6)+#1*#3*(-#2+#4)*#6+#3*#5*#2*(-#4+#6)}}

\pgfmathdeclarefunction{Hji}{8}{\pgfmathparse{#3*#4*(#6-#8)+#7*( #4-#6)*#8+#5*#6*(-#4+#8)}}
\pgfmathdeclarefunction{Hjj}{8}{\pgfmathparse{#5*#6*(#2-#8)+#7*(-#2+#6)*#8+#1*#2*(-#6+#8)}}
\pgfmathdeclarefunction{Hjk}{8}{\pgfmathparse{#1*#2*(#4-#8)+#7*( #2-#4)*#8+#3*#4*(-#2+#8)}}
\pgfmathdeclarefunction{Hjl}{8}{\pgfmathparse{#3*#4*(#2-#6)+#5*(-#2+#4)*#6+#1*#2*(-#4+#6)}}

\pgfmathdeclarefunction{Hki}{8}{\pgfmathparse{#3*#5*(-#4+#6)+#3*#7*(#4-#8)+#5*#7*(-#6+#8)}}
\pgfmathdeclarefunction{Hkj}{8}{\pgfmathparse{#1*#5*( #2-#6)+#5*#7*(#6-#8)+#1*#7*(-#2+#8)}}
\pgfmathdeclarefunction{Hkk}{8}{\pgfmathparse{#1*#3*(-#2+#4)+#1*#7*(#2-#8)+#3*#7*(-#4+#8)}}
\pgfmathdeclarefunction{Hkl}{8}{\pgfmathparse{#1*#3*( #2-#4)+#3*#5*(#4-#6)+#1*#5*(-#2+#6)}}

\pgfmathdeclarefunction{Hli}{8}{\pgfmathparse{#7*(-#4+#6)+#5*(#4-#8)+#3*(-#6+#8)}}
\pgfmathdeclarefunction{Hlj}{8}{\pgfmathparse{#7*( #2-#6)+#1*(#6-#8)+#5*(-#2+#8)}}
\pgfmathdeclarefunction{Hlk}{8}{\pgfmathparse{#7*(-#2+#4)+#3*(#2-#8)+#1*(-#4+#8)}}
\pgfmathdeclarefunction{Hll}{8}{\pgfmathparse{#5*( #2-#4)+#1*(#4-#6)+#3*(-#2+#6)}}

\makeatletter
\pgfmathdeclarefunction{Nxy}{2}{%
  \begingroup
    \def\vo##1{\pgfkeysvalueof{/pgfplots/helper/##1}}% shortcut for here
    \pgfmathparse{\vo{factor}+\vo{factorx}*#1+\vo{factory}*#2+\vo{factorxy}*#1*#2}%
    \pgfmathsmuggle\pgfmathresult
  \endgroup
}
\pgfmathdeclarefunction{NxyDet}{2}{%
  % quicker than \pgfmathparse{Nxy(#1,#2)/\pgfkeysvalueof{/pgfplots/helper/det}}
  \pgfmathNxy@{#1}{#2}%
  \pgfmathdivide@{\pgfmathresult}{\pgfkeysvalueof{/pgfplots/helper/det}}%
}

\pgfkeys{
  /handlers/.pgfmath/.code=%
    \pgfmathparse{#1}\expandafter\pgfkeys@exp@call\expandafter{\pgfmathresult},
  /handlers/.pgfmath fpu/.code=%
    \begingroup\pgfset{fpu}\pgfmathparse{#1}\expandafter\endgroup
    \expandafter\pgfkeys@exp@call\expandafter{\pgfmathresult}}
\makeatother
\pgfplotsset{
  helper/factor/.initial=0,
  helper/factorx/.initial=0,
  helper/factory/.initial=0,
  helper/factorxy/.initial=0,
  helper/det/.initial=0,
  prepare matrix/.style 2 args={
    helper/factor/.pgfmath fpu  ={Hi#1(#2)}, 
    helper/factorx/.pgfmath fpu ={Hj#1(#2)},
    helper/factory/.pgfmath fpu ={Hk#1(#2)},
    helper/factorxy/.pgfmath fpu={Hl#1(#2)},
    helper/det/.pgfmath fpu     ={det(#2)}}}
\begin{document}
\begin{tikzpicture}
\begin{axis}[every axis plot/.append style={surf, samples=20}]
\addplot3[domain=0:1, y domain=0:1,
  prepare matrix={i}{ 0, 0, 1, 0, 1, 1, 0, 1}] {NxyDet(x,y)};
\addplot3[domain=-1:0, y domain=0:1,
  prepare matrix={j}{-1, 0, 0, 0, 0, 1,-1, 1}] {NxyDet(x,y)};
\addplot3[domain=-1:0, y domain=-1:0,
  prepare matrix={k}{-1,-1, 0,-1, 0, 0,-1, 0}] {NxyDet(x,y)};
\addplot3[domain=0:1, y domain=-1:0,
  prepare matrix={l}{ 0,-1, 1,-1, 1, 0, 0, 0}] {NxyDet(x,y)};
\end{axis}
\end{tikzpicture}
\end{document}

Output

enter image description here

7
  • Would it be possible to explain the code a bit? Commented Aug 31, 2022 at 18:30
  • Thanks for the details. I've never plotted functions this way in pgfplots so I'm learning about it, before I always used the declare function within the tikzpicture options. I'm still a bit lost with the code you wrote. Suppose I have 4 functions I want to actually plot (Ni, Nj, Nk, and Nl), each one with its own and different detG, then I guess I have to replicate by 4 the code you wrote, right? Commented Sep 1, 2022 at 6:50
  • Also, it seems that we're only providing information to compute detG in prepare matrix within the addplot3 options. Does that mean that I can change these to change the computation of detG? Commented Sep 1, 2022 at 7:27
  • I managed to get the code to plot the 4 functions (see my edit). There's a lot of repeated code, and I'm not sure whether the approach is the right one since I'm using pgfplotsset just before each addplot3 command. I noticed also that I had to give a proper order for the plotting, otherwise the final result wouldn't look fine (part of functions in the back would overlap to the front). What do you think? Commented Sep 1, 2022 at 8:13
  • @Qrrbrbirlbel Could you include expressions of the functions as LaTeX output? It takes a lot of time to rewrite/guess them from the code (detG= determinant, NiDet=? ...) Commented Sep 1, 2022 at 8:50

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.