1

[REVISED VERSION aimed at making the MWE more realistic]

I have two related figures of different width that are drawn in the tikzpicture environment using pgfplots and the related axis environment. The pictures are currently drawn for a beamer document class, thus being able to exploit the \only command to establish an order for the various operations. In particular, such order is needed because each of the picture makes use of some information which is extracted from the other picture at the previous frame: this is what establishes a link between the pictures. In particular, each picture makes use of some coordinate component extracted from the previous picture, and at least some of such coordinates are determined via the intersections library.

All this works perfectly fine in beamer, thanks to the \only command.

Is there a relatively easy way to reproduce the same mechanism in a non-beamer document class such as article?

I have already consulted a number of related Q&A (such as this and of course this), but I cannot arrive to any solution starting from there. I think my coding skills are just insufficient to make it on my own. Additionally, I have consulted the animate package documentation, but its possible solutions (if any) to the present problem appear to be very convoluted. Finally, I have considered externalizing and exporting to pdf each picture to then include their final frame where needed. Unfortunately, the heterogenous widths of pictures make this solution scarcely viable when one has to produce and include many pictures.

I hereby provide a revised MWE and the last frame of the resulting output. MWE

\documentclass{beamer}
\usepackage[mode=buildnew]{standalone}
\usepackage{tikz,pgfplots}
\usetikzlibrary{intersections}

% Coordinate extraction
% from: https://tex.stackexchange.com/questions/420498/extract-convert-store-and-reuse-x-y-coordinate-components
\newlength{\lenx}
\newlength{\plotwidth}
\newlength{\leny}
\newlength{\plotheight}
\newcommand{\getvalue}[1]{\pgfkeysvalueof{/pgfplots/#1}}
\newcommand{\Getxycoords}[3]% #1 = node name, #2 x coordinate, #2 y coordinate
{\pgfplotsextra{%
    \pgfextractx{\lenx}{\pgfpointdiff{\pgfplotspointaxisxy{0}{0}}{\pgfpointanchor{#1}{center}}}%
    \pgfextractx{\plotwidth}{\pgfpointdiff{\pgfplotspointaxisxy{\getvalue{xmin}}{0}}%
        {\pgfplotspointaxisxy{\getvalue{xmax}}{0}}}%
    \pgfextracty{\leny}{\pgfpointdiff{\pgfplotspointaxisxy{0}{0}}{\pgfpointanchor{#1}{center}}}%
    \pgfextracty{\plotheight}{\pgfpointdiff{\pgfplotspointaxisxy{0}{\getvalue{ymin}}}%
        {\pgfplotspointaxisxy{0}{\getvalue{ymax}}}}%
    \pgfmathsetmacro{\myx}{\lenx*(\getvalue{xmax}-\getvalue{xmin})/\plotwidth}%
    \pgfmathsetmacro{\myy}{\leny*(\getvalue{ymax}-\getvalue{ymin})/\plotheight}%
    \xdef#2{\myx}%
    \xdef#3{\myy}%
    %       \typeout{\myx,\myy} <- for debugging
}%
}


\begin{document}

    \begin{frame}
    \centering
    \begin{tikzpicture}[baseline=(current bounding box.north),trim axis left,trim axis right]
    \begin{axis}[scale=0.6,clip=false,ytick={0}]
        \addplot [name path=f,smooth,domain=-20:20] {1+0.5*x} node [anchor=north,yshift=-2mm] {$f(x)$};
        \addplot [name path=h,smooth,domain=-20:20] {8+1*x} node [anchor=south,yshift=-2mm] {$h(x)$};
    \only<2->{
        \path [name intersections={of=f and h,by={A}}] node [anchor=south] at (A) {$A$}; %Assign point A
        \Getxycoords{A}{\Ax}{\Ay};
        \draw [fill=red] (A) circle (2pt);
    }
    \only<4->{
        \node (C) at (axis cs:{(\By-1)/0.5},\By) {}; %Get point C given point B
        \Getxycoords{C}{\Cx}{\Cy};
        \draw [fill=red] (C) circle (2pt) node [anchor=south] {C};
        \draw [dashed] (axis cs:\Cx,\pgfkeysvalueof{/pgfplots/ymin}) -- (C) -- (axis cs:\pgfkeysvalueof{/pgfplots/xmin},\Cy) node [anchor=east] {$y$-component of $C$};
    }
    \end{axis}
    \end{tikzpicture}

    \begin{tikzpicture}[baseline=(current bounding box.north),trim axis left,trim axis right]
    \begin{axis}[scale=0.6,clip=true,ytick={0}]
        \addplot [name path=g,smooth,domain=-20:20] {1+0.6*x} node [anchor=north,yshift=-2mm] {$g(x)$};
    \only<3->{
        \node (B) at (axis cs:\Ax,{1+0.6*\Ax}) {}; %Get point B given point A
        \Getxycoords{B}{\Bx}{\By};
        \draw [fill=red] (B) circle (2pt) node [anchor=south] {B};
    }
    \end{axis}
    \end{tikzpicture}

\end{frame}


\end{document}
  • Have a look at the animate package – samcarter_is_at_topanswers.xyz Mar 21 '18 at 10:02
  • @samcarter That is the first option I have considered. But it seems very convoluted to apply in a specific case like the one I have presented. That is precisely why I decided to come up with a specific MWE, although it probably wasn't specific enough, as it turns out from the discussion hereby. – Brocardo Reis Mar 23 '18 at 13:37
  • Maybe stupid question, why can't you just use the font of your article in the standalone example and include the resulting pdf in your article? – samcarter_is_at_topanswers.xyz Mar 23 '18 at 13:58
  • @samcarter When producing graphs in tikzpicture, it is straightforward to align them horizontally (as strictly needed) via the trim axis command. Instead, horizontal alignment has to be done manually once you include the pictures, due to the fact that the pictures have different width. Since I have many pictures, I cannot take this road. Also, I am having troubles changing the beamer font in tikzpictureto the same serif font used in article. – Brocardo Reis Mar 23 '18 at 14:21
  • To change the font just do \usefonttheme{serif} (and depending an which document class you use for your article, change the size). Both plots you showed us, have the same width. – samcarter_is_at_topanswers.xyz Mar 23 '18 at 14:28
  • @samcarter Again, the MWE is too minimal, because the actual pictures have different width. As for \usefonttheme{serif}, that is what I have used. Such command works smoothly when the pictures at stake are not externalized via the external library, which is instead what I have actually used so far. – Brocardo Reis Mar 23 '18 at 14:35
  • What's your desired output? Something that looks like the last frame? Or something that looks like all three frames sequentially? – Teepeemm Mar 23 '18 at 16:14
  • @Teepeemm My desired output is to obtain just the figures shown in the last frame (not the frame its self). If you are thinking about including the figures produced in standalone, this means that the two graphs would have to be printed in a single file, so that its inclusion won't cause problems with horizontal alignment. – Brocardo Reis Mar 23 '18 at 17:12

2 Answers2

1

New answer (to revised question)

So when the main problem is to align the different plots because of different bounding box sizes, one solution is to put all the axis environments into one tikzpicture environment and align the axis environments accordingly. I demonstrate this here for two axis environments only, but I think with this having this as a starting point you can create the other axis environments on your own.

For details please have a look at the comments in the code

% used PGFPlots v1.16
\documentclass[border=5pt]{standalone}
\usepackage{pgfplots}
    \usetikzlibrary{intersections}
    % Coordinate extraction from
    % <https://tex.stackexchange.com/a/426245/95441>
    % #1: node name
    % #2: output macro name: x coordinate
    % #3: output macro name: y coordinate
    \newcommand{\Getxycoords}[3]{%
         \pgfplotsextra{%
             \pgfplotspointgetcoordinates{(#1)}%
             \global\pgfkeysgetvalue{/data point/x}{#2}%
             \global\pgfkeysgetvalue{/data point/y}{#3}%
         }%
    }
\begin{document}
\begin{tikzpicture}
    \begin{axis}[
        % name the plot, so we later can align the second `axis' environment
        % relative to this one
        name=top plot,
        %
        clip mode=individual,       % <-- changed from `clip=false'
        ytick={0},
        domain=-20:20,
    ]
        \addplot [name path=f] {1+0.5*x}    node [below=2mm] {$f(x)$};
        \addplot [name path=h] {8+1*x}      node [above] {$h(x)$};

% \only<2->{ \path [ name intersections={ of=f and h, by={A}, }, ] node [anchor=south] at (A) {$A$}; \Getxycoords{A}{\Ax}{\Ay}; \draw [fill=red] (A) circle (2pt); % }

    % add node (B) to this plot, too
    \node (B) at (axis cs:\Ax,{1+0.6*\Ax}) {};
        \Getxycoords{B}{\Bx}{\By};

% \only<4->{ \node (C) at (axis cs:{(\By-1)/0.5},\By) {}; \Getxycoords{C}{\Cx}{\Cy}; \draw [fill=red] (C) circle (2pt) node [above] {C}; \draw [dashed] (axis cs:\Cx,\pgfkeysvalueof{/pgfplots/ymin}) -- (C) -- (axis cs:\pgfkeysvalueof{/pgfplots/xmin},\Cy) node [left] {$y$-component of $C$}; % } \end{axis} % don't end the tikzpicture' environment here, but add the other plots % as well \begin{axis}[ % align thisaxis' environment relative to the top one at={(top plot.below south west)}, anchor=above north west, yshift=-2ex, % ytick={0}, domain=-20:20, ] \addplot [name path=g] {1+0.6*x} node [below=2mm] {$g(x)$};

% \only<3->{ \node (B) at (axis cs:\Ax,{1+0.6*\Ax}) {}; % \Getxycoords{B}{\Bx}{\By}; \draw [fill=red] (B) circle (2pt) node [above] {B}; % } \end{axis} \end{tikzpicture} \end{document}

image showing the result of above code

Old answer (to question of revision 2)

If you just need to create the single plots there is a much simpler way to determine/set the point coordinates in your given example, because all coordinates can be calculated directly knowing coordinate (A).

% used PGFPlots v1.15
\documentclass[border=5pt]{standalone}
\usepackage{pgfplots}
    \pgfmathsetmacro{\Ax}{2}
    \pgfmathsetmacro{\Ay}{1+0.5*2}
    \pgfmathsetmacro{\Bx}{\Ax}
    \pgfmathsetmacro{\By}{2+2*\Ax}
    \pgfmathsetmacro{\Cx}{(\By-1)/0.5}
    \pgfmathsetmacro{\Cy}{\By}
\begin{document}
\begin{tikzpicture}
    \begin{axis}
        \addplot [smooth,domain=-20:20] {1+0.5*x} node [below=2mm] {$f(x)$};
        \node (A) at (axis cs:\Ax,\Ay) {};
        \draw [fill=red] (A) circle (2pt) node [above] {A};
    \end{axis}
\end{tikzpicture}

\begin{tikzpicture} \begin{axis} \addplot [smooth,domain=-5:5] {2+2*x} node [below=2mm] {$g(x)$}; \node (B) at (axis cs:\Bx,\By) {}; \draw [fill=red] (B) circle (2pt) node [above] {B}; \end{axis} \end{tikzpicture}

\begin{tikzpicture} \begin{axis} \addplot [smooth,domain=-20:20] {1+0.5*x} node [below=2mm] {$f(x)$}; \node (A) at (axis cs:\Ax,\Ay) {}; \draw [fill=red] (A) circle (2pt) node [above] {A};

    \node (C) at (axis cs:\Cx,\Cy) {};
    \draw [fill=red] (C) circle (2pt) node [above] {C};
\end{axis}

\end{tikzpicture} \end{document}

image showing the result of above code

Stefan Pinnow
  • 29,535
  • I know that I can compute all the relevant points starting from \Ax. But this is not the type of solution that solves my problem: I need a way to easily substitute the \onlycommand, since the figures need first to be built in beamer and then to be built again in an article document class. And I cannot use the last frame from the beamer handout and include it elsewhere as an image. I need to directly build the figure in the article document class. Thanks anyway for your attempt. – Brocardo Reis Mar 22 '18 at 21:43
  • Sorry, but I don't know why you shouldn't be able to use my solution if this is your real case example. Anyway, maybe someone else comes up with another answer which then hopefully helps you. – Stefan Pinnow Mar 23 '18 at 05:29
  • I have produced an excessively minimal MWE, which does not fully represent the real code. I am sorry. The basic issue is that, in the real code, some of the points are found via the intersections package. That means that I actually have to strike paths with addplot, find their intersections, and then use the resulting points sequentially like in the MWE I have provided. I sincerely apologize for wasting your time. – Brocardo Reis Mar 23 '18 at 13:30
  • Ok, then maybe you should change your MWE so something that is equals a bit more your real case. Perhaps than I have another idea ... – Stefan Pinnow Mar 23 '18 at 15:58
  • I have uploaded a revised version of the MWE that accounts for all the further details that have so far emerged in the Q&A. I hope it is clearer now. – Brocardo Reis Mar 23 '18 at 20:14
  • @BrocardoReis, does my revised answer answer your question? If yes, please consider upvoting (by clicking on the arrows next to the score) and/or marking it as the accepted answer (by clicking on the checkmark ✓) and if not, please edit the question again. – Stefan Pinnow Apr 15 '18 at 13:02
1

Beamer overlays can be approximated using PDF Layers (OCGs). Replace only{<...>}{} with nested TikZ scopes that are associated with OCGs.

Based on S. Pinnows code version.

enter image description here

% used PGFPlots v1.15
\documentclass[border=5pt]{standalone}
%\documentclass[border=5pt]{article}
\usepackage{pgfplots}
\usepackage[tikz]{ocgx2}
\pgfplotsset{compat=1.15}

\usetikzlibrary{intersections}
% Coordinate extraction
% from: https://tex.stackexchange.com/questions/420498/extract-convert-store-and-reuse-x-y-coordinate-components
\newlength{\lenx}
\newlength{\plotwidth}
\newlength{\leny}
\newlength{\plotheight}
\newcommand{\getvalue}[1]{\pgfkeysvalueof{/pgfplots/#1}}
\newcommand{\Getxycoords}[3]% #1 = node name, #2 x coordinate, #2 y coordinate
{\pgfplotsextra{%
    \pgfextractx{\lenx}{\pgfpointdiff{\pgfplotspointaxisxy{0}{0}}{\pgfpointanchor{#1}{center}}}%
    \pgfextractx{\plotwidth}{\pgfpointdiff{\pgfplotspointaxisxy{\getvalue{xmin}}{0}}%
        {\pgfplotspointaxisxy{\getvalue{xmax}}{0}}}%
    \pgfextracty{\leny}{\pgfpointdiff{\pgfplotspointaxisxy{0}{0}}{\pgfpointanchor{#1}{center}}}%
    \pgfextracty{\plotheight}{\pgfpointdiff{\pgfplotspointaxisxy{0}{\getvalue{ymin}}}%
        {\pgfplotspointaxisxy{0}{\getvalue{ymax}}}}%
    \pgfmathsetmacro{\myx}{\lenx*(\getvalue{xmax}-\getvalue{xmin})/\plotwidth}%
    \pgfmathsetmacro{\myy}{\leny*(\getvalue{ymax}-\getvalue{ymin})/\plotheight}%
    \xdef#2{\myx}%
    \xdef#3{\myy}%
    %       \typeout{\myx,\myy} <- for debugging
}}%

\begin{document}
\begin{tikzpicture}
    \begin{axis}[
        % name the plot, so we later can align the second `axis' environment
        % relative to this one
        name=top plot,
        %
        clip mode=individual,       % <-- changed from `clip=false'
        ytick={0},
        domain=-20:20,
    ]
        \addplot [name path=f] {1+0.5*x}    node [below=2mm] {$f(x)$};
        \addplot [name path=h] {8+1*x}      node [above] {$h(x)$};

    \begin{scope}[ocg={ref=2,name=2,status=invisible}]
%    \only<2->{
        \path [
            name intersections={
                of=f and h,
                by={A},
            },
        ] node [anchor=south] at (A) {$A$};
            \Getxycoords{A}{\Ax}{\Ay};
        \draw [fill=red] (A) circle (2pt);
%    }
    \end{scope}

        % add node (B) to this plot, too
        \node (B) at (axis cs:\Ax,{1+0.6*\Ax}) {};
        \Getxycoords{B}{\Bx}{\By};

     \begin{scope}[ocg={ref=2,name=2,status=invisible}]
     \begin{scope}[ocg={ref=3,name=3,status=invisible}]
     \begin{scope}[ocg={ref=4,name=4,status=invisible}]
%    \only<4->{
        \node (C) at (axis cs:{(\By-1)/0.5},\By) {};
            \Getxycoords{C}{\Cx}{\Cy};
        \draw [fill=red] (C) circle (2pt)   node [above] {C};
        \draw [dashed] (axis cs:\Cx,\pgfkeysvalueof{/pgfplots/ymin})
            -- (C)
            -- (axis cs:\pgfkeysvalueof{/pgfplots/xmin},\Cy)
                node [left] {$y$-component of $C$};
%    }
    \end{scope}\end{scope}\end{scope}
    \end{axis}
    % don't end the `tikzpicture' environment here, but add the other plots
    % as well
    \begin{axis}[
        % align this `axis' environment relative to the top one
        at={(top plot.below south west)},
        anchor=above north west,
        yshift=-2ex,
        %
        ytick={0},
        domain=-20:20,
    ]
        \addplot [name path=g] {1+0.6*x}    node [below=2mm] {$g(x)$};
     \begin{scope}[ocg={ref=2,name=2,status=invisible}]
     \begin{scope}[ocg={ref=3,name=3,status=invisible}]
%    \only<3->{
        \node (B) at (axis cs:\Ax,{1+0.6*\Ax}) {};
%            \Getxycoords{B}{\Bx}{\By};
        \draw [fill=red] (B) circle (2pt)   node [above] {B};
%    }
     \end{scope}\end{scope}
    \end{axis}
    \path node [show ocg={2}, draw, anchor=north west, name=A] at (0,-7) {A}
      node [show ocg={3}, draw, anchor=west, right of=A, name=B] {B}
      node [show ocg={4}, draw, anchor=west, right of=B, name=C] {C}
      node [hide ocg={2 3 4}, draw, anchor=west, right of=C] {Clear};
\end{tikzpicture}
\end{document}
AlexG
  • 54,894