5

I have macros that use anchor points in pgfplots to access certain coordinate. For instance, in a graph I can invoke a macro such as:

\newcommand*{\DoSomethingWithXAxis}{%
   \draw [ultra thick, blue] (current axis.left of origin) -- (current axis.right of origin);
}

I would like to be able to reuse such macros in a basic tikzpicture environment by manually defining the coordinates (current axis.left of origin) and (current axis.right of origin). The problem stems from the fact that those are anchor points, so was wondering what is the simplest approach to set those.

Notes:

  • I realize that \DoSomethingWithXAxis presented here is not very interesting and that there are easier ways to accomplish the same goal. But, this is just a MWE, with emphasis on the M part of the MWE.

The MWE below has \DoSomethingWithXAxis commented out in the first tikzpicture and yields the following. The desired result is for the tikzpicture axis to also be in blue via \DoSomethingWithXAxis}.

enter image description here

References:

Code:

\documentclass{article}
\usepackage{pgfplots}

\newcommand*{\DoSomethingWithXAxis}{%
    \draw [ultra thick, blue] (current axis.left of origin) -- (current axis.right of origin);
}

%% Only specifying one side to ensure that this works with both  
%% manually specified end point and an auto determined one.
\newcommand*{\XMax}{8}

\begin{document}
\begin{tikzpicture}
    \draw [-latex] (1,0) -- (\XMax,0) node [above, pos=0.5] {tikzpicture};

    %% Don't think these coordinates are being set correctly?
    \coordinate (current axis.left of origin)  at (1,0);
    \coordinate (current axis.right of origin) at (\XMax,0);
    %\DoSomethingWithXAxis;%%% <---- How do this ????
\end{tikzpicture}
\par\medskip
\begin{tikzpicture}
    \begin{axis}[axis lines=middle, samples=50, xmax=\XMax]
        \addplot [mark=none, red, thick] {x*x} node [pos=0.75, right] {pgfplots};
        \DoSomethingWithXAxis;
    \end{axis}
\end{tikzpicture}
\end{document}
  • I am not 100% sure I understand what you want to do. left of origin etc. are anchors of the shape pgfplots@low@level@shape but to set them you need to be inside an axis because otherwise the macros that set them do not have all necessary information. Do you want to create another shape that allows you to set these anchors as you want, i.e. by hand? – marmot Jul 11 '18 at 19:54
  • @marmot: I was hoping that I don't need to use pgf to create shapes. I want to be able to define the point that is meant by (current axis.right of origin) outside of an axis environment. Desire is to not need two versions of each of those macros: one that works inside an axis environment and one that works in a tikzpicture (outside of an axis environment). – Peter Grill Jul 11 '18 at 21:09
2

(Posting answer as requested.)

A small improvement of Peter's method could be to use \pgfplotsifinaxis only to define new coordinates, and do all the work with those coordinates. So one would have something like

\newcommand*{\DoSomethingWithXAxis}{%
    \pgfplotsifinaxis{% https://tex.stackexchange.com/a/17436/4301
        \coordinate (current axis left of origin) at (current axis.left of origin);
        \coordinate (current axis right of origin) at (current axis.right of origin);
    }{}%
    \draw [ultra thick, blue] (current axis left of origin) -- (current axis right of origin);
}

The benefit of this is that you don't have to duplicate all the code in \DoSomethingWithXAxis.

3

One way to address this problem is to use \pgfplotsifinaxis and have a different code when outside of the axis environment:

\newcommand*{\DoSomethingWithXAxis}{%
    \pgfplotsifinaxis{% https://tex.stackexchange.com/a/17436/4301
        \draw [ultra thick, blue] (current axis.left of origin) -- (current axis.right of origin);
    }{%
        \draw [ultra thick, blue] (current axis left of origin) -- (current axis right of origin);
    }%
}

where I define a current axis left of origin (note the missing .) when I am not in an axis environment.

enter image description here

Notes:

  • I really dislike this solution as it requires two mode of each macro that uses the coordinates of the ends of the axis.

References:

Code:

\documentclass{article}
\usepackage{pgfplots}

\newcommand*{\DoSomethingWithXAxis}{%
    \pgfplotsifinaxis{% https://tex.stackexchange.com/a/17436/4301
        \draw [ultra thick, blue] (current axis.left of origin) -- (current axis.right of origin);
    }{%
        \draw [ultra thick, blue] (current axis left of origin) -- (current axis right of origin);
    }%
}

%% Only specifying one side to ensure that this works with both  
%% manually specified end point and an auto determined one.
\newcommand*{\XMax}{8}

\begin{document}
\begin{tikzpicture}
    \draw [-latex] (1,0) -- (\XMax,0) node [above, pos=0.5] {tikzpicture};

    \coordinate (current axis left of origin)  at (1,0);
    \coordinate (current axis right of origin) at (\XMax,0);
    \DoSomethingWithXAxis;%%% <---- Works! BUT I needed to define different coordinate above
\end{tikzpicture}
\par\medskip
\begin{tikzpicture}
    \begin{axis}[axis lines=middle, samples=50, xmax=\XMax]
        \addplot [mark=none, red, thick] {x*x} node [pos=0.75, right] {pgfplots};
        \DoSomethingWithXAxis;
    \end{axis}
\end{tikzpicture}
\end{document}
  • I really would prefer to not have to define two different versions of \DoSomethingWithXAxis as this answer does. – Peter Grill Jul 11 '18 at 21:23
  • 2
    What about having \pgfplotsifinaxis{\coordinate (current axis left of origin) at (current axis.left of origin);}{} and doing everything with current axis left of origin? – Torbjørn T. Jul 11 '18 at 21:33
  • @TorbjørnT.: Yes that is a slight improvement, but would require me to insert the code in all the existing macros that look at current axis.left of origin. – Peter Grill Jul 12 '18 at 8:56
  • Yes, but that is no different from your answer. By inserting a snippet like that at the start of \DoSomethingWithXAxis the main part of the macro can be the same for both cases, so you don't need to do what you said you didn't want to do. – Torbjørn T. Jul 12 '18 at 9:24
  • @TorbjørnT.: Like I said, that is an improvement over this hack answer that I posted. And you comment makes perfect sense assuming that there exists only a few cases where there is functionality such as \DoSomethingWithXAxis. And if I was doing this for the first time I would certainly do it that way. But I have already used current axis.left of origin. If a better solution does not appear, then I will modify things as you suggested. – Peter Grill Jul 12 '18 at 18:12
1

Here is a simple shape and a command to do what you want. \dualcoordinate is limited, it just looks like TikZ code and the node is always named current axis. Also the center anchor is not in the center.

\documentclass{article}
\usepackage{pgfplots}

\newcommand*{\DoSomethingWithXAxis}{%
    \draw [ultra thick, blue] (current axis.left of origin) -- (current axis.right of origin);
}

\makeatletter
% options for the new shape
\pgfset{
  second point x/.initial=0,
  second point y/.initial=0,
  second point/.style 2 args={/pgf/second point x=#1,/pgf/second point y=#2},
}

% to store the origin of the node
\newdimen\pgf@base@x
\newdimen\pgf@base@y

% new shape
\pgfdeclareshape{dual coordinate}
{
  \savedanchor\firstpoint{%
    % save the origin of the node, needed for \secondpoint
    % otherwise, it would be relative to the first
    \global\pgf@base@x=\pgf@x
    \global\pgf@base@y=\pgf@y
    % copied from \pgfdeclareshape{coordinate}
    % x
    \pgf@x=.5\wd\pgfnodeparttextbox%
    % y
    \pgf@y=.5\ht\pgfnodeparttextbox%
    \advance\pgf@y by -.5\dp\pgfnodeparttextbox%
  }
  \savedanchor\secondpoint{%
    \pgfpointdiff{\pgfpoint{\pgf@base@x}{\pgf@base@y}}%
        {\pgfpointxy{\pgfkeysvalueof{/pgf/second point x}}{\pgfkeysvalueof{/pgf/second point y}}}%
  }

  \anchor{left of origin}{\secondpoint}
  \anchor{right of origin}{\firstpoint}
  \anchor{center}{\firstpoint}% necessary to prevent odd errors
  \anchorborder{\firstpoint}

  \nodeparts{}% no text
}

% split to allow space between first and second coordinate
\def\dualcoordinate(#1,#2){\dual@coordinate{#1}{#2}}
\def\dual@coordinate#1#2(#3,#4){%
    \node[dual coordinate, second point={#3}{#4}] (current axis)  at (#1,#2) {}%
    % no semicolon here, so it's necessary in the tikz picture
}
\makeatother

%% Only specifying one side to ensure that this works with both  
%% manually specified end point and an auto determined one.
\newcommand*{\XMax}{8}

\begin{document}
\begin{tikzpicture}
    \draw [-latex] (1,0) -- (\XMax,0) node [above, pos=0.5] {tikzpicture};

    \dualcoordinate (1,0) (\XMax,0);
    \DoSomethingWithXAxis;
\end{tikzpicture}
\par\medskip
\begin{tikzpicture}
    \begin{axis}[axis lines=middle, samples=50, xmax=\XMax]
        \addplot [mark=none, red, thick] {x*x} node [pos=0.75, right] {pgfplots};
        \DoSomethingWithXAxis;
    \end{axis}
\end{tikzpicture}
\end{document}
  • Seems to do the job. – Peter Grill Jul 15 '18 at 9:06

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.