0

Short Version

I want to do some fairly complicated coordinate math to make a notional diagram but would like to use pgfplots since I have used it elsewhere in my document and want the axis styles (which I personally prefer) to match.

I do the coordinate math in tikzmath,

\begin{tikzpicture}
  \tikzmath{
    coordinate \c;
    \c0 = (0.0,0.0);
    \c1 = (1.0,1.0);
  }
  \begin{axis}[
    xmin=0,
    xmax=1,
    ymin=0,
    ymax=1]
    \draw (\c0) -- (\c1);
    \coordinate [label=$\c1$] (foo) at (0.5,0.5);
  \end{axis}
\end{tikzpicture}

but when I render this, the coordinates are not in the axis coordinate system: actual LaTeX output

I would like instead to have the following plot: desired LaTeX output

Is there a way to convert to the axis coordinate system from whatever coordinate system tikzmath uses?

Long Version

I am trying to make a plot demonstrating quadratic interpolation through a few points. Specifically, I want to show how (unlike cubic interpolation) the shape of the entire curve can be wholly determined by the derivative at one point (I choose the first point). I want to draw this curve for different values of \d0 so I figured I could make use of the cubic control points that TikZ provides (through controls) and calculate what those control points should be.

\begin{tikzpicture}
  \tikzmath{
    % coordinates
    coordinate \p;
    \p0 = (0.0,0.0);
    \p1 = (0.2,0.6);
    \p2 = (0.6,0.9);
    \p3 = (1.0,1.0);
    % dy/dx values
    real \d;
    \d0 = 1.0;
    \d1 = 2.0 * (\py1 - \py0) / (\px1 - \px0) - \d0;
    \d2 = 2.0 * (\py2 - \py1) / (\px2 - \px1) - \d1;
    \d3 = 2.0 * (\py3 - \py2) / (\px3 - \px2) - \d2;
    % https://math.stackechange.com/a/336679/475643
    % quadratic control points
    coordinate \q;
    \q1 = ({(\px0 + \px1) / 2.0}, {\py0 + \d0 * (\px1 - \px0) / 2.0});
    \q2 = ({(\px1 + \px2) / 2.0}, {\py1 + \d1 * (\px2 - \px1) / 2.0});
    \q3 = ({(\px2 + \px3) / 2.0}, {\py2 + \d2 * (\px3 - \px2) / 2.0});
    % cubic control points, lefthand side
    coordinate \s;
    \s1 = {(2 / 3 * \q1) + (1 / 3 * \p0)};
    \s2 = {(2 / 3 * \q2) + (1 / 3 * \p1)};
    \s3 = {(2 / 3 * \q3) + (1 / 3 * \p2)};
    % cubic control points, righthand side
    coordinate \r;
    \r1 = {(2 / 3 * \q1) + (1 / 3 * \p1)};
    \r2 = {(2 / 3 * \q2) + (1 / 3 * \p2)};
    \r3 = {(2 / 3 * \q3) + (1 / 3 * \p3)};
  }
  \begin{axis}[
    xmin=0,
    xmax=60,
    ymin=0,
    ymax=60,
    width=\textwidth,
    height=\textwidth]
    % https://math.stackexchange.com/q/335226/475643
    \draw (axis cs:\p0) .. controls (axis cs:\s1) and (axis cs:\r1) .. (axis cs:\p1);
    \draw (axis cs:\p1) .. controls (axis cs:\s2) and (axis cs:\r2) .. (axis cs:\p2);
    \draw (axis cs:\p2) .. controls (axis cs:\s3) and (axis cs:\r3) .. (axis cs:\p3);
    % datapoints
    \draw (axis cs:\p0) node[circle,fill,scale=0.5,label=above:$P_{0}$] {};
    \draw (axis cs:\p1) node[circle,fill,scale=0.5,label=above:$P_{1}$] {};
    \draw (axis cs:\p2) node[circle,fill,scale=0.5,label=above:$P_{2}$] {};
    \draw (axis cs:\p3) node[circle,fill,scale=0.5,label=above:$P_{3}$] {};
  \end{axis}
\end{tikzpicture}

If you ignore the bug in computing the control points (still working on it), it seems to plot everything correctly up to some scale factor:

more complex actual LaTeX output

4
  • Axis cs coordinates are only defined inside the axis environment, and tikzmath wouldn't use them anyway. You can compute x and y values using \pgfmathsetmacro (but not \pgfmathsetlengthmacro) and use them inside the axis environment, but coordinates are always screen coordinates. Commented May 14, 2023 at 18:04
  • 1
    Maybe there's a better approach. What are you trying to achieve? Commented May 14, 2023 at 18:29
  • TikZmath uses the current coordinate system, at the place it is used. In your case it uses the xyz coordinate system (without units) which is mapped to the canvas coordinate system (with units). Even if you move your TikZmath inside the axis environment, it will do weird things. At best you need to force the use of the axis coordinate system: \draw[green] (axis cs: \c0) -- (axis cs: \c1); Commented May 14, 2023 at 18:38
  • @Qrrbrbirlbel I've updated the post with the particular problem I'm trying to solve.
    – segfault
    Commented May 14, 2023 at 19:45

1 Answer 1

1
  • The \tikzmath statement needs to be inside the axis environment.

    This seems to make TikZ math to interpret the coordinate specifications one-to-one, i.e. 1pt = 1. All the following coordinate calculation will be taken out in the canvas coordinate system of PGF/TikZ.

  • When a coordinate like (\s2) is used inside a TikZ path that will result in (0.3333pt, 1.26666pt), i.e. a coordinate in the aforementioned canvas coordinate system. Forcing PGF/TikZ to interpret this in the axis coordinate system by specifying axis cs: explicitly will turn this back to a PGFPlots coordinate (i.e. 1 = 1pt).

    Whether this is and the points before is a nice side effect of how PGFPlots axis coordinate system is implemented or a lucky accident remains to be seen. Expect this not to work properly in more complex cases (3d won't work at all, numbers greather than 16000-ish won't work either).

  • The coordinate calculations for r and s are not correct: \s1 = {(2 / 3 * \q1) + (1 / 3 * \p0)}; will result into

    \s1 = {(2 / 3 * \qx1, \qy1) + (1 / 3 * \px0, \py0)};
    

    which is probably interpreted as the addition of the two coordinates (2 / 3 * \qx1, \qy1) and (1 / 3 * \px0, \py0), i.e. the factor 1/3 is only applied to the x variable.

When the calc library is loaded the “normal” coordinate calculations will be available:

  \s1 = ($2 / 3 *(\q1) + 1 / 3 *(\p0)$);
  \s2 = ($2 / 3 *(\q2) + 1 / 3 *(\p1)$);
  \s3 = ($2 / 3 *(\q3) + 1 / 3 *(\p2)$);

Note that there's no space between * and ( as per the manual.

Code

\documentclass[tikz]{standalone}
\usetikzlibrary{calc, math}
\usepackage{pgfplots}
\pgfplotsset{compat=newest}
\begin{document}
\begin{tikzpicture}
\begin{axis}[
  xmin=0, xmax=1, ymin=0, ymax=2,
  width=\textwidth,
  height=\textwidth]
\tikzmath{
  % coordinates
  coordinate \p;
  \p0 = (0.0,0.0);
  \p1 = (0.2,0.6);
  \p2 = (0.6,0.9);
  \p3 = (1.0,1.0);
  % dy/dx values
  real \d;
  \d0 = 1.0;
  \d1 = 2.0 * (\py1 - \py0) / (\px1 - \px0) - \d0;
  \d2 = 2.0 * (\py2 - \py1) / (\px2 - \px1) - \d1;
  \d3 = 2.0 * (\py3 - \py2) / (\px3 - \px2) - \d2;
  % https://math.stackexchange.com/a/336679/475643
  % quadratic control points
  coordinate \q;
  \q1 = ({(\px0 + \px1) / 2.0}, {\py0 + \d0 * (\px1 - \px0) / 2.0});
  \q2 = ({(\px1 + \px2) / 2.0}, {\py1 + \d1 * (\px2 - \px1) / 2.0});
  \q3 = ({(\px2 + \px3) / 2.0}, {\py2 + \d2 * (\px3 - \px2) / 2.0});
  % cubic control points, lefthand side
  coordinate \s;
  \s1 = ($2 / 3 *(\q1) + 1 / 3 *(\p0)$);
  \s2 = ($2 / 3 *(\q2) + 1 / 3 *(\p1)$);
  \s3 = ($2 / 3 *(\q3) + 1 / 3 *(\p2)$);
  % cubic control points, righthand side
  coordinate \r;
  \r1 = ($2 / 3 *(\q1) + 1 / 3 *(\p1)$);
  \r2 = ($2 / 3 *(\q2) + 1 / 3 *(\p2)$);
  \r3 = ($2 / 3 *(\q3) + 1 / 3 *(\p3)$);
}
  % https://math.stackexchange.com/q/335226
  \draw (axis cs:\p0) .. controls (axis cs:\s1) and (axis cs:\r1) .. (axis cs:\p1);
  \draw (axis cs:\p1) .. controls (axis cs:\s2) and (axis cs:\r2) .. (axis cs:\p2);
  \draw (axis cs:\p2) .. controls (axis cs:\s3) and (axis cs:\r3) .. (axis cs:\p3);
  % datapoints
  \draw (axis cs:\p0) node[circle,fill,scale=0.5,label=above:$P_{0}$] {};
  \draw (axis cs:\p1) node[circle,fill,scale=0.5,label=above:$P_{1}$] {};
  \draw (axis cs:\p2) node[circle,fill,scale=0.5,label=above:$P_{2}$] {};
  \draw (axis cs:\p3) node[circle,fill,scale=0.5,label=above:$P_{3}$] {};
\end{axis}
\end{tikzpicture}
\end{document}

Output

enter image description here

4
  • 1
    I believe the best approach would be to not use any coordinate calculation at all but only reals. Commented May 14, 2023 at 21:17
  • Your fix for the r and s variables is much appreciated. This would have taken me forever to figure out on my own. I don't think that behavior (applying only to the x variable unless parenthesized) is explicitly mentioned anywhere in the TikZ manual?
    – segfault
    Commented May 14, 2023 at 22:35
  • Also, out of curiosity, if I have the calc library loaded, shouldn't I be able to replace the $...$ with {...}?
    – segfault
    Commented May 14, 2023 at 22:46
  • 1
    @segfault \q1 is just a simple substitution (expansion) for \qx1,\qy1. If you use (1/3 * \q1 * sqrt 2) it will just be x = 1/3*\qx1 and y = \qy1 * sqrt 2. There's nothing recognizing \q1 as a coordinate, it's just two length separated by a comma. The rest is just the calc library's syntax. First a factor, then a coordinate (with * beforehand) and then possibly another coordinate calculation added (e.g. again a factor and a coordinate). Commented May 14, 2023 at 22:54

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .