还没有账号去注册
latex 是用于排版的,严格上不算真正的编程语言,因此若需要一些复杂一点的计算功能,最好还是借助其它语言。比如:随机数在latex也是有的,加减法也是可以做的,但想实现一个20或100以内加减法随机算式的小册子,我还是首先想到用python来获得随机的计算式。所以本文讲讲怎么利用latex结合python来实现我们的目标,获得一个由随机计算式构成的小册子。
latex 中使用python有多种方法,比如:利用python宏包、pythontex宏包等。目前发展的功能比较完整的是pythontex宏包。由于latex宏包众多,即便我这种业余使用latex多年的人,也只是熟悉部分的宏包,所以要使用python,我们先来学习怎么使用pythontex,其实这也是所有latexer的常态,5000多个宏包不可能记的过来,有些文档还特别长,更别说其中大量的自定义的命令或宏。
搜索pythontex的相关文档主要有三个,pythontex.pdf,pythontex_gallery.pdf,pythontex_quickstart.pdf。通常这种带quickstart、tutorial,guide这些字眼的文档是快速入门的重要文档。我们先来看看它的内容。
第一部分讲安装我们不用管了,因为texlive完全安装,通常都已经OK了。第二部分讲编译,只有一个关键点,就是中间步需要使用pythontex.py进行编译。至于tex引擎则使用pdftex、xetex、luatex都行。所以对于习惯使用xelatex的我来说,编译步骤应该是(注意下面列出的步骤没有考虑其它内容需要其它工具的编译问题,比如bibtex/biber等):
xelatex test.tex
pythontex.py test.tex
xelatex test.tex
第三和四部分讲基本命令和环境。其中pycode, pyblock, pyverbatim, pysub 环境分别等价于命令\pyc
、\pyb
、\pyv
、\pys
。具体如下:
\py
返回其参数执行代码得到的结果的字符串表示,特别注意其中的python代码是存在返回的,若没有指定返回则返回None。
\pyc
执行参数中的代码并保存结果,且保存变量定义便于后面在\py
命令中调用,比如:\pyc{var = 2}
创建了一个变量,可以在其后用\py{var}
来调用。
\pyb
执行参数中的代码并输出这些代码。比如:\pyb{var = 2}
除了创建了一个变量也输出 var = 2
\pyv
仅将代码输出,而不执行。比如:\pyv{var = 2}
输出文本 var = 2
.
\pys
执行代码中的变量替换. 需要替换的区域用!{...}
表示。比如:使用之前定义的var变量,那么命令 \pys{\verb|var = !{var}|}
将得到 var = 2
.
需要注意的是还有一些命令和环境以sympy和pylab开头,这些命令和环境默认会将sympy和pylab模块引入,使得包含在其中的python代码不用再加载这些python模块,这在第五部分介绍。
另外pyconsole环境可以产生类似终端的效果,不仅包命令输出,也输出计算结果。比如:
\begin{pyconsole}
var = 1 + 1
var
\end{pyconsole}
会得到:
>>> var = 1 + 1
>>> var
2
而其中的变量可以利用\pycon
命令访问。
第6部分讲了一下使用python2情况下的问题,通常我们使用python3,所以无需关注。pythontex也支持其它语言,因为机制本身是相通的。这在第7部分介绍了一下。第8部分讲了一下可以在latex宏中使用前述命令,但要避免在python代码中使用latex特殊字符,比如%等,这很好理解,如果在宏中使用%那么tex引擎可能会认为其后的内容是注释内容。第9部分讲了一些功能和相关工具,如depythontex等。第10部分讲了pythontex输出代码是基于fancyvrb和fvextra宏包的,所以两者的设置可以正常使用,也可以将相关可选设置作为pythontex提供环境的参数传递进来。第11部分介绍了unicode支持,明确pythontex在任意tex引擎下的使用方式。
pythontex提供的三个文档中,pythontex_gallery.pdf提供了一些示例,通过这些示例的实践,我们可以快速的掌握pythontex的使用。实践代码如下:
\documentclass{article}
\usepackage{geometry}
\usepackage{ctex}
\usepackage{pythontex}%[pyginline=true]
\usepackage{amsmath}
\usepackage{graphicx}
\begin{document}
\section{简单命令和环境}
需要注意:python中print的输出等价于于tex文档内部的文本输入
\py{2 + 4**2} %存在返回
\pyc{print('Python says hi!')}
\pyc{print(str(2**2**2) + r'\par')}
\pyc{print('$1 + 1 = {0}$'.format(1 + 1))}
\section{python代码的高亮显示}
在不同的环境下python代码都是高亮的,比如:
\begin{pyconsole}
x = 123
y = 345
z = x + y
z
def f(expr):
return(expr**4)
f(x)
print('Python says hi from the console!')
\end{pyconsole}
pygment命令也可以高亮显示行内的python代码,比如:\pygment{python}|sum=0|,其中第一个参数是代码的语言。
\section{复杂的python运算:符号运算}
利用sympy开头的环境进行符号运算,如:
\begin{sympyblock}
var('x, y, z')
z = x + y
\end{sympyblock}
\begin{sympycode}
from scipy.integrate import quad
from scipy.constants import *
var('x, y, z')
z = x + y
print(r'\begin{align*}')
print(latex(z)+r"\\")
f = x**3 + cos(x)**5
g = Integral(f, x)
print(latex(g)+r"\\")
phi = Symbol(r'\phi')
h = Integral(exp(-phi**2), (phi, 0, oo))
print(latex(h)+r"\\")
myintegral = quad(lambda x: e**-(x**2), 0,1)[0]
print(latex(myintegral)+r"\\")
print(r'\end{align*}')
\end{sympycode}
\begin{sympycode}
x, y, z = symbols('x,y,z')
f = Symbol('f(x,y,z)')
# Define limits of integration
x_llim = 0
x_ulim = 2
y_llim = 0
y_ulim = 3
z_llim = 0
z_ulim = 4
print(r'\begin{align*}')
# Notice how I define f as a symbol, then later as an actual function
left = Integral(f, (x, x_llim, x_ulim), (y, y_llim, y_ulim), (z, z_llim, z_ulim))
f = x*y + y*sin(z) + cos(x+y)
right = Integral(f, (x, x_llim, x_ulim), (y, y_llim, y_ulim), (z, z_llim, z_ulim))
print(latex(left) + '&=' + latex(right) + r'\\')
# For each step, I move limits from an outer integral to an inner, evaluated
# integral until the outer integral is no longer needed
right = Integral(Integral(f, (z, z_llim, z_ulim)).doit(), (x, x_llim, x_ulim),
(y, y_llim, y_ulim))
print('&=' + latex(right) + r'\\')
right = Integral(Integral(f, (z, z_llim, z_ulim), (y, y_llim, y_ulim)).doit(),
(x, x_llim, x_ulim))
print('&=' + latex(right) + r'\\')
right = Integral(f, (z, z_llim, z_ulim), (y, y_llim, y_ulim),
(x, x_llim, x_ulim)).doit()
print('&=' + latex(right) + r'\\')
print('&=' + latex(N(right)) + r'\\')
print(r'\end{align*}')
\end{sympycode}
注意运算中的doit函数。
使用pycode环境并在代码中加入from sympy import * 等价于使用sympycode环境。利用sympy进行公式的推导也是不错的。
\begin{pycode}
from sympy import *
from re import sub
var('x')
# Create a list of functions to include in the table
funcs = ['sin(x)', 'cos(x)', 'tan(x)',
'sin(x)**2', 'cos(x)**2', 'tan(x)**2',
'asin(x)', 'acos(x)', 'atan(x)',
'sinh(x)', 'cosh(x)', 'tanh(x)']
print(r'\begin{align*}')
for func in funcs:
# Put in some vertical space when switching to arc and hyperbolic funcs
if func == 'asin(x)' or func == 'sinh(x)':
print(r'&\\')
myderiv = 'Derivative(' + func + ', x)'
myint = 'Integral(' + func + ', x)'
print(latex(eval(myderiv)) + '&=' +
latex(eval(myderiv + '.doit()')) + r'\quad & \quad')
print(latex(eval(myint)) + '&=' +
latex(eval(myint+'.doit()')) + r'\\')
print(r'\end{align*}')
\end{pycode}
\section{复杂的python运算:绘图}
利用pylab开头的环境进行绘图
\begin{pylabcode}
rc('text', usetex=True)
rc('font', family='serif')
rc('font', size=10.0)
rc('legend', fontsize=10.0)
rc('font', weight='normal')
x = linspace(0, 10)
figure(figsize=(4, 2.5))
plot(x, sin(x), label='$\sin(x)$')
xlabel(r'$x\mathrm{-axis}$')
ylabel(r'$y\mathrm{-axis}$')
legend(loc='lower right')
savefig('myplot.pdf', bbox_inches='tight')
\end{pylabcode}
\begin{figure}[!h]
\centering
\includegraphics[width=0.5\linewidth]{myplot.pdf}
\caption{利用python绘图后插入图片}
\end{figure}
\end{document}
结果为:
通过这个简单的示例,我们已经明白了pythontex的基本使用方式。
编译方式为(注意:为了避免路径问题导致编译错误,可以使用绝对路径):
xelatex eg.tex
python C:\texlive\2020\texmf-dist\scripts\pythontex\pythontex.py D:\work-latex\test\b\eg.tex
xelatex eg.tex
掌握了pythontex,那么实现一个练习册就是一个组装的工作了。
我们用一个A5的纸张,所以设置一下页面:
\usepackage[a5paper,left=0.5cm,right=0.5cm,top=1cm,bottom=1.5cm]{geometry}
分成三栏,所以用一下multicol宏包,同时利用ctex设置一下段首的缩进:
\usepackage[autoindent=1em]{ctex}
\usepackage{multicol}
\setlength{\columnsep}{0.1em}
\setlength\columnseprule{0.4pt}
填写的位置用田字格表示,那么利用tikz画个田字格:
\usepackage{tikz}
\usetikzlibrary{shapes,snakes}
\tikzset{
milines/.style={very thin,dash pattern=on 0.1em off 0.1em, black!50},
mibox/.style={thin},
}
\def\hanzimibox{\raisebox{-0.35em}{\tikz{%米字格形状
\def\xst{0}
\def\yst{0}
\def\xed{1.3em}
\def\yed{1.35em}
\draw[mibox](\xst,\yst) rectangle (\xed,\yed);
%\draw[milines](\xst,\yst) -- (\xed,\yed);
%\draw[milines](\xst,\yed) -- (\xed,\yst);
\draw[milines](\xst,\yed/2) -- (\xed,\yed/2);
\draw[milines](\xed/2,\yst) -- (\xed/2,\yed);
}}}
最后用一个pycode环境,利用python代码使用随机数,循环,输出需要的算式(20和100以内的加减)。最终的形式如下:
\documentclass{article}
\usepackage[a5paper,left=0.5cm,right=0.5cm,top=1cm,bottom=1.5cm]{geometry}
\usepackage[autoindent=1em]{ctex}
\usepackage{pythontex}
\usepackage{amsmath}
\usepackage{multicol}
\setlength{\columnsep}{0.1em}
\setlength\columnseprule{0.4pt}
\usepackage{tikz}
\usetikzlibrary{shapes,snakes}
\tikzset{
milines/.style={very thin,dash pattern=on 0.1em off 0.1em, black!50},
mibox/.style={thin},
}
\def\hanzimibox{\raisebox{-0.35em}{\tikz{%米字格形状
\def\xst{0}
\def\yst{0}
\def\xed{1.3em}
\def\yed{1.35em}
\draw[mibox](\xst,\yst) rectangle (\xed,\yed);
%\draw[milines](\xst,\yst) -- (\xed,\yed);
%\draw[milines](\xst,\yed) -- (\xed,\yst);
\draw[milines](\xst,\yed/2) -- (\xed,\yed/2);
\draw[milines](\xed/2,\yst) -- (\xed/2,\yed);
}}}
\begin{document}
\zihao{-2}
\begin{multicols}{3}
\begin{pycode}
import random
neq=0
while(True):
#a=random.randint(0, 20)
#b=random.randint(0, 20)
c=random.randint(0, 1)
#print(random.choices(range(21),k=2))
lst=random.choices(range(21),k=2)
a,b=lst[0],lst[1]
if(c==0):
if a+b<=20:
print("%2s"%a," + ","%2s"%b," ="+r"\mbox{}\hanzimibox"+"\n")
neq+=1
else:
if(a>=b):
print("%2s"%a," - ","%2s"%b," ="+r"\mbox{}\hanzimibox"+"\n")
neq+=1
if neq>1000:
break
\end{pycode}
\begin{pycode}
import random
neq=0
while(True):
#a=random.randint(0, 100)
#b=random.randint(0, 100)
c=random.randint(0, 1)
#print(random.choices(range(101),k=2))
lst=random.choices(range(101),k=2)
a,b=lst[0],lst[1]
if(c==0):
if a+b<=100:
print("%2s"%a," + ","%2s"%b,"="+r"\mbox{}\hanzimibox"+"\n")
neq+=1
else:
if(a>=b):
print("%2s"%a," - ","%2s"%b,"="+r"\mbox{}\hanzimibox"+"\n")
neq+=1
if neq>729:
break
\end{pycode}
\end{multicols}
\end{document}
结果为:
本文利用pythontex调用python代码随机的生成算术计算式,并结合latex生成算术练习手册,并介绍了pythontex的功能和用法。 当然出于快速考虑,算术计算式没有做太多的优化,否则可以利用方格等方式将其对齐起来,但总的来说是已经不影响使用了。
pythontex_quickstart.pdf
pythontex_gallery.pdf
pythontex.pdf
暂无评论