我正在写一篇相当长的文章,其中包含许多不同的图表。这些图表的范围从简单的图表(如abs(x)
或)x^2
到具有一阶和二阶导数的高阶多项式,以及非线性(S 型、正切等)。有时它们也是三维的。
我在 tikzpicture 中使用 pgfplot,然后使用 gnuplot。对于简单的图,这很简单。但是,对于更复杂的图(可能包含非连续性点),gnuplot 表达式变得越来越难以理解和维护。对于某些图,我无论如何都需要随机创建的点(创建一次,然后固定),这些点需要根据函数进行“分类”。
对于所有绘图,我都有(或可以创建)Python 脚本来输出可在 pgfplot 表导入功能中使用的坐标表。对于 x^2 来说,这似乎有点过分,但对于更复杂的绘图来说,这确实是必要的。而且对于更高的多项式,我不必手动进行导数。
这适用于二维中的点或线的图,但不适用于三维中的图,因为导入表的点数超出了 LaTeX 的内存(x 和 y 各有 1000 个样本,因此有 1,000,000 个坐标)。
由于我本来就有 Python 函数,所以我也可以用 matplotlib(或 seaborn 等)来创建带有图的 PDF。但缺点是,这些图看起来不像用 LaTeX/gnuplot 绘制时那样(颜色、样式等不同),所以我必须在两个不同的地方维护样式。
是否有此类绘图的最佳实践?我想要一种类型的绘图(仅有的gnuplot 或仅有的我使用 Python 作为示例,而不是混合不同的方法。
答案1
几年前我就遇到过这个问题。在我的案例中,我想确保我的 tikz/pgfplots
- 可以使用轴和窗口来完成
- 能够显示方格纸背景
- 能够同时处理多个图表
- 可以处理更复杂的功能
现在,简单的功能(比如你在高中看到的那些)都可以轻松完成模板1:我已经发布Tikz 图 x^a*cos(ln(x))。你会看到有很多设置轴环境的设置。注释掉的行%grid = both,%grid for major ticks (every integer) and minor ticks
阻止了方格纸背景。经过一些尝试我发现sagetex
软件包能够解决您所关心的问题:处理更复杂的功能. 文档可在 CTAN 上找到这里;该软件包让您可以访问计算机代数系统 (CAS),即 SAGE,以及 Python 编程。从 CAS 中,您可以获得更复杂的函数,例如 erf、riemann zeta、fourier 等。有关内置函数的 SAGE 文档是这里。您还可以获得精确的计算、计算导数和积分的能力以及选择绘制点的能力。由于 SAGE 不是您的 LaTeX 发行版的一部分,因此需要将其安装在您的计算机上,或者您需要打开一个免费的Cocalc 账户。免费帐户是启动和运行的最简单方法。
按下Build
Cocalc 中的按钮后,编译过程分为三个步骤:首先运行 LaTeX。其次,SAGE 运行其所需的内容。第三,LaTeX 运行由 LaTeX 和 SAGE 内容组成的最终产品。为了顺利完成编译,我发现最简单的方法是用 Python 创建一个原始字符串,它将进行任何所需的计算(例如图中的坐标)并创建将在 LaTeX 中运行的文本。模板 2:本网站的许多帖子都使用了需要 SAGE 的二维绘图;例如:如何在 Latex 中绘制 Gamma 函数的倒数。请注意,我使用 导入了该函数,from sage.functions.other import gamma1
并以两种方式使用它。首先将其绘制为,sageplot
向您显示由 SAGE 创建的图。第二个图显示了将坐标推送到 pgfplots 以获得显示的第二个图时的结果。它类似于第一个模板,只是现在我将代码放入字符串中,以便 SAGE 可以进行排版。由于我的轴环境说output += r"grid = none,"
不会有方格纸。在帖子中在 Tikz 中隐式绘图您将看到用于隐式绘图的相同基本模板。请注意,方格纸背景来自output += r"grid = both,"
。除了这两个用于绘制二维的模板外,还有模板3:对于需要 SAGE 的 3d 图Tikz 绘制 3D。一旦您熟悉了该过程,您可以轻松地使用 SAGE 作为其他图的引擎,而无需使用讨论的模板。例如帖子
- 使用 pgfplots 绘制傅里叶展开使用 SAGE 的傅里叶级数知识加上不同的情节设置。
- 如何在 Tikz 中绘制勒贝格奇异函数?在创建函数时更多地使用 Python 编程。
- 绘制极点位于 (0,0) 处的函数 ℝ² →ℝ 的平滑图形 展示 SAGE 如何使用您想要的特定点进行绘图。
- 绘制龙曲线 提到如何增加缓冲:您可以将编译更改为类似于的内容
buf_size=1000000 pdflatex -synctex=1 -interact=nonstopmode MyFile.tex
。 - 不使用 gnuplot 绘制任意 R^3 函数的轮廓图展示如何在文档中嵌入 matplotlib 图。
- 给定一个素数列表,如何绘制 π(x)?使用内置的素函数来绘制序列。
- Tikz 上的黎曼积分使用命令展示如何创建一个生成左、右黎曼积分的 Python 函数。
- 如何自动要求 tikz 生成坐标并根据邻接矩阵绘制图形从邻接矩阵创建顶点和边类型图。
- 获取非均匀分布的随机 0 和 1 抽取表说明如何处理 numpy 数组以创建由随机创建的 1 和 0 组成的数组。
- 椭圆曲线的射影图展示 SAGE 3d 图形。
- 如何在 TikZ 中绘制包含上限的函数?展示如何绘制具有众多不连续点的函数。
总之,您可以使用该sagetex
包以及三个模板来创建具有相同外观和感觉的 2d/3d 图,无论它们有多复杂。使用 Python 可以使代码更易于阅读和修改,甚至可以让您强制绘制特定点。您可以轻松增加缓冲区的大小以处理更多数据。SAGE 可以处理微分和积分。如果您愿意,您还可以使用 matplotlib 和 SAGE 图。您还可以搜索此网站上发布的其他示例。
什么是最佳实践?我不知道是否有一个让所有人都满意的答案。不过,这个sagetex
包可以处理你提到的问题。
答案2
我遇到了类似的问题。我所做的是“外部化”图的生成。您可以通过包括
\usepgfplotslibrary{external}
\tikzexternalize
在您的序言中。您必须使用附加选项 -shell-escape 调用 Latex。这将导致编译器为每个 tikz 图片从头开始,因此您的编译将不再累积内存消耗。每张图片将有一个单独的文件,它们也将很好地组合成一个文档。
话虽如此,1M 个点还是太多了。坦率地说,我认为没有必要绘制出高质量的图。无论如何,你都应该减少它。尝试使用点数(反正 Python 中就有,所以应该不难。)我尝试通过反复试验来找到极限。你可能希望在单独的文档中创建和调试图片,以便获取错误日志。
答案3
这里我提出了一个绘制正弦和余弦函数的例子,其中我展示了(带有注释)方格纸、网格、刻度、特定点等的方法:
\documentclass{standalone}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}[>=latex,scale=1.5]
% first option for a grid like a millimetral grahic paper (next 3 lines)
\draw[thin,brown!25] (-.5,-1.5) grid[step= 1mm] ++ (7.5,3);
\draw[semithick,brown!50] (-.5,-1.5) grid[step= 5mm] ++ (7.5,3);
\draw[ thick,brown!75] (-.5,-1.5) grid[step=10mm] ++ (7.5,3);
% second option for a grid in dotted gray in next line (uncomment the next line but comment the preceding 3 lines)
%\draw[dotted] (-0,-1) grid (6.5,1);
% x axis and its label
\draw[->] (-.5,0) -- (6.5,0) node[right] {$x$};
% x axis graduations in integers
\foreach \x in {1,2,...,6}
\fill[shift={(\x,0)}] circle(.5pt) node[above] {\tiny $\x$};
% x axis graduations in \pi
\foreach \x /\n in {.7854/$\frac{\pi}{4}$,1.5708/$\frac{\pi}{2}$,2.3562/$\frac34\pi$,3.1416/$\pi$,3.9270/$\frac54\pi$,4.7124/$\frac32\pi$,5.4978/$\frac74\pi$,6.2832/$2\pi$} \draw[shift={(\x,0)}] (0pt,2pt) -- (0pt,-2pt) node[below] {\tiny \n};
% y axis, its label and graduations
\draw[->] (0,-1.5) -- (0,1.5) node[below right] {$y$};
\foreach \y in {-1,1}
\draw[shift={(0,\y)}] (2pt,0pt) -- (-2pt,0pt) node[left] {\tiny $\y$};
\node[below left] at (0,0) {\tiny $0$};
% draw functions
\draw[smooth,blue,mark=none,domain=0:6.283,line width=1.5pt] plot (\x,{sin(deg(\x))});
\draw[smooth,magenta,mark=none,domain=-0:6.283,line width=1.5pt] plot (\x,{cos(deg(\x))});
% draw the functions names
\draw[] (2,-1) node[magenta,below](1) {$y=\cos x$};
\draw[] (2,1) node[blue,above](1) {$y=\sin x$};
% plot the intersections points A and B
\fill[black,shift={(3.9270,-.707)}] circle(1.5pt) node[below] {\tiny B};
\fill[black,shift={(.7854,.707)}] circle(1.5pt) node[above] {\tiny A};
% draw the exact coordinates of A and B
\draw[] (5,-.95) node[below] (3) {\tiny A$\left(\frac{\pi}{4},\frac{\sqrt2}{2}\right)$ \quad \tiny B$\left(\frac{5}{4}\pi,-\frac{\sqrt2}{2}\right)$};
\end{tikzpicture}
\end{document}
结果如下: