在 pgfplots 图中,使用宏作为坐标

在 pgfplots 图中,使用宏作为坐标

我正在尝试解决这个问题如何与 TikZ 和 Pgfplots 保持一致性?本质上,需要一种将坐标保存为宏(或者可能是全局键?)的方法,然后可以<x>,<y>在正常节点/路径和 pgfplots 图中使用它来代替通常的对。

澄清一下:我希望能够定义一个宏\PointA,每当需要语法时都可以调用它(<x>,<y>)。这可能是在节点定义中使用\node at (<x>,<y>) {};,或者在 pgfplots 图中使用\addplot coordinates { (0,0) (<x>,<y>) (1,1) };

对于普通节点和路径,仅使用就\def\<name>{<x>,<y>}可以正常工作,但是当我尝试将其用作 pgfplots 图中的坐标时,它会失败并显示错误消息:

File ended while scanning use of \pgfplots@foreach@plot@coord@NEXT.

又是扩展问题?还是我应该采用完全不同的方法?

\documentclass{article}
\usepackage{pgfplots}

\def\PointA{1,2}

\begin{document}
\begin{tikzpicture}

  \draw [gray] (0,0) grid (3,3);
  \fill (\PointA) circle (2pt); % Works

  \begin{axis}[xshift=3.5cm,width=6cm,xmin=0,xmax=3,ymin=0,ymax=3,grid=both]

    \fill [orange] (axis cs:\PointA) circle (4pt); % Works
    \addplot coordinates { (0,0) (1,2) (2,2) }; % Works
%    \addplot coordinates { (0,0) (\PointA) (2,2) }; % Fails

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

答案1

实现此目的的一种方法是修补负责读取坐标的内部宏。检测到开口后将调用\pgfplots@foreach@plot@coord@NEXTin并从输入流中读取。在您的示例中,您有,因此被视为 X 和Y 部分。想法是修补此宏以展开下一个标记以显示其中的。这可以使用以下代码完成:pgfplotscoordprocessing.code.tex((#1,#2)(\PointA) (2,2)\PointA) (22(,

\documentclass{article}
\usepackage{pgfplots}

\def\PointA{1,2}

\makeatletter
\let\orig@pgfplots@foreach@plot@coord@NEXT\pgfplots@foreach@plot@coord@NEXT
\def\pgfplots@foreach@plot@coord@NEXT{%
    \expandafter\orig@pgfplots@foreach@plot@coord@NEXT\expandafter
}
\makeatother

\begin{document}
\begin{tikzpicture}

  \draw [gray] (0,0) grid (3,3);
  \fill (\PointA) circle (2pt); % Works

  \begin{axis}[xshift=3.5cm,width=6cm,xmin=0,xmax=3,ymin=0,ymax=3,grid=both]

    \fill [orange] (axis cs:\PointA) circle (4pt); % Works
%    \addplot coordinates { (0,0) (1,2) (2,2) }; % Works
    \addplot coordinates { (0,0) (\PointA) (2,2) }; % Works now!!

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

另一种方法是修补负责读取{ }之后的宏coordinate,以便在进一步处理该参数之前完全扩展该参数。这样做的好处是,您可以包含保存多个坐标的宏或其他无法使用上述代码扩展的宏。调用有问题的宏\pgfplots@addplotimpl@coordinates@并将坐标读取为#3。以下代码使用扩展该参数\edef

\documentclass{article}
\usepackage{pgfplots}

\def\PointA{1,2}

\def\mycoordinates{ (1,0) (2,1) (3,0) }

\makeatletter
\long\def\pgfplots@addplotimpl@coordinates@#1#2#3#4{%
    \pgfplots@start@plot@with@behavioroptions{#1,/pgfplots/.cd,#2}%
    \pgfplots@PREPARE@COORD@STREAM{#4}%
    \begingroup
    \edef\@tempa{{#3}}%
    \ifpgfplots@curplot@threedim
        \expandafter\endgroup\expandafter
        \pgfplots@coord@stream@foreach@threedim\@tempa
    \else
        \expandafter\endgroup\expandafter
        \pgfplots@coord@stream@foreach\@tempa
    \fi
}%
\makeatother

\begin{document}
\begin{tikzpicture}

  \draw [gray] (0,0) grid (3,3);
  \fill (\PointA) circle (2pt); % Works

  \begin{axis}[xshift=3.5cm,width=6cm,xmin=0,xmax=3,ymin=0,ymax=3,grid=both]

    \fill [orange] (axis cs:\PointA) circle (4pt); % Works
%    \addplot coordinates { (0,0) (1,2) (2,2) }; % Works
    \addplot coordinates { (0,0) (\PointA) (2,2) }; % Works now!!
    \addplot coordinates \mycoordinates; % Works as well!!
    \addplot coordinates { (0,1) \mycoordinates (6,7) }; % Works as well!!

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

或者,您可以定义\PointAX然后\PointAY写入(\PointAX,\PointAY)哪些也应该可以在没有任何补丁的情况下工作。

答案2

您可以单独存储每个坐标或定义一个表:

\documentclass{article}
\usepackage{pgfplots}


\def\PointAx{1}
\def\PointAy{2}
\def\PointA{\PointAx,\PointAy}
\pgfplotstableread{%
  2 2
}{\PointB}

\begin{document}
\begin{tikzpicture}

  \draw [gray] (0,0) grid (3,3);
  \fill (\PointA) circle (2pt); % Works

  \begin{axis}[xshift=3.5cm,width=6cm,xmin=0,xmax=3,ymin=0,ymax=3,grid=both]

    \fill [orange] (axis cs:\PointA) circle (4pt); % Works
    \addplot coordinates { (1,2) }; % Works
    \addplot coordinates { (\PointAx,\PointAy) }; % Works
    \addplot table {\PointB}; % Works

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

答案3

换个角度来看这个问题:

\documentclass{article}
\usepackage{tikz}
\usepackage{pgfplots}

\def\PointA{1,2}
\def\PointB{coordinates {(3,3)}}
\begin{document}


\begin{tikzpicture}
  \draw [gray] (0,0) grid (3,3);
  \fill (\PointA) circle (2pt); % Works

  \begin{axis}[xshift=3.5cm,width=6cm,xmin=0,xmax=3,ymin=0,ymax=3,grid=both]
    \fill [orange] (axis cs:\PointA) circle (4pt); % Works
    \expandafter\addplot\PointB; % Works
  \end{axis}
\end{tikzpicture}
\end{document}

这是一个简单干净的解决方案。可以对其进行修改。例如,您可以定义一个宏:

\def\Coordinates#1#2{%
  \def\A{#1}
  \def\B{#2}
  \def\PointB{coordinates {(\A,\B)}}
  \expandafter\addplot\PointB;
}

这也可以起作用,只需从内部调用它\begin{axis}...。\end{axis}

相关内容