【转帖·翻译】在LaTeX中制作亲属关系图

引子

有一天,那时我还没有毕业,在办公室里用LaTeX写论文。那边厢,向柏霖也在LaTeX上工作,突然,他把他的学生(包括我)都召唤过来,展示他忙了一上午的成果。是用PGF/Tikz制作的茶堡话亲属关系图!如下图,是不是很厉害?

于是,沾沾自喜的向先生群发了一封邮件,把这庞大的工程广而告之了。

没想到,这一举动惊动了LaTeX之神,Thomas Pellard。他专门研究琉球的语言,也在Inalco开设了LaTeX的课程。他看到这张亲属关系图,居然甚是不满意。果然是内行看门道,他觉得有必要大动手术。于是他三下五除二就整了一个新的技惊四座的漂亮亲属关系图,如下:

是不是美轮美奂得罄竹难书?然后,Thomas在自己的部落格(点击看原文)上把代码公开了。我们征得他的同意,把法文原文翻译成了中文,供大家学习和膜拜。

用LaTeX制作亲属关系图

Thomas Pellard

我的同事以及朋友向柏霖问我有关用LaTeX制作亲属关系图的建议。亲属关系图是人类学中用来描述亲属系统的常用工具。不同的文化和语言中,亲属关系并不遵循相同的概念和称谓。比如说,在琉球的语言中,弟弟和妹妹共用同一个称谓,完全不作性别划分。同样地,有许多十分不同的亲属系统,对于我们来说,可能十分“怪异”。反过来说,法语不区分(内外)祖父母、叔伯、姑姨的系统对于某些文化来说可能也是尤其奇怪的。

用LaTeX来制作亲属关系图,似乎不存在“一站式”的解决方案。最接近的可能是genealogytree,但它并不能解决亲属关系图中的特殊性。另外,它的说明书有292页,我们可以预见自定义命令的难度。在等待有人能开发出针对亲属关系图的插件的同时,我们必须使用LaTeX一般用来画图的工具。

最好以及最常用的工具之一就是PGF/Tikz。这是一个非常全面、记载得相当好的工具(3.0.1a版有1161页的说明书),可以用来制作非常复杂的图(参见http://www.texample.net/tikz/examples/all/中的例子)。

我们可以用 Tikz tree来做亲属关系图,它可以生成树形图。然后,我们可以加上新的命令,用以表示婚姻关系,并加上兄弟姐妹以及男女性的符号。当然, 我们也可以使用Tikz的标准命令添加装饰。

这就是成图,展示了向柏霖研究的茶堡话亲属关系图(初步版本,加上了我自己的标记以显示不同的命令):

这是整篇代码,并含解释不同命令的注释:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
\documentclass[11pt,border=2pt]{standalone}
\usepackage{polyglossia}
\setmainfont[StylisticSet=20]{Brill}
\usepackage{tikz}
\usetikzlibrary{trees,calc,shapes.geometric,arrows.meta
}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 树形图的第一个节点 \treeroot[#1]{#2}{#3}
% #1 性别符号的选项
% #2 节点名称
% #3 节点文本
\newcommand{\treeroot}[3][]{
\node (#2) {#3} ;
\draw[#1
] ($(#2.north) +(0,.5em)$) -- (#2.north);
}

% 加上兄弟或姐妹 \sibling[#1]{#2}{#3}{#4}{#5}
% #1 性别符号的选项
% #2 节点名称
% #3 节点位置
% #4 兄弟姐妹的称谓
% #5 节点文本
\newcommand{\sibling}[5][]{
\node (#2) #3 {#5};
\draw[#1
] ($(#4.north) +(0,.5em)$) -- +(0pt,.4\tikzleveldistance -.5em) -| (#2.north);
}

% 在节点的左边添加配偶:\spouseleft[#1]{#2}{#3}{#4}
% #1 性别符号的选项
% #2 节点名称
% #3 预设的配偶称谓
% #4 节点文本
\newcommand{\spouseleft}[4][]{\node[anchor=base east,xshift=-.5em] (#2) at(#3.base west) {#4} ;
\draw[#1] ($(#2.north) +(0,.5em)$) -- (#2.north);
\draw[] ([yshift=.2ex]#2.mid east) -- ([yshift=.2ex]#3.mid west) ;
\draw[] ([yshift=-.2ex]#2.mid east) -- ([yshift=-.2ex]#3.mid west) ;
}

% 在节点的右边添加配偶 \spouseright[#1]{#2}{#3}{#4}
% #1 性别符号的选项
% #2 节点名称
% #3 预设的配偶称谓
% #4 节点文本
\newcommand{\spouseright}[4][]{\node[anchor=base west,xshift=.5em] (#2) at(#3.base east) {#4} ;
\draw[#1] ($(#2.north) +(0,.5em)$) -- (#2.north);
\draw[] ([yshift=.2ex]#3.mid east) -- ([yshift=.2ex]#2.mid west) ;
\draw[] ([yshift=-.2ex]#3.mid east) -- ([yshift=-.2ex]#2.mid west) ;
}

% 在已有夫妻下添加子女 \unionchild[#1]{#2}{#3}
% #1 图中左边的父母
% #2 图中右边的父母
% #3 一般的节点内容: child {node {NOM}}, 等
\newcommand{\unionchild}[3]{\node at($(#1.base east)!0.5!(#2.base west)$) {} #3 ;}

% 一般分支的体例设定
\tikzstyle{edge from parent fork down}= [edge from parent path={(\tikzparentnode\tikzparentanchor) -- +(0pt,-.4\tikzleveldistance) -| (\tikzchildnode\tikzchildanchor)}]

\tikzset{
% 缺省体例
edge from parent fork down, sibling distance=3em, level distance=10ex,
every node/.style={anchor=base,inner sep=2pt,outer sep=0pt,minimum width=1em,text height=2ex,text depth=.5ex,font=\strut},
% 女性符号的体例:“fem”
set fem/.code={\pgfqkeys{/tikz/fem}{#1}}, set fem={fill/.initial=white, color/.initial=black},
fem/.style={set fem={#1},-{Circle[open,length=.5em,color=\pgfkeysvalueof{/tikz/fem/color},fill=\pgfkeysvalueof{/tikz/fem/fill}]}
},
% 男性符号的体例:“masc”
set masc/.code={\pgfqkeys{/tikz/masc}{#1}}, set masc={fill/.initial=white, color/.initial=black},
masc/.style={set masc={#1},-{Triangle[open,reversed,width=.75em,length=.5em,color=\pgfkeysvalueof{/tikz/masc/color},fill=\pgfkeysvalueof{/tikz/masc/fill}]}
},
% 不确定性别符号的体例:“fm”
set fm/.code={\pgfqkeys{/tikz/fm}{#1}}, set fm={fill/.initial=white, color/.initial=black},
fm/.style={set fm={#1},-{Square[open,length=.5em,color=\pgfkeysvalueof{/tikz/fm/color},fill=\pgfkeysvalueof{/tikz/fm/fill}]}
},
% 添加表示年龄大小的“+”“-”号
older/.style={label={[label distance=-.5ex]85:+}},
younger/.style={label={[label distance=-.5ex]85:-}}
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begin{document}
\begin{tikzpicture}

\treeroot[masc]{wa}{tɤ-wa}
\spouseright[fem]{mu}{wa}{tɤ-mu}
\unionchild{wa}{mu}{
child[fem] {node (snom) {tɤ-snom}}
child[masc] {node[older] (ego) {\textsc{ego}}}
child[masc,sibling distance=7em] {node[younger] (xtg) {tɤ-xtɤɣ}}
}

\spouseright[fem]{rzab}{ego}{tɤ-rʑaβ}
\unionchild{ego}{rzab}{child[masc] {node{tɤ-tɕɯ}} child[fem] {node {tɯ-me}} }

\spouseleft[masc]{piri}{snom}{tɤ-pi⁺ ta-ʁi⁻}
\unionchild{piri}{snom}{child[fm] {node(ftsa) {tɤ-ftsa}} }

\spouseright[fem]{piri2}{xtg}{tɤ-pi⁺ ta-ʁi⁻}
\unionchild{xtg}{piri2}{child[fm] {node {tɤ-mdɯ}} }

\sibling[masc]{rpu}{at([xshift=3.5em]mu.base west -| piri2.base east)}{mu}{tɤ-rpɯ}
\spouseright[fem]{lar}{rpu}{tɤ-ɬaʁ}
\unionchild{rpu}{lar}{
child[masc={fill=black}] {node (rpu2) {tɤ-rpɯ}
child[masc={fill=black}] {node (rpu3) {tɤ-rpɯ}}
child[fem={fill=black}] {node {tɤ-ɬaʁ}}
}
child[fem={fill=black}] {node {tɤ-ɬaʁ}}
}

\sibling[fem]{nyi}{at([xshift=-1em]wa.base east -| piri.base west)}{wa}{tɤ-ɲi}
\spouseleft[masc]{bgo}{nyi}{tɤ-βɣo}
\unionchild{bgo}{nyi}{
child[fm={fill=orange}] {node(ftsa2) {tɤ-ftsa}
child[fm={fill=orange}] {node{tɤ-ɣe}}
}
}

\draw (ftsa.mid west) to[bend left] (ftsa2.base east);
\draw (rpu.mid west) to[bend right] (rpu2.mid west) ;
\draw (rpu.mid west) to[bend right] (rpu3.mid west) ;
\end{tikzpicture}
\end{document
}

Author: Lai, Yunfan

目前是马克斯普朗克协会人类历史科学研究所(Max-Planck Institut für Menschheitsgeschichte)的博士后。

评论