7

I'm trying to do some annotation with TikZ in a PGFplots axis environment by means of nodes. However, the placement of the nodes is going wrong all the time, see the minimum working example below. How can I fix this? How do I calculate the coordinates for the TikZ annotation properly?

MWE:

\documentclass[margin=1cm]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=newest}
\usetikzlibrary{calc}
\begin{document}
    \begin{tikzpicture}
        \begin{axis}
        [
            xtick={-0.1,0,1,1.1},xmin=-0.1,xmax=1.1,xlabel=$x$,
            ytick={-0.2,0,2,2.2},ymin=-0.2,ymax=2.2,ylabel style={rotate=-90},ylabel=$y$,
            unit vector ratio=2 1 1,
        ]
            \addplot[blue,domain=0:1] {x};
            \addplot[red,domain=0:1] {2*x};

            % Annotation.
            \coordinate (SW) at (axis cs:-0.1,-0.2); % (S)outh (w)est.
            \coordinate (SE) at (axis cs:1.1,-0.2); % (S)outh (e)ast.
            \coordinate (NE) at (axis cs:1.1,2.2); % (N)orth (e)ast.
            \coordinate (NW) at (axis cs:-0.1,2.2); % (N)orth (w)est.

            \coordinate (A) at (axis cs:1,0);
            \fill[black] (A) circle (1pt) node[anchor=south]{A};

             % ??? WHY IS THIS NOT WORKING. SHOULD BE THE SAME AS NODE A. ???
            \coordinate (B) at ($(SE)+(axis cs:-0.1,0.2)$); % ??? WHY IS THIS NOT WORKING. SHOULD BE THE SAME AS NODE A. ???
            \fill[black] (B) circle (1pt) node[anchor=south east]{B}; % ??? WHY IS THIS NOT WORKING. SHOULD BE THE SAME AS NODE A. ???
             % ??? WHY IS THIS NOT WORKING. SHOULD BE THE SAME AS NODE A. ???

        \end{axis}
    \end{tikzpicture}
\end{document}

7
  • Why don't you keep using axis cs coordinate system for nodes?
    – Ignasi
    May 12, 2015 at 9:57
  • 1
    calc is a tikz library and doesn't know anything about axis coordinate systems of pgfplots. Play around with xmin and ymin values (with possibly clip=false added) and you'll see that B would be dancing around.
    – percusse
    May 12, 2015 at 9:59
  • You don't need the $$ in ($(1,0)$), just write (1,0).
    – Alenanno
    May 12, 2015 at 10:03
  • @Ignasi. I believe it doesn't matter, since axis cs is the default within the axis environment, according to the PGFplots manual. See 4.17 Custom annotations, PGFplots manual Revision 1.12 (2015/01/31). Nonetheless, it is indeed more consistent to use axis cs everywhere, so I edited the code ;). Thanks for your suggestion.
    – Adriaan
    May 12, 2015 at 11:17
  • 1
    I think you should rephrase the question. Your problem is how to calculate coordinates within pgfplots and not only positioning nodes.
    – Ignasi
    May 12, 2015 at 12:28

2 Answers 2

10

The origin of the canvas area is different from the origin of the plot area. A plot coordinate pair (-0.1, 0.2) inside the calc expression ($(SE) + (-0.1, 0.2)$) is transformed to canvas coordinates and added to the canvas coordinates of SE. But since the origins do not match, the result is moved by the displacement of the plot origin to the canvas origin. Actually you want to add "relative" coordinates:

($(SE) + (-0.1, 0.2) - (0, 0)$)

The following example tries to illustrate this:

\documentclass[margin=1cm]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=newest}
\usetikzlibrary{arrows.meta}
\usetikzlibrary{calc}
\begin{document}
    \begin{tikzpicture}
        \begin{axis}
        [
            xtick={-0.1,0,1,1.1},xmin=-0.1,xmax=1.1,xlabel=$x$,
            ytick={-0.2,0,.5,.7},
            ymin=-0.2,ymax=.7,
            ylabel style={rotate=-90},
            ylabel=$y$,
            unit vector ratio=2 1 1,
        ]
            % \addplot[blue,domain=0:1] {x};
            % \addplot[red,domain=0:1] {2*x};

            % Annotation.
            \coordinate (SW) at (axis cs:-0.1,-0.2); % (S)outh (w)est.
            \coordinate (SE) at (axis cs:1.1,-0.2); % (S)outh (e)ast.
            \coordinate (NE) at (axis cs:1.1,2.2); % (N)orth (e)ast.
            \coordinate (NW) at (axis cs:-0.1,2.2); % (N)orth (w)est.

            \coordinate (A) at ($(1,0)$);
            \fill[black] (A) circle (1pt) node[anchor=south]{A};

            \coordinate (CO) at (0pt, 0pt);% canvas origin
            \coordinate (PO) at (0, 0);% plot origin
            \coordinate (D) at (-0.1, 0.2);% displacement as plot point

            \begin{scope}[
              -{Triangle[]},
              node font=\footnotesize,
              inner sep=.15em,
            ]
              % Show canvas origin
              \draw
               (CO) ++(1em, .4em) node[above right] (tmp) {Canvas origin (CO)}
               (tmp.west) -- (CO);

              % Show plot origin
              \draw
                (PO) ++(1em, .4em) node[above right] (tmp) {Plot origin (PO)}
                (tmp.west) -- (PO);

              % Show displacement as absolute plot point
              \draw
                (D) ++(1em, .4em) node[above right] (tmp) {D}
                (tmp.west) -- (D);

              % Show SE
              \draw
                (SE) ++(-1.5em, .4em) node[above left] (tmp) {SE}
                (tmp.east) -- (SE);

               % Show SE + D
               \draw
                 ($(SE) + (D)$) coordinate (SE_D)
                 ++(-1em, .4em) node[above left] (tmp) {SE + D}
                 (tmp.east) -- (SE_D);

               % Show SE + D - plot origin
               \draw
                 ($(SE) + (D) - (PO)$) coordinate (SE_D_PO)
                 ++(-1em, 0em) node[left] (tmp) {SE + D - PO}
                 (tmp.east) -- (SE_D_PO);

               \draw[red, very thick, <->, >={latex[]}]
                 (CO) -- (D);
               \draw[red, very thick, <->, >={latex[]}]
                 (SE) -- (SE_D);

               \draw[blue, thick, <->, >={latex[]}]
                 (PO) -- (D);
               \draw[blue, thick, <->, >={latex[]}]
                 (SE) -- (SE_D_PO);
            \end{scope}
        \end{axis}
    \end{tikzpicture}
\end{document}

Result

A more clear notation is using the coordinate system cs axis direction as shown in the answer of esdd.

5
  • 1
    From the options xmin=-0.1, and ymin=-0.2, specified in the axis environment, I think the lower left corner of the TikZ display is the point (-0.1, 0.2). From your command \coordinate (CO) at (0pt, 0pt); and the display rendered that shows the point CO at the lower left corner, it is apparent that the canvas coordinates of a point are different than its axis coordinates. I guess pt can be replaced with mm or cm. You also label the lower left corner SW in the command \coordinate (SW) at (axis cs:-0.1,-0.2);. I think that you do this for calculations.
    – Adelyn
    May 25, 2015 at 21:18
  • 1
    From the option xmax=1.1 and the command \coordinate (SE) at (axis cs:1.1,-0.2);, I think that you are labeling the point in the lower right corner of the TikZ display SE. With the command \coordinate (D) at (-0.1, 0.2);, you are labeling a point D along the left edge of the TikZ display - 0.2cm above the x-axis. Why don't you have to have \coordinate (D) at (axis cs:-0.1,0.2);?
    – Adelyn
    May 25, 2015 at 21:39
  • To put the label SE + D - PO to the left of the point (1,0) in the axis coordinate system using the calc package, you issue the command \draw ($(SE) + (D) - (PO)$) ++(-1em, 0em) node[left] {SE + D - PO} -- ($(SE) + (D) - (PO)$). (By the way, you don't need to have (tmp) and (tmp.east).) Why do you have add (D)? Would you get the same display with \draw (axis cs:1,0) ++(-1em, 0em) node[left] {SE + D - PO} -- (axis cs:1,0)?
    – Adelyn
    May 25, 2015 at 21:45
  • @Adelyn In the axis environment the axis coordinate system is usually the default, therefore I can drop the explicit specifier axis cs: at many places there. May 26, 2015 at 4:45
  • @Adelyn I need (tmp) because I want to start the arrows at (tmp.east) or (tmp.west) explicitly. The additions with D are the point of the illustration. May 26, 2015 at 4:50
4

You have to use the axis direction cs:

\coordinate (B) at ($(SE)+(axis direction cs:-0.1,0.2)$);

enter image description here

Code:

\documentclass[margin=1cm]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.12}
\usetikzlibrary{calc}
\begin{document}
    \begin{tikzpicture}
        \begin{axis}
        [
            xtick={-0.1,0,1,1.1},xmin=-0.1,xmax=1.1,xlabel=$x$,
            ytick={-0.2,0,2,2.2},ymin=-0.2,ymax=2.2,ylabel style={rotate=-90},ylabel=$y$,
            unit vector ratio=2 1 1,
        ]
            \addplot[blue,domain=0:1] {x};
            \addplot[red,domain=0:1] {2*x};

            % Annotation.
            \coordinate (SW) at (-0.1,-0.2); % (S)outh (w)est.
            \coordinate (SE) at (1.1,-0.2); % (S)outh (e)ast.
            \coordinate (NE) at (1.1,2.2); % (N)orth (e)ast.
            \coordinate (NW) at (-0.1,2.2); % (N)orth (w)est.

            \coordinate (A) at (1,0);
            \fill[black] (A) circle (1pt) node[anchor=south]{A};

             % ??? WHY IS THIS NOT WORKING. SHOULD BE THE SAME AS NODE A. ???
            \coordinate (B) at ($(SE)+(axis direction cs:-0.1,0.2)$);??? WHY IS THIS NOT WORKING. SHOULD BE THE SAME AS NODE A. ???
            \fill[red,fill opacity=.5] (B) circle (2pt) node[anchor=south east]{B}; % ??? WHY IS THIS NOT WORKING. SHOULD BE THE SAME AS NODE A. ???
             % ??? WHY IS THIS NOT WORKING. SHOULD BE THE SAME AS NODE A. ???

        \end{axis}
    \end{tikzpicture}
\end{document}
2
  • In the PGFplots manual Revision 1.12 (2015/01/31), it says 'While axis cs allows to supply absolute positions, axis direction cs supplies directions. It allows to express relative positions, includings lengths and dimensions, by means of axis coordinates.' I really have no idea what this means, but your solution seems to work :S. Do you understand what the difference between axis cs and axis direction cs is?
    – Adriaan
    May 12, 2015 at 11:30
  • @Heiko Oberdiek explains this in his answer.
    – esdd
    May 12, 2015 at 12:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.