2

With the BIG help of @njsg (Nuno Silva) I made this plot. The goal is use it as a animation inside a beamer slide.

\documentclass{standalone}
\usepackage{tikz}
\usepackage{pgfplots}
\pgfplotsset{compat=newest}
\usepackage[export]{animate}
%\usepackage{animate}
\usepackage{pythontex}
\usepackage[output-decimal-marker={,}]{siunitx}

% Código copiado de
% https://tex.stackexchange.com/questions/389478/how-can-i-access-a-float-defined-via-pgfmathsetmacro-from-pythontex/389530#389530
\makeatletter
\newcommand{\pythontexassign}[2]{%
  \expandafter\pythontexassign@i\expandafter{#2}{#1}}
\newcommand{\pythontexassign@i}[2]{%
  \pyc{#2=#1}}
\makeatother
% 

\newcommand{\pySI}[2]{\py{'\SI{' + str(#1) + '}{#2}'}} 

\begin{document}

\begin{pycode}
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from sympy import *

x       =   symbols('x')

xp      =   1
func    =   x**2+2
Deltax  =   9
Divisoes=   10
dx      =   Deltax/Divisoes

func    =   sympify(func)
dfunc   =   diff(func, x)

yp      =   func.subs(x,xp)
mt      =   dfunc.subs(x,xp)
bt      =   yp-mt*xp
tang    =   mt*x+bt
tang    =   sympify(tang)

def sympy2pgf(expression):
    return latex(expression,mul_symbol='times')\
        .replace(r'\times','*')\
            .replace('{','(').replace('}',')')

def teste(valor):
    return valor

def calcpos(i):
    xi  =   (xp+Deltax) - dx*i
    yi  =   func.subs(x,xi)
    return(xi,yi)

def recta(i):
    if xp == (xp+Deltax) - dx*i:
        return sympy2pgf(tang)
    else:
        ms   = (calcpos(i)[1] - yp)/(calcpos(i)[0] - xp)
        bs   = yp - ms*xp
        seca = ms*x+bs
        seca = sympify(seca)
        return sympy2pgf(seca)
\end{pycode}

\begin{animateinline}[poster=last,autoplay,loop]{5} 
\multiframe{10}{rt=1+1}{% 
\resizebox{0.5\textwidth}{!}{%
\begin{tikzpicture}[shift={(1,1)},x=1cm, y=1cm,
    extended line/.style={shorten >=-#1,shorten <=-#1},
    extended line/.default=2cm]
\begin{axis}[% 
    x=1cm, y=0.1cm,
    anchor=target,
    enlargelimits=0.05,
    axis x line = center,
    axis y line = left,
    axis line style={line width=1pt,->,opacity=1},
    ymin=0,
    ymax=120,
    xmin=0,
    xmax=12,
    clip mode=individual,
    %clip mode=false,
    axis x line=bottom,
    axis y line=left,
    xtick={0,2,...,10},
    ytick={0,20,...,100},
    ticklabel style={font=\normalsize,opacity=1},
    xlabel={$t/\si{s}$},
    ylabel={$x/\si{m}$},
    y tick label style={
        /pgf/number format/.cd,
        fixed,
        fixed zerofill,
        precision=1,
        use comma,
        /tikz/.cd},
    x tick label style={
        /pgf/number format/.cd,
        fixed,
        fixed zerofill,
        precision=1,
        use comma,
        /tikz/.cd},
    every axis x label/.style={
        at={(ticklabel* cs:1)},
        anchor=north east,
        style={font=\normalsize},
        opacity=1},
    every axis y label/.style={
        at={(ticklabel* cs:1)},
        anchor=north east,
        style={font=\normalsize},
        opacity=1},
    %ticks=none,
]

% Atribuição da variável \rt a meurt
\pythontexassign{meurt}{\rt}

% curva
\pys{\addplot [domain=0:10, samples=100, color=blue ]{!{sympy2pgf(func)}};}

% rectas 
\pys{\addplot [domain=0:10, samples=100, color=blue ]{!{recta(meurt)}};}

% Ponto fixo
\pys{\coordinate (P) at  (!{xp},!{yp});}
\node[outer sep=0pt,circle, fill=red,inner sep=1.5pt] (P) at (P) {};

% Ponto variável
\pys{\coordinate (Q) at  (!{calcpos(meurt)[0]},!{calcpos(meurt)[1]});}
\node[outer sep=0pt,circle, fill=red,inner sep=1.5pt] (Q) at (Q) {};

% tracejados
\pys{\draw[red,dotted,very thick] (P) -- (!{xp},0);}
\pys{\draw[red,dotted,very thick] (P) -- (0,!{yp});}
\pys{\draw[red,dotted,very thick] (Q) -- (!{calcpos(meurt)[0]},0);}
\pys{\draw[red,dotted,very thick] (Q) -- (0,!{calcpos(meurt)[1]});}

% chavetas
\pys{\draw[decorate,decoration={brace,amplitude=3pt,mirror}] (!{xp},-5.0) -- (!{calcpos(meurt)[0]},-5.0) ; }
\pys{\draw[decorate,decoration={brace,amplitude=3pt,mirror}] (-.90,!{calcpos(meurt)[1]}) -- (-.90,!{yp}) ; }

% Deltas
\pys{\pgfmathsetmacro\XP{!{xp}}}
\pys{\pgfmathsetmacro\YP{!{yp}}}
\pys{\pgfmathsetmacro\XI{!{calcpos(meurt)[0]}}}
\pys{\pgfmathsetmacro\YI{!{calcpos(meurt)[1]}}}
\pgfmathsetmacro\DELTAX{ \XI - \XP }
\pgfmathsetmacro\DELTAY{ \YI - \YP }
\node[text width=3cm] at (\XI,-10.0) {$\Delta x =$ \DELTAX $\si{\second}$};
\node[text width=3cm] at (-1.55,\YI) {$\Delta y =$ \DELTAY $\si{\metre}$ };

\node[coordinate] (target) at (axis cs:0,0){};
\end{axis}
\end{tikzpicture}}}
\end{animateinline}

\end{document}

But, when I change from this

\usepackage[export]{animate}
%\usepackage{animate}

to this

%\usepackage[export]{animate}
\usepackage{animate}

the result is unexpected, as the images show

enter image description here

and the next one, the problematic:

enter image description here

what I can do to solve this issue.


To AlexG

  1. compile de next code with:

xelatex figura.tex pythontex figura. xelatex figura.tex

\documentclass{standalone}
\usepackage{tikz}
\usepackage{pgfplots}
\pgfplotsset{compat=newest}
\usepackage[export]{animate}
%\usepackage{animate}
\usepackage{pythontex}
\usepackage[output-decimal-marker={,}]{siunitx}

% Código copiado de
% https://tex.stackexchange.com/questions/389478/how-can-i-access-a-float-defined-via-pgfmathsetmacro-from-pythontex/389530#389530
\makeatletter
\newcommand{\pythontexassign}[2]{%
  \expandafter\pythontexassign@i\expandafter{#2}{#1}}
\newcommand{\pythontexassign@i}[2]{%
  \pyc{#2=#1}}
\makeatother
% 

\newcommand{\pySI}[2]{\py{'\SI{' + str(#1) + '}{#2}'}} 

\begin{document}

\begin{pycode}
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from sympy import *

x       =   symbols('x')

xp      =   1
func    =   x**2+2
Deltax  =   9
Divisoes=   10
dx      =   Deltax/Divisoes

func    =   sympify(func)
dfunc   =   diff(func, x)

yp      =   func.subs(x,xp)
mt      =   dfunc.subs(x,xp)
bt      =   yp-mt*xp
tang    =   mt*x+bt
tang    =   sympify(tang)

def sympy2pgf(expression):
    return latex(expression,mul_symbol='times')\
        .replace(r'\times','*')\
            .replace('{','(').replace('}',')')

def teste(valor):
    return valor

def calcpos(i):
    xi  =   (xp+Deltax) - dx*i
    yi  =   func.subs(x,xi)
    return(xi,yi)

def recta(i):
    if xp == (xp+Deltax) - dx*i:
        return sympy2pgf(tang)
    else:
        ms   = (calcpos(i)[1] - yp)/(calcpos(i)[0] - xp)
        bs   = yp - ms*xp
        seca = ms*x+bs
        seca = sympify(seca)
        return sympy2pgf(seca)
\end{pycode}

\begin{animateinline}[poster=first,autoplay,loop]{4} 
\multiframe{10}{rt=1+1}{% 
\resizebox{0.5\textwidth}{!}{%
\begin{tikzpicture}[shift={(1,1)},x=1cm, y=1cm,
    extended line/.style={shorten >=-#1,shorten <=-#1},
    extended line/.default=2cm]
\begin{axis}[% 
    x=1cm, y=0.1cm,
    anchor=target,
    enlargelimits=0.05,
    axis x line = center,
    axis y line = left,
    axis line style={line width=1pt,->,opacity=1},
    ymin=0,
    ymax=120,
    xmin=0,
    xmax=12,
    clip mode=individual,
    axis x line=bottom,
    axis y line=left,
    xtick={0,2,...,10},
    ytick={0,20,...,100},
    ticklabel style={font=\normalsize,opacity=1},
    xlabel={$t/\si{s}$},
    ylabel={$x/\si{m}$},
    y tick label style={
        /pgf/number format/.cd,
        fixed,
        fixed zerofill,
        precision=1,
        use comma,
        /tikz/.cd},
    x tick label style={
        /pgf/number format/.cd,
        fixed,
        fixed zerofill,
        precision=1,
        use comma,
        /tikz/.cd},
    every axis x label/.style={
        at={(ticklabel* cs:1)},
        anchor=north east,
        style={font=\normalsize},
        opacity=1},
    every axis y label/.style={
        at={(ticklabel* cs:1)},
        anchor=north east,
        style={font=\normalsize},
        opacity=1},
]

% Atribuição da variável \rt a meurt
\pythontexassign{meurt}{\rt}

% curva
\pys{\addplot [domain=0:10, samples=100, color=blue ]{!{sympy2pgf(func)}};}

% rectas 
\pys{\addplot [domain=0:10, samples=100, color=blue ]{!{recta(meurt)}};}

% Ponto fixo
\pys{\coordinate (P) at  (!{xp},!{yp});}
\node[outer sep=0pt,circle, fill=red,inner sep=1.5pt] (P) at (P) {};

% Ponto variável
\pys{\coordinate (Q) at  (!{calcpos(meurt)[0]},!{calcpos(meurt)[1]});}
\node[outer sep=0pt,circle, fill=red,inner sep=1.5pt] (Q) at (Q) {};

% tracejados
\pys{\draw[red,dotted,very thick] (P) -- (!{xp},0);}
\pys{\draw[red,dotted,very thick] (P) -- (0,!{yp});}
\pys{\draw[red,dotted,very thick] (Q) -- (!{calcpos(meurt)[0]},0);}
\pys{\draw[red,dotted,very thick] (Q) -- (0,!{calcpos(meurt)[1]});}

% chavetas
\pys{\draw[decorate,decoration={brace,amplitude=3pt,mirror}] (!{xp},-5.0) -- (!{calcpos(meurt)[0]},-5.0) ; }
\pys{\draw[decorate,decoration={brace,amplitude=3pt,mirror}] (-.90,!{calcpos(meurt)[1]}) -- (-.90,!{yp}) ; }

% Deltas
% inicialização
\pgfmathsetmacro\XP{0.0}
\pgfmathsetmacro\YP{0.0}
\pgfmathsetmacro\XI{0.0}
\pgfmathsetmacro\YI{0.0}
% operação
\pys{\pgfmathsetmacro\XP{!{xp}}}
\pys{\pgfmathsetmacro\YP{!{yp}}}
\pys{\pgfmathsetmacro\XI{!{calcpos(meurt)[0]}}}
\pys{\pgfmathsetmacro\YI{!{calcpos(meurt)[1]}}}
\pgfmathsetmacro\DELTAX{ \XI - \XP }
\pgfmathsetmacro\DELTAY{ \YI - \YP }
\node[text width=3cm] at (\XI,-10.0) {$\Delta x =$ \DELTAX $\si{\second}$};
\node[text width=3cm] at (-1.55,\YI) {$\Delta y =$ \DELTAY $\si{\metre}$ };

\node[coordinate] (target) at (axis cs:0,0){};
\end{axis}
\end{tikzpicture}}}
\end{animateinline}

\end{document}

you have just make a pdf with the name figura.pdf

  1. then, compile the next code with

xelatex beamer.tex

\documentclass[compress]{beamer}
\usepackage{animate}

\begin{document}
\section{Figura}
\begin{frame}
\begin{figure}
\animategraphics[autoplay,loop]{4}{figura}{}{}
\end{figure}
\end{frame}
\end{document}

Works for me.

enter image description here

  • The issue I get is Undefined control sequence \XI, to get it to work I had to comment out the four lines starting with \pgfmathsetmacro\DELTAX{ \XI - \XP }, run pdflatex then pythontex, then uncomment those four lines, and run pdflatex again. I don't quite understand what the problem is though, is there a lot of whitespace in the second image? Edit: that was without changing the code at all though. – Torbjørn T. Sep 14 '19 at 12:14
  • \XI is being defined inside \pys{}, which means it will not be defined until there is some result from pythontex to embed in the document. Either all uses of \XI need to be wrapped with \pys or pysub (while this looks like it is possible here, it might not be always possible), or \XI must be defined in some way outside pythontex (for example, by adding \pgfmathsetmacro\XI{42} (or some other value, of course) before the \pys{...} command which will set \XI — somebody else might have a more elegant solution, though?). – njsg Sep 14 '19 at 13:17
  • @TorbjørnT., thankyou! the pdf comes very large, with the graphic on right side. – Luis Ferreira Sep 14 '19 at 13:43
  • @njsg still the same as before.

    % Deltas

    % inicialização

    \pgfmathsetmacro\XP{0.0}

    \pgfmathsetmacro\YP{0.0}

    \pgfmathsetmacro\XI{0.0}

    \pgfmathsetmacro\YI{0.0}

    % operação

    \pys{\pgfmathsetmacro\XP{!{xp}}}

    \pys{\pgfmathsetmacro\YP{!{yp}}}

    \pys{\pgfmathsetmacro\XI{!{calcpos(meurt)[0]}}}

    \pys{\pgfmathsetmacro\YI{!{calcpos(meurt)[1]}}}

    \pgfmathsetmacro\DELTAX{ \XI - \XP}

    \pgfmathsetmacro\DELTAY{ \YI - \YP}

    \node[text width=3cm] at (\XI,-10.0) {$\Delta x =$ \DELTAX $\si{\second}$};

    \node[text width=3cm] at (-1.55,\YI) {$\Delta y =$ \DELTAY $\si{\metre}$ };

    – Luis Ferreira Sep 14 '19 at 13:45
  • Forgot to mention one thing: the P and Q nodes are defined within a \pys, so at the first run they are not available, and you get an error. Do as @njsg suggest, and use a \pys for those two \nodes as well. Doesn't solve the whitespace problem, but it would make the code compile without errors. – Torbjørn T. Sep 14 '19 at 14:17
  • That said, given that you want to make an animation, I don't really understand why you don't want the export option in the first place. – Torbjørn T. Sep 14 '19 at 14:20
  • 1
    @TorbjørnT., if I understand animate correctly, export exports the animation with the still frames as different pages, while, without that option, it is exported as a PDF embedded animation. – njsg Sep 14 '19 at 14:47
  • @TorbjørnT. because I need the embedded animation to use it in a Beamer presentation. – Luis Ferreira Sep 14 '19 at 18:12
  • 1
    In theory if you create a multi-page PDF called foo.pdf, you could load the animate package in your presentation and use \animategraphics{2}{foo}{}{} to get an animation running at 2 fps (cf. https://tex.stackexchange.com/q/30683/). I couldn't get it to work, but I don't know if it's because the PDF viewers I tried couldn't handle the animation. – Torbjørn T. Sep 14 '19 at 18:30
  • @TorbjørnT. Thank you. I've follow your advice and works! :-) – Luis Ferreira Sep 14 '19 at 20:50
  • @njsg - Thank you, Nuno, for your knowledge and patience. :-) – Luis Ferreira Sep 14 '19 at 20:52
  • So, how did you get those plots in your question when the code you posted does not compile? Put the code you really used and the required compilation steps in your question. – AlexG Sep 16 '19 at 09:20
  • @AlexG : I've edited the post. – Luis Ferreira Sep 16 '19 at 12:52
  • The first xelatex already fails. ! Package pgf Error: No shape named P is known. – AlexG Sep 16 '19 at 13:07
  • @AlexG - I don't what to say. Try with pdflatex in the same way. – Luis Ferreira Sep 16 '19 at 14:16
  • @AlexG only a compilation without input from pythontex fails. If you let it run despite the errors (hit return a couple times, or use xelatex -interaction nonstopmode, for example), you should be able to run pythontex and latex itself won't fail anymore after that. – njsg Sep 16 '19 at 14:18
  • Chances are that, at some point, P and Q were defined outside pythontex commands, or were only used inside pythontex commands. From there, it'd be easy to end up with a document that gives these errors if compiled from scratch. – njsg Sep 16 '19 at 14:23
  • By the way, the whitespace issue disappears if the preview option is passed to the document class. But that will also change the output of animate with the export option. – njsg Sep 16 '19 at 14:29
  • @njsg It looks as though the whitespace is produced by the python calls. I wonder why Python is used at all. The analytical expression for the derivative is easily found. It allows you to calculate the intersection points of the secant line with the curve without the need for an external program. – AlexG Sep 16 '19 at 15:06
  • @AlexG : Well... make your proposal, I've done mine, using pythontex. And I like it! :-) – Luis Ferreira Sep 16 '19 at 15:13
  • @AlexG So far this is looking like an issue between pythontex and standalone, similar to [1] and [2]. – njsg Sep 16 '19 at 19:41
  • I was able to reproduce this with a minimal example that has standalone and pythontex. Seems to be related to the pygments feature, as the issue does not show up when I compile it from scratch with the pygments=false option of pythontex. – njsg Sep 16 '19 at 19:58
  • This is enough to reproduce: \documentclass{standalone}\usepackage{pythontex}\begin{document}Teste: \py{'1'}\end{document} – njsg Sep 16 '19 at 20:04

0 Answers0