LaTeX:如何用 LaTeX 做動(dòng)態(tài) gif 圖

作者:王美庭

我的簡(jiǎn)書(shū)主頁(yè)請(qǐng)點(diǎn)擊這


一、引言

我們知道,一般我們作圖都是用 stata、matlab 或其他軟件,然后再將作出的圖片另做他用,如做定格動(dòng)畫(huà)。但一般很少人直接用latex去做,原因有兩點(diǎn):(1)作出的圖為PDF版本,還需通過(guò)一定的途徑轉(zhuǎn)化為其他格式如PNG格式;(2)目前很多軟件如 imagemagick、Adobe acrobat DC轉(zhuǎn)出的圖片效果不是很好(失真率很大);(3)定格動(dòng)畫(huà)本身需要很多圖片素材,一般需要跑循環(huán)才能完成,而 latex 的循環(huán)語(yǔ)句比較難閱讀和使用的。本文的目的在于為大家創(chuàng)建一個(gè)用 latex 做定格動(dòng)畫(huà)的模式,以供大家套用。


二、先做出單張PDF圖

這里我們先做一個(gè)角度為120^\circ的圖。

代碼如下:

%采用pdflatex編譯(速度大大提升)
\documentclass[12pt,a4paper,UTF8]{ctexart}
\usepackage{tikz}
\usepackage{siunitx} %需要用到\ang[options]{degrees}命令
\newcommand{\iangle}{120}
%\usepackage{ctex}
\usepackage[landscape]{geometry} %使得頁(yè)面橫置
%對(duì)于中文字體的處理:pdfLaTeX用CJK包或ctex包會(huì)出錯(cuò),而用\documentclass[UTF8]{ctexart}則沒(méi)有問(wèn)題。

\begin{document}
\begin{tikzpicture}[scale=1.5] %scale參數(shù)可以使得圖形放大一定的倍數(shù)而本身的字體大小可以保持不變。
    %畫(huà)左邊的圓
    %scope環(huán)境里夠成一整個(gè)區(qū)塊,然后可以使這一整個(gè)區(qū)塊進(jìn)行平移。
    \begin{scope}[xshift=-1.75cm] 
        \fill[fill=gray,fill opacity=0.2]
        (0,0) -- (0:1) arc (0:\iangle:1) -- cycle;
        \filldraw[fill=gray,fill opacity=0.5]
        (0,0) --(0:0.3) arc (0:\iangle:0.3) -- cycle;
        \draw[->] (-1.2,0) -- (1.2,0);
        \draw[->] (0,-1.2) -- (0,1.2);
        \draw[thick] (0,0) circle (1);
        \coordinate[label=\iangle:$P$] (P) at (\iangle:1);
        \coordinate[label=below:$P_0$] (P0) at (P |- 0,0);
        \draw (0,0) -- (P);
        \draw (P) -- (P0);
        \node[right] at (\iangle/2:0.3) {\ang{\iangle}};
    \end{scope}
    %畫(huà)右邊的正弦曲線
    \draw[->] (0,0) -- ({rad(210)},0);
    \draw[->] (0,-1.2) -- (0,1.2);
    \draw[thick,domain=0:rad(210)] plot(\x,{sin(\x r)}) node[right] {$\sin x$};
    \foreach \t in {0,90,180} {
        \draw ({rad(\t)},-0.05) -- ({rad(\t)},0.05);
        \node[below,outer sep=2pt,fill=white,font=\small]
        at ({rad(\t)},0) {\ang{\t}};    
    }
    \foreach \y in {-1,1} {
        \draw (-0.05,\y) -- (0.05,\y);
    }
    \coordinate[label=above:$Q$] (Q) at ({rad(\iangle)},{sin(\iangle)});
    \coordinate[label=below:$Q_0$] (Q0) at (Q |- 0,0);
    \draw (Q) -- (Q0);
    %左右相互連接
    \draw[dashed] (P) -- (Q);
\end{tikzpicture}
\end{document}

三、用preview宏包切除tikzpicture環(huán)境周?chē)嘤嗟目瞻祝ɑ蛘咭部梢栽O(shè)定周?chē)潭ǖ目瞻组L(zhǎng)度)

代碼如下:

%直接不用腳本,即注釋掉\pgfrealjobname{survey}等系列命令,然后用pdflatex進(jìn)行編譯。
%編譯后每一個(gè)tikzpicture環(huán)境中的圖都在單獨(dú)的一個(gè)頁(yè)面存在,然后可以通過(guò)\setlength\PreviewBorder{距離}設(shè)置四周邊界的大小,以達(dá)到更好的觀賞目的。
\documentclass[12pt,a4paper]{article}
\usepackage{tikz}
%\pgfrealjobname{survey}
\usepackage{siunitx} %需要用到\ang[options]{degrees}命令
\newcommand{\iangle}{120}
\usepackage[pdftex,active,tightpage]{preview}
\setlength\PreviewBorder{2cm} % use to add a border around the image
\PreviewEnvironment{tikzpicture}

\begin{document}
%\beginpgfgraphicnamed{survey-f1}
\begin{tikzpicture}[scale=1.5]
    %畫(huà)左邊的圓
    \begin{scope}[xshift=-1.75cm]
        \fill[fill=gray,fill opacity=0.2]
        (0,0) -- (0:1) arc (0:\iangle:1) -- cycle;
        \filldraw[fill=gray,fill opacity=0.5]
        (0,0) --(0:0.3) arc (0:\iangle:0.3) -- cycle;
        \draw[->] (-1.2,0) -- (1.2,0);
        \draw[->] (0,-1.2) -- (0,1.2);
        \draw[thick] (0,0) circle (1);
        \coordinate[label=\iangle:$P$] (P) at (\iangle:1);
        \coordinate[label=below:$P_0$] (P0) at (P |- 0,0);
        \draw (0,0) -- (P);
        \draw (P) -- (P0);
        \node[right] at (\iangle/2:0.3) {\ang{\iangle}};
    \end{scope}
    %畫(huà)右邊的正弦曲線
    \draw[->] (0,0) -- ({rad(210)},0);
    \draw[->] (0,-1.2) -- (0,1.2);
    \draw[thick,domain=0:rad(210)] plot(\x,{sin(\x r)}) node[right] {$\sin x$};
    \foreach \t in {0,90,180} {
        \draw ({rad(\t)},-0.05) -- ({rad(\t)},0.05);
        \node[below,outer sep=2pt,fill=white,font=\small]
        at ({rad(\t)},0) {\ang{\t}};    
    }
    \foreach \y in {-1,1} {
        \draw (-0.05,\y) -- (0.05,\y);
    }
    \coordinate[label=above:$Q$] (Q) at ({rad(\iangle)},{sin(\iangle)});
    \coordinate[label=below:$Q_0$] (Q0) at (Q |- 0,0);
    \draw (Q) -- (Q0);
    %左右相互連接
    \draw[dashed] (P) -- (Q);
\end{tikzpicture}
%\endpgfgraphicnamed
\end{document}

四、用循環(huán)語(yǔ)句生成連續(xù)的PDF圖(在前面的preview宏包的作用下,每個(gè)tikzpicture都為單獨(dú)的一頁(yè))

代碼如下(從0^\circ360^\circ共361頁(yè)P(yáng)DF圖):

\documentclass[12pt,a4paper]{article}
\usepackage{tikz}
\usepackage{ifthen}
\usepackage{siunitx} %需要用到\ang[options]{degrees}命令
\usepackage[pdftex,active,tightpage]{preview}
\setlength\PreviewBorder{1cm} % use to add a border around the image
\PreviewEnvironment{tikzpicture}

%微調(diào)系數(shù)
\newcommand{\iangle}{0} %設(shè)定角度起始值
\newcommand{\ax}{0.3*1.85} %橢圓a值
\newcommand{\by}{0.3*1.7} %橢圓b值
\newcommand{\p}{1*1.2} %放置的P離原點(diǎn)的距離

\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\forrange}{mO{1}mm}
{
    \int_step_function:nnnN {#1} {#2} {#3} #4
}
\ExplSyntaxOff
\newcommand{\mycommand}[1]{
    \renewcommand{\iangle}{#1}
    \begin{tikzpicture}[scale=1.5]
    %畫(huà)左邊的圓
    \begin{scope}[xshift=-2cm] 
    \fill[fill=gray,fill opacity=0.2]
    (0,0) -- (0:1) arc (0:\iangle:1) -- cycle;
    \filldraw[fill=gray,fill opacity=0.5]
    (0,0) --(0:0.3) arc (0:\iangle:0.3) -- cycle;
    \draw[->] (-1.5,0) -- (1.5,0);
    \draw[->] (0,-1.5) -- (0,1.5);
    \draw[thick] (0,0) circle (1);
    \coordinate (P) at (\iangle:1);
    \node at (\iangle:\p) {$P$};
    \coordinate[label=below:$P_0$] (P0) at (P |- 0,0);
    \draw (0,0) -- (P);
    \draw (P) -- (P0);
    \node at ({\ax*cos(\iangle/2)},{\by*sin(\iangle/2)}) {\ang{\iangle}};
    \end{scope} 
    %畫(huà)右邊的正弦曲線
    \draw[->] (0,0) -- ({rad(390)},0);
    \draw[->] (0,-1.5) -- (0,1.5);
    \draw[thick,smooth,domain=0:rad(390)] plot(\x,{sin(\x r)}) node[right] {$\sin x$};
    \foreach \t in {0,90,...,360} {
        \draw ({rad(\t)},-0.05) -- ({rad(\t)},0.05);
        \node[below,outer sep=2pt,fill=white,font=\small]
        at ({rad(\t)},0) {\ang{\t}};    
    }
    \foreach \y in {-1,1} {
        \draw (-0.05,\y) -- (0.05,\y);
    }
    \ifthenelse{\iangle < 180}{
        \coordinate[label=above:$Q$] (Q) at ({rad(\iangle)},{sin(\iangle)});}{
        \coordinate[label=below:$Q$] (Q) at ({rad(\iangle)},{sin(\iangle)});
        }
    \coordinate[label=below:$Q_0$] (Q0) at (Q |- 0,0);
    \draw (Q) -- (Q0);
    %左右相互連接
    \draw[dashed] (P) -- (Q);
    \end{tikzpicture}
}

\begin{document}
\forrange{0}[1]{360}{\mycommand}
\end{document}

五、PDF圖轉(zhuǎn)化為PNG圖

這個(gè)我試過(guò)imagemagick的convert,Adobe acrobat DC自帶的轉(zhuǎn)化,效果都不是很好。這里提供一個(gè)國(guó)外的網(wǎng)站,效果是我用過(guò)最好的:它會(huì)把前面361頁(yè)的PDF文檔轉(zhuǎn)化為361張圖片(命名格式為:原文件名稱(chēng)+數(shù)字序號(hào))。

六、做GIF圖

這里可以用imagemagick的命令實(shí)現(xiàn),具體為:

magick -delay 1 "./figures/*.png" together.gif

-delay標(biāo)明每一張圖片的時(shí)間間隔,我的測(cè)試結(jié)果是:這里的1單位長(zhǎng)度時(shí)間接近0.04s(也就是我們?cè)谖覀冊(cè)谧鲆曨l中常常見(jiàn)到的1s=25幀中的一幀)。./figures/*.png的意思是我的361張PNG圖都放在了當(dāng)前目錄下的figures子目錄下,最后生成的together.gif將被放在當(dāng)前路徑下。于是我們就得到了文章開(kāi)頭的圖(不知道為什么,做出來(lái)的gif放在了網(wǎng)上之后速度就變慢了)。

擴(kuò)展:$0.0^\circ-360.0^\circ$共3600個(gè)點(diǎn)形成的gif

過(guò)程大致如上,但需要注意以下幾個(gè)問(wèn)題:

  • 里面的循環(huán)step不能出現(xiàn)小數(shù)。
  • \ang{}命令里面若寫(xiě)為\ang{a,b},則ab都必須要是整數(shù)。
  • 用內(nèi)核的循環(huán)比tizk的循環(huán)更快。
  • 參數(shù)傳遞時(shí)盡量一步到位,以提升運(yùn)行速度。

具體代碼如下:

\documentclass[12pt,a4paper]{article}
\usepackage{tikz} %needed tikz library
\usetikzlibrary{math}
\usepackage{ifthen}
\usepackage{siunitx} %需要用到\ang[options]{degrees}命令
\usepackage[pdftex,active,tightpage]{preview}
\setlength\PreviewBorder{1cm} % use to add a border around the image
\PreviewEnvironment{tikzpicture}

%微調(diào)系數(shù)
\newcommand{\ax}{0.3*1.85} %橢圓a值
\newcommand{\by}{0.3*1.7} %橢圓b值
\newcommand{\p}{1*1.2} %放置的P離原點(diǎn)的距離

\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\forrange}{mO{1}mm}
{
    \int_step_function:nnnN {#1} {#2} {#3} #4
}
\ExplSyntaxOff
\newcommand{\mycommand}[1]{
    \begin{tikzpicture}[scale=2.05]
    \tikzmath{
        \xx = int(#1*0.1);
        \yy = int(mod(#1,10));
    }
    %畫(huà)左邊的圓
    \begin{scope}[xshift=-2cm] 
    \fill[fill=gray,fill opacity=0.2]
    (0,0) -- (0:1) arc (0:#1/10:1) -- cycle;
    \filldraw[fill=gray,fill opacity=0.5]
    (0,0) --(0:0.3) arc (0:#1/10:0.3) -- cycle;
    \draw[->] (-1.5,0) -- (1.5,0);
    \draw[->] (0,-1.5) -- (0,1.5);
    \draw[thick] (0,0) circle (1);
    \coordinate (P) at (#1/10:1);
    \node at (#1/10:\p) {$P$};
    \coordinate[label=below:$P_0$] (P0) at (P |- 0,0);
    \draw (0,0) -- (P);
    \draw (P) -- (P0);
    \node at ({\ax*cos(#1/10/2)},{\by*sin(#1/10/2)}) {\ang{\xx,\yy}};
    \end{scope} 
    %畫(huà)右邊的正弦曲線
    \draw[->] (0,0) -- ({rad(390)},0);
    \draw[->] (0,-1.5) -- (0,1.5);
    \draw[thick,smooth,domain=0:rad(390)] plot(\x,{sin(\x r)}) node[right] {$\sin x$};
    \foreach \t in {0,90,...,360} {
        \draw ({rad(\t)},-0.05) -- ({rad(\t)},0.05);
        \node[below,outer sep=2pt,fill=white,font=\small]
        at ({rad(\t)},0) {\ang{\t}};    
    }
    \foreach \y in {-1,1} {
        \draw (-0.05,\y) -- (0.05,\y);
    }
    \ifthenelse{#1 < 1800}{
        \coordinate[label=above:$Q$] (Q) at ({rad(#1/10)},{sin(#1/10)});}{
        \coordinate[label=below:$Q$] (Q) at ({rad(#1/10)},{sin(#1/10)});
        }
    \coordinate[label=below:$Q_0$] (Q0) at (Q |- 0,0);
    \draw (Q) -- (Q0);
    %左右相互連接
    \draw[dashed] (P) -- (Q);
    \end{tikzpicture}
}

\begin{document}
\forrange{0}[1]{3600}{\mycommand}
\end{document}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • ## ImageMagick 命令行處理 ImageMagic命令行能像這樣簡(jiǎn)單: 或者它很復(fù)雜,就像下面的: 不...
    焉知非魚(yú)閱讀 10,779評(píng)論 2 9
  • 先占個(gè)位,以后解釋原理 如何用 Matplotlib 畫(huà) GIF 動(dòng)圖 原文來(lái)源:http://codingpy....
    白菜代碼小推車(chē)閱讀 3,679評(píng)論 0 4
  • 在你完成應(yīng)用程序的beta版本后,最后會(huì)有些人去幫你測(cè)試,使你去完善應(yīng)用程序……或者會(huì)有投資青睞。但是如果測(cè)試人員...
    zmp1123閱讀 6,892評(píng)論 15 46
  • 今天中午,覺(jué)得肚子有點(diǎn)餓,但是又不想吃主食,于是就屁顛屁顛去剝了一個(gè)柚子。 說(shuō)實(shí)話,我家柚子的個(gè)頭比人家五塊五一個(gè)...
    你好涵閱讀 481評(píng)論 2 16
  • 天邊之月,枕邊之書(shū) 思罷遠(yuǎn)處,低頭細(xì)顧 心意躊躇,燈火螢螢 映我影孤,薛濤小箋 心事難書(shū),通信錄內(nèi) 高朋滿(mǎn)座,誰(shuí)有...
    丁_香閱讀 592評(píng)論 29 18

友情鏈接更多精彩內(nèi)容