撰写科学论文的技巧和窍门

目录

排版你的论文

排版是通过排列字体(例如字母和符号)来编写文本的过程。这主要关乎美观,但精美的字体设计能让文档更易于阅读,更赏心悦目,帮助读者更好地理解信息。

我们列出了一些排版技巧和工具,可以更好帮助您撰写文档。其中一些技巧仅适用于 LaTeX,但其他技巧则适用于任何语言。

每行一个句子

编写 LaTeX 文档时,请在源文件中每行只放一个句子。例如:

This is my first sentence.
This is the second one.
而不是:
This is my first sentence. This is the second one.

这样做的主要原因是为了更好的对源代码控制和协作:查看提交的更改时,每个句子都单独放在一行,就能更容易地识别哪些句子被更改了。这样,你的同事就能更容易地看到更改。

另一个好处是,当我们的 LaTeX 编译器仅给出行号时,您将能够更快速地识别错误。

大写

下面我们将提到两种大写类型:

  • 句子格式:好书的标题
  • 标题格式:好书的标题

所有章节、小节等标题都应使用标题格式。为了帮助您正确使用大写字母,有一个方便的网站: capitalizemytitle.com。

保持参考文献完整

有时,对象(例如图形、表格、图表或算法)的名称及其参考编号会分成两行。例如,对象名称可能在一行,而参考编号则出现在下一行。

为了确保 LaTeX 将对象名称及其引用保持在同一行,您可以在对象和引用之间使用~字符。通过~这种方式使用波浪号,您可以避免不雅的换行,并在 LaTeX 文档中保持对象名称和引用编号的格式一致。

Figure~\ref{fig:example} displays that the project ...

为了保证不会忘记使用波浪号,您可以通过创建自定义命令来简化自动化流程。以下是示例:

\newcommand{\refalg}[1]{Algorithm~\ref{#1}}
\newcommand{\refapp}[1]{Appendix~\ref{#1}}
\newcommand{\refchap}[1]{Chapter~\ref{#1}}
\newcommand{\refeq}[1]{Equation~\ref{#1}}
\newcommand{\reffig}[1]{Figure~\ref{#1}}
\newcommand{\refsec}[1]{Section~\ref{#1}}
\newcommand{\reftab}[1]{Table~\ref{#1}}

一旦定义了这些命令,就无需再写:

Figure~\ref{fig:example}

只需输入:

\reffig{fig:example}

表格

(完整示例)

booktabs 可以帮助您制作干净、美观的表格。

\usepackage{booktabs}
% --
\begin{table}
    \centering
    \begin{tabular}{lcc}
        \toprule
        & \multicolumn{2}{c}{Data} \\ \cmidrule(lr){2-3}
        Name & Column 1 & Another column \\
        \midrule
        Some data & 10 & 95 \\
        Other data & 30 & 49 \\
        \addlinespace
        Different stuff & 99 & 12 \\
        \bottomrule
    \end{tabular}
    \caption{My caption.}
    \label{tab-label}
\end{table}

Booktabs example

一般来说,避免在表格中使用垂直线。如果要对列进行分组,请在标题中使用\cmidrule 进行分组。您也可以使用 \addlinespace 用空格代替水平线。

列标题应使用句子格式大写(请参阅 https://www.chicagomanualofstyle.org/qanda/data/faq/topics/Capitalization.html )。

您可以在这里找到更多关于表格格式的建议: http://www.inf.ethz.ch/personal/markusp/teaching/guides/guide-tables.pdf 。 这里有一份表格示例,演示了其中一些规则:paper-tips-and-tricks 表格示例。

数字格式

(完整示例)

使用 siunitx 包格式化所有数字、货币、单位等:

\usepackage{siunitx}
% ---
This thing costs \SI{123456}{\$}.
There are \num{987654} people in this room, \SI{38}{\percent} of which are male.

Siunitx formatting

您还可以使用它来对数字进行舍入:

\usepackage{siunitx}
% ---
\sisetup{
    round-mode = places,
    round-precision = 3
}%
You can also round numbers, for example \num{1.23456}.
Siunitx formatting

最后,它可以帮助您更好地对齐表格中的数字:

\usepackage{booktabs}
\usepackage{siunitx}
%---
\begin{table}
    \centering
    \begin{tabular}{lS}
        \toprule
        Name & {Value} \\ % headers of S columns have to be in {}
        \midrule
        Test & 2.3456 \\
        Blah & 34.2345 \\
        Foo & -6.7835 \\
        Bar & 5642.5 \\
        \bottomrule
    \end{tabular}
    \caption{Numbers alignment with \texttt{siunitx}.}
\end{table}
Siunitx formatting

数学符号

(完整示例)

在写方程式时,以连贯一致的方式书写变量、向量、矩阵等会很有帮助。它可以帮助读者识别你在说什么,并记住每个符号的语义。

符号

我们提出以下数学书写规则:

  • 变量用小写斜体表示: x ($x$)
  • 向量用小写斜体粗体表示: x ($\mathbold{x}$)
  • 矩阵用大写斜体粗体表示: X ($\mathbold{X}$)
  • 大写斜体表示随机变量: X ($X$)

该\mathbold命令来自fixmath包,类似于\boldmath或\bm,不同之处在于所有符号都是斜体,甚至希腊字母也是如此(其他包不会将希腊字母斜体化)。

向变量添加索引或指数时,请确保将它们添加到变量的样式之外,即写为$\mathbold{x}_i$而不是$\mathbold{x_i}$。

定义自定义命令

因为我们经常引用变量,所以建议定义以下两个命令:

\renewcommand{\vec}[1]{\mathbold{#1}}
\newcommand{\mat}[1]{\mathbold{#1}}

然后,您就可以在文档中使用$\vec{x}$和 $\mat{X}$ 了。如果您决定更改矩阵的格式,只需更改\mat命令即可,它将更新整个文档。

我们还建议为最常用的变量定义命令。例如,如果您经常使用\vec{x}和\mat{X},可以考虑定义以下命令:

\newcommand{\vx}{\vec{x}}
\newcommand{\vX}{\mat{X}}

然后您可以写出更紧凑的方程: $\vx^T \vy = \vZ$。

对列和元素使用正确的符号

请注意,应始终根据变量的类型来设置其样式。例如,向量的第 $i$ 个元素\vx是x_i,而非\vx_i(它是一个数字)。类似地,如果有一个矩阵\vX,则可以将其第 i 列称为\vx_i(它是一个向量,因此以粗体显示),如果其元素x_{ij},而非 \vX_i且\vX_{ij},则可以将其第 i 列称为\vx_i。

环境

用于\(...\)编写内联方程式。您也可以使用$...$,但它是一个 TeX 命令,并且会给出更隐晦的错误信息。

要使公式居中并排,请勿使用(这是LaTeX 的致命错误$$...$$之一)。虽然可以使用,但间距不正确。请使用\begin{equation*}或\begin{align*}。

参考书目

反向引用

(完整示例)

对于较长的文档,例如学士、硕士或博士论文,在参考书目中添加参考文献以显示参考文献的引用位置会很有用。为此,只需在hyperref包中添加backref=page选项:

\usepackage[backref=page]{hyperref}

您可以使用以下命令自定义反向引用的显示方式:

\renewcommand*{\backref}[1]{}
\renewcommand*{\backrefalt}[4]{{\footnotesize [%
    \ifcase #1 Not cited.%
    \or Cited on page~#2%
    \else Cited on pages #2%
    \fi%
]}}

Backref custom appearance

创建图形

图表是任何论文的重要组成部分,因为它们可以向读者传达你的研究结果。你应该思考每幅图上的信息究竟能传达给读者什么,并确保信息量刚好足以支撑你的信息,不要过多。例如,如果你想展示二维点的模式(有两个分离良好的簇),就没有必要在坐标轴上标注刻度和数值(比例尺其实并不重要)?图表不应该过于复杂。用几幅图来传达一两条信息(方法A优于方法B,但收敛速度较慢)比用一张又大又乱的图表要好。

每个数据驱动的图形对应一个脚本

有些图形是手工制作的,例如用于解释系统或提供全局视图;而另一些图形则是数据驱动的,即用于说明一些数据。这些数据驱动的图形应尽可能脚本化:理想情况下,如果数据发生变化,只需运行一次脚本即可更新图形,而无需任何其他干预(设置视图、缩放、保存/裁剪图形等)。同样,如果生成图形所需的数据需要几秒钟以上的时间,则应该使用第一个脚本来计算和保存数据,并使用第二个脚本来绘制数据。这样,您将在绘图时节省大量时间:您不必在对图形进行每次微小更改后等待才能看到其效果。

我们还建议将用于生成图形的命令保存在 LaTeX 文件中,例如作为图形上方的注释,特别是当脚本需要参数时。

\documentclass{article}

\usepackage{graphicx}

\begin{document}

% python figure_example.py --save ../../examples/figure/figure.eps
\begin{figure}
    \centering
    \includegraphics{figure.eps}
    \caption{Example of a sigmoid function}
\end{figure}

\end{document}

Python 帮助脚本

如果可能,所有图形的标签、坐标轴等都应使用相同的字体。尤其要注意,不要让一个图形的标签/刻度较大,而另一个图形的标签/刻度较小。一个解决方案是在生成图形的脚本中定义图形的大小,而不是在文档中重新缩放(例如,不要在 LaTeX 文档中更改图形的宽度设置\textwidth)。

为了获得一致的图形,我们建议使用类似于我们的辅助脚本plot_utils.py。使用此脚本,您只需调用figure_setup()函数定义所有尺寸,然后创建所需尺寸的图形并保存即可。

import argparse
import matplotlib.pyplot as plt
import numpy as np
import plot_utils as pu


def main(args):
    x = np.linspace(-6, 6, 200)
    y = 1/(1 + np.exp(-x))

    pu.figure_setup()

    fig_size = pu.get_fig_size(10, 5)
    fig = plt.figure(figsize=fig_size)
    ax = fig.add_subplot(111)

    ax.plot(x, y, c='b', lw=pu.plot_lw())

    ax.set_xlabel('$x$')
    ax.set_ylabel('$\\sigma(x)$')

    ax.set_axisbelow(True)

    plt.grid()
    plt.tight_layout()

    if args.save:
        pu.save_fig(fig, args.save)
    else:
        plt.show()


if __name__ == '__main__':
    parser = argparse.ArgumentParser()

    parser.add_argument('-s', '--save')

    args = parser.parse_args()
    main(args)

图形格式

图片格式应与论文的编译方式和图片内容相配合,不能统一要求所有图都保存为 EPS:

使用场景 常用格式 选择时注意
使用 pdfLaTeX、XeLaTeX 或 LuaLaTeX 插入曲线图、流程图 PDF 保留矢量线条和文字,缩放后检查字体与符号是否完整
使用传统 LaTeX → DVI → PostScript 流程 EPS 按该流程或投稿模板的说明使用;pdfLaTeX 使用 EPS 通常还需要转换
照片、软件截图等位图 PNG 或 JPEG 按最终插入尺寸检查清晰度;提高导出分辨率不会补回原图丢失的细节

Matplotlib 可直接导出 PDF 和 PNG。下面的例子从同一幅图保存两个文件,文件扩展名决定导出格式:

import matplotlib.pyplot as plt

fig, ax = plt.subplots(figsize=(4, 3))
ax.plot([0, 1, 2], [0, 1, 4])
ax.set_xlabel("x")
ax.set_ylabel("y")
fig.savefig("curve.pdf", bbox_inches="tight")
fig.savefig("curve.png", dpi=300, bbox_inches="tight")
plt.close(fig)

保存后,把图片插入实际论文模板,检查最终 PDF 中的文字、边距和线条。投稿方指定格式时,以投稿说明为准。具体选项见 Matplotlib 保存图片说明,LaTeX 图片格式可参考 Overleaf 图片插入说明。

保留绘图数据,方便复查同一张图

只保留图片,后续修改坐标轴或图例时可能找不回当时的数据。建议将绘图脚本和实际使用的数据一起保存;如果示例含随机数,同时固定随机种子。下面的例子第一次运行时保存数据,此后直接读取同一份 CSV,再导出 PDF 和 PNG:

from pathlib import Path

import matplotlib.pyplot as plt
import numpy as np

output = Path("figures")
output.mkdir(exist_ok=True)
data_file = output / "line_points.csv"

if not data_file.exists():
    rng = np.random.default_rng(42)
    x = np.linspace(0, 1, 40)
    y = 2 * x + rng.normal(0, 0.08, x.size)
    np.savetxt(data_file, np.column_stack((x, y)), delimiter=",",
               header="x,y", comments="")

x, y = np.loadtxt(data_file, delimiter=",", skiprows=1, unpack=True)
fig, ax = plt.subplots(figsize=(8 / 2.54, 6 / 2.54), layout="constrained")
ax.plot(x, y, marker="o", markersize=3, linewidth=1, label="samples")
ax.set(xlabel="x", ylabel="y")
ax.legend()
fig.savefig(output / "line.pdf")
fig.savefig(output / "line.png", dpi=300)
plt.close(fig)

固定绘图数据后导出的折线图,包含 40 个采样点

上图是示例数据对应的 PNG 输出,用于对照点的位置、坐标范围和图例是否一致。它展示的是随机示例数据,不代表实际实验结果。

此处图幅为宽 8 cm、高 6 cm;Matplotlib 的 figsize 使用英寸,因此要除以 2.54。没有使用 bbox_inches="tight",以保留指定的整体画布尺寸。将图片插入正文后,仍需按实际显示宽度检查字号与图例。

复查时连续运行两次,确认 line_points.csv 内容未变,两种格式中的点和曲线一致。修改真实实验数据时应另存一份有明确含义的数据文件,并修改脚本的读取路径,避免把旧数据误当作新结果。固定种子用于重复生成示例数据,不能保证不同 NumPy 或 Matplotlib 版本导出的图片文件逐字节相同;需要长期复查时,同时记录这些依赖的版本。

参考 NumPy:随机数生成器和 Matplotlib:图幅尺寸。

将图形的部分栅格化

如果绘图中包含大量数据点,生成的 EPS 文件可能会非常大。您可以将图形保存为 PNG 文件,但这会导致文本模糊。解决方案是将图形的部分内容栅格化,即告诉 matplotlib 数据点必须在 EPS 文件中渲染为位图,其余部分则渲染为矢量格式。

您可以将 rasterized=True 关键字传递给 matplotlib 中的大多数绘图函数。您还可以使用 zorder 来设置不同的图层,并使用轴的 set_rasterization_zorder() 方法告诉 matplotlib 对给定 zorder 以下的所有图层进行栅格化。有关栅格化的示例,请参阅 figure_rasterized_example.py 和 http://matplotlib.org/examples/misc/rasterization_demo.html。

其他检查

内容

  • 相关工作不是对现有论文的罗列,而是做评述,最后还需要引出自己的工作

形式

  • 所有图片尽量用矢量图,生成PDF后保证能够用鼠标选中里面的文字,放大后不会失真
  • 图中的字体要注意,需要按照模板要求
  • 如果文章只出现一次,又不是非常通用的缩写,可以不用缩写。并且只在第一次出现的时候声明缩写
  • 所有文中的符号都是公式符号,而不是英文
  • latex 编译生成中间文件( .aux, .log等)和输出pdf文件不用放到仓库
  • 一次性不要提交太多文件,不好审核,提交前检查下,比如大的二进制文件可以提供一个下载链接
  • 缓存、不必要的输出文件不要放到仓库,比如:__pycache__不需要的缓存文件、训练的模型、中间记录文件、.pyc文件、checkpoint文件、.pth文件最多放一个、.npy文件等

其他

有用的资源

补充提示:插图导出后请检查文字、线条和图例是否清晰,再放入论文正文。

导出后可先打开 PDF 检查文字是否清晰、图例是否完整,再查看 PNG 在最终版心宽度下的显示效果。若图片来自脚本,建议同时保留脚本和导出的文件名,后续修改数据时更容易重新生成同一张图。

插图放入正文后的检查

  • 按正文中的实际宽度查看图片,确认坐标刻度、图例和注释能直接读清,不只检查放大后的效果。
  • 导出整篇 PDF 后重新检查图像边缘,确认标题、单位和图例没有被裁切,图号与正文引用相符。
  • 涉及多条曲线时,检查线型、标记和颜色是否容易区分;打印成灰度后也应能对应到图例。