是的,我们正在谈论 TeX 和朋友们!
编辑:我决定将背景动机移到问题的末尾,因为它在 TeX 上下文中似乎有点离题。
以下代码只是初步想法。我的计划是将一本笔记本藏在西斯廷教堂内,打开电子表格应用程序并开始计算新教皇选举的选票。
以下名单列出了 115 名新教皇候选人的名字。整个过程的数据都是根据投票结果手工制表的,每位枢机主教都用自己的方式进行注释投票审查每位候选人的得票数。选举结果仍以纸笔记录。
现在,只需导出数据.csv
并使用 Nicola Talbot 的出色datatool
软件包即可为红雀生成一份漂亮的报告!但等一下,我们仍然需要保持传统,墨水和笔。
感谢我的好友 percusse,现在是 TikZ 时间!让我们伪造一些手写注释来投票!这里的想法非常简单:获取投票数,生成一张 TikZ 图片,以直观的方式表示当前数字并呈现它。
首先,这是cardinals.csv
:
Surname,Name,Votes
Kasper,Walter,0
Poletto,Severino,0
Sandoval Íñiguez,Juan,0
Danneels,Godfried,0
Errázuriz ossa,Francisco Javier,0
Farina,Raffaele,0
Agnelo,Geraldo Majella,7
Meisner,Joachim,0
Vela Chiriboga,Raúl Eduardo,0
Re,Giovanni Battista,0
Tettamanzi,Dionigi,0
Monterisi,Francesco,0
Hummes,Cláudio,15
Amigo Vallejo,Carlos,0
Sardi,Paolo,0
Cordes,Paul Josef,0
Rodé,Franc,0
Bertone,Tarcisio,11
Pham Minh Mân,Jean-Baptiste,0
Lajolo,Giovanni,0
Naguib,Antonios,0
Rigali,Justin Francis,0
De Paolis,Velasio,0
Abril y Castelló,Santos,0
da Cruz Policarpo,José ,0
Mahony,Roger Michael,0
Terrazas Sandoval,Julio,0
Dias,Ivan,0
Lehmann,Karl,0
Levada,William Joseph,0
Okogie,Anthony Olubunmi,0
Turcotte,Jean-Claude,0
Rouco Varela,Antonio María,0
Ortega y Alamino,Jaime Lucas,0
López Rodrígues,Nicolás de Jesús,0
Antonelli,Ennio,0
Sarr,Théodore-Adrien,0
Bergoglio,Jorge Mario,0
George,Francis Eugene,0
Bačkis,Audrys Juozas,0
Damasceno Assis,Raymundo,7
Nicora,Attilio,0
Martínez Sistach,Lluís,0
Vegliò,Antonio Maria,0
Romeo,Paolo,0
Coccopalmerio,Francesco,0
Monteiro de Castro,Manuel,0
Caffarra,Carlo,0
Amato,Angelo,0
O'Brien,Edwin Frederik,0
Dziwisz,Stanisław,29
Tong Hon,John,0
Brady,Seán Baptist,0
Monsengwo,Pasinya Laurent,0
Grocholewsky,Zenon,0
Toppo,Telesphore Placidus,0
Raï,Béchara Boutros,0
Vallini,Agostino,0
Wuerl,Donald William,0
Zubeir Wako,Gabriel,0
Napier,Wilfrid Fox,0
Pell,George,0
Scola,Angelo,0
Rivera Carrera,Norberto,0
Urosa Savino,Jorge Liberato,0
Salazar Gómez,Rubén,0
Bertello,Giuseppe,0
Ravasi,Gianfranco,0
Vingt-Trois,André,0
Rodríguez Maradiaga,Óscar Andrés,0
Bagnasco,Angelo,0
Calcagno,Domenico,0
Duka,Dominik,0
Sepe,Crescenzio,0
Tauran,Jean-Louis,0
Versaldi,Giuseppe,0
Comastri,Angelo,0
Sandri,Leonardo,0
Cipriani Thorne,Juan Luis,0
Onaiyekan,John Olorunfemi,0
Ouellet,Marc,0
O’Malley,Sean Patrick,0
Pengo,Polycarp,0
Piacenza,Mauro,0
Ricard,Jean-Pierre,0
Gracias,Oswald,0
Njue,John,0
Schönborn,Christoph,0
Alencherry,George,0
Sarah,Robert,0
Ryłko,Stanisław,0
Puljić,Vinko,0
Cañizares Llovera,Antonio,0
Filoni,Fernando,0
Collins,Thomas Christopher,0
Betori,Giuseppe,0
Braz de Avis,João,21
Patabendige Don,Albert Malcolm Ranjith,0
Burke,Raymond Leo,0
Turkson,Peter Kodwo Appiah,0
Robles Ortega,Francisco,0
Bozanić,Josip,0
DiNardo,Daniel Nicholas,0
Scherer,Odilo Pedro,37
Harvey,James Michael,0
Nycz,Kazimierz,0
Dolan,Timothy Michael,2
Koch,Kurt,0
Barbarin,Philippe,0
Erdő,Péter,0
Eijk,Willem Jacobus,0
Marx,Reinhard,0
Woelki,Rainer Maria,0
Tagle,Luis Antonio,0
Thottunkal,Baselios Cleemis,0
现在,我们亲爱的vota.tex
:
\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[top=1.5cm, bottom=1.5cm, left=1.5cm, right=1.5cm, landscape]{geometry}
\usepackage{lmodern}
\usepackage{datatool}
\usepackage{multicol}
\usepackage{xspace}
\usepackage{tikz}
\usetikzlibrary{calc,decorations}
\makeatletter
\pgfdeclaredecoration{penciline}{initial}{
\state{initial}[width=+\pgfdecoratedinputsegmentremainingdistance,auto corner on length=1mm,]{\pgfpathcurveto{%
\pgfqpoint{\pgfdecoratedinputsegmentremainingdistance}{\pgfdecorationsegmentamplitude}}{\pgfmathrand\pgfpointadd{%
\pgfqpoint{\pgfdecoratedinputsegmentremainingdistance}{0pt}}{\pgfqpoint{-\pgfdecorationsegmentaspect\pgfdecoratedinputsegmentremainingdistance}
{\pgfmathresult\pgfdecorationsegmentamplitude}}}{\pgfpointadd{\pgfpointdecoratedinputsegmentlast}{\pgfpoint{1pt}{1pt}}}}\state{final}{}}
\tikzset{
prison/.style={
append after command={
\pgfextra{\ifnum#1=0\else
\foreach \x in {0,...,\number\numexpr#1-1\relax}{
\coordinate (mytemp) at ($(\tikzlastnode.north west)!0.3333*\x!(\tikzlastnode.north east)$);
\draw[decorate] (mytemp) -- (mytemp|-\tikzlastnode.south);}\fi
}
}
},
fived/.style={append after command={
\pgfextra{
\draw[decorate] ([shift={(-2mm,1mm)}]\tikzlastnode.south west)--([shift={(2mm,-1mm)}]\tikzlastnode.north east);}
}
}
}
\makeatother
\newcommand{\drawvotes}[1]{%
\begin{tikzpicture}[decoration=penciline]
\def\numofscr{#1}
\pgfmathtruncatemacro\residue{Mod(\numofscr,5)}
\pgfmathtruncatemacro\numoflots{\numofscr/5}
\ifnum\numofscr<5\else
\foreach \x in {1,...,\numoflots}{
\node[prison=4,fived] (a) at (\x,0) {};
}
\fi
\node[prison=\residue] at (\numoflots+1,0) {};
\end{tikzpicture}
}
\DTLloaddb{cardinals}{cardinals.csv}
\begin{document}
\pagestyle{empty}
\begin{center}
{\Huge\textsc{Vota Scrutinii}}
\end{center}
\vspace{1em}
\begin{multicols}{2}
\begin{enumerate}
\DTLforeach{cardinals}{\surname=Surname,\name=Name,\votes=Votes}{%
\item \textsc{\surname\xspace\drawvotes{\votes}}}
\end{enumerate}
\end{multicols}
\end{document}
输出结果如下:
让我们重点关注投票部分:
耶,我们刚刚将 TeX 和朋友们带到了教皇选举!现在,我很想改进代码,如果可能的话,添加以下功能:
如果枢机主教获得 2/3 的选票,他就会当选教皇。如果候选人中有一人达到这个数字,我们可以在名单上给他的名字加上一个漂亮的蓝色圆圈,也许还可以加上一个注释教皇陛下!靠近它。这样,懒惰的红衣主教们就很容易发现当选的人选。
:)
如果没有人获得 2/3 的选票,至少我们现在可以了解投票方案,例如得票最多的枢机主教,这将影响下一次投票。我的想法是,如果没有枢机主教获得所有选票的 2/3,让我们在得票最多的 5 位枢机主教的名字周围添加一个漂亮的红色圆圈,这样我们就可以轻松发现趋势。
:)
如果您愿意,请随意添加更多功能。:)
好了,就这样。希望你们喜欢最初的代码和想法。:)
现在,我们需要请 egreg 或 Claudio Fiandrino 去罗马说服红衣主教们采用我们的提议。这会更有趣。:)
任何帮助都将受到赞赏。:)
背景
作为一名天主教徒,新教皇的选举对我来说是一个里程碑。事实上,随着教皇本笃十六世的辞职,这将是我第二次观看选举 - 教皇约翰保罗二世于 1978 年当选,那时我出生前几年,但我当然观看了拉辛格枢机主教的选举。:)
我甚至在电视上看到了白烟!
我爸爸经常给我讲很多过去选举的故事。我觉得整个过程相当有趣,尤其是枢机主教们投票给候选人的方式。
前巴西利亚大主教何塞·弗莱雷·法尔考枢机主教接受了巴西一家网站的精彩采访,并在采访中展示了上届枢机主教选举秘密会议的文件。这是投票选票,枢机主教写下他选择的名字。每位枢机主教投票后,就该汇总数据了!这已经完成了在另一份文件中,投票审查。
我几乎确信这个过程自古以来就是用墨水和纸张完成的。但当然,用 LaTeX 和朋友给他们一点帮助怎么样?:)
答案1
我的datatool
技术有限,所以以下解决方案使用 TeX 原语和 PGF 数学引擎及其\pgfutil@in@
宏/条件。
相互作用
第 99 行:红衣主教当选为教皇所需的最低比率。
\pgfmathparse{2/3*\the\value{sumVotes}}
第 70 行:如果没有人达到限制,则标记的红衣主教数量。因为这将在循环内使用,所以
\foreach
它至少应该是3
(→ Top 3)。\setcounter{numberOfTopCardinals}{5}
需要解释一下:如果两位或更多位红衣主教获得相同数量的选票,他们都会加入前五名名单。这意味着,尽管设置
numberOfTopCardinals
为,但5
我们可以在前五名名单中拥有六位或更多位红衣主教。又称“平局”。该
\ifHabemusPapam
条件可用于检查某位红衣主教是否已达到最低票数限制。样式
papa
、not papa
以及top
可every name
用于改变列表的外观。
它是如何工作的?
很简单:
- 第一个循环:
- 准备顶部列表的宏(
\votesForPlace<place>
)
- 准备顶部列表的宏(
- 第二循环:
- 所有投票总数
- 如果某人的基数投票大于列表中的投票数,则将其包括进去,并将最后一个淘汰。(我相信这种排序“算法”有一个名字……)
- 第三个循环:
- 该
\votesOfTopCardinals
宏将包含出现在顶部列表中的所有投票数。
- 该
- 检查顶部投票数(
\votesForPlace1
)是否大于或等于所需数量。这将设置\ifHabemusPapam
。 - 主循环(通过
\setStyleForVotes
):- 如果有人获得超过三分之二的选票,他将被授予 风格
papa
。 - 如果没有人获得超过三分之二的选票,则检查票数是否存在于前几名中。如果是,他将被分配
top
,否则not papa
。 - 生成的 TikZ 节点使用选定的样式和
every name
样式。
- 如果有人获得超过三分之二的选票,他将被授予 风格
代码
\documentclass{article}
\usepackage[T1]{fontenc}\usepackage[utf8]{inputenc}
\usepackage[top=1.5cm, bottom=1.5cm, left=1.5cm, right=1.5cm, landscape]{geometry}
\def\theenumi{\Roman{enumi}}
\usepackage{lmodern,datatool,multicol,xspace}
\usepackage{tikz}
\usetikzlibrary{calc,decorations}
\makeatletter
\pgfdeclaredecoration{penciline}{initial}{
\state{initial}[width=+\pgfdecoratedinputsegmentremainingdistance,
auto corner on length=1mm] {
\pgfpathcurveto{
\pgfqpoint{\pgfdecoratedinputsegmentremainingdistance}
{\pgfdecorationsegmentamplitude}
}{\pgfmathrand\pgfpointadd{\pgfqpoint{\pgfdecoratedinputsegmentremainingdistance}
{0pt}}
{\pgfqpoint{-\pgfdecorationsegmentaspect\pgfdecoratedinputsegmentremainingdistance}
{\pgfmathresult\pgfdecorationsegmentamplitude}
}
}{\pgfpointadd{\pgfpointdecoratedinputsegmentlast}{\pgfpoint{1pt}{1pt}}}
}
\state{final}{}
}
\makeatother
\tikzset{
prison/.style={
append after command={
\pgfextra
\ifnum#1=0\else
\foreach \x in {0,...,\number\numexpr#1-1\relax} {%
\coordinate (mytemp)
at ($(\tikzlastnode.north west)!0.3333*\x!(\tikzlastnode.north east)$);
\draw[decorate] (mytemp) -- (mytemp |- \tikzlastnode.south);}%
\fi
\endpgfextra
}
},
fived/.style={
append after command={
\pgfextra
\draw[decorate] ([shift={(-2mm,1mm)}]\tikzlastnode.south west) --
([shift={(2mm,-1mm)}]\tikzlastnode.north east);
\endpgfextra
}
},
}
\newcommand{\drawvotes}[1]{%
\begin{tikzpicture}[decoration=penciline]
\def\numofscr{#1}
\pgfmathtruncatemacro\residue{Mod(\numofscr,5)}
\pgfmathtruncatemacro\numoflots{\numofscr/5}
\ifnum\numofscr<5\else
\foreach \x in {1,...,\numoflots} \node[prison=4,fived] (a) at (\x,0) {};
\fi
\node[prison=\residue] at (\numoflots+1,0) {};
\end{tikzpicture}%
}
\DTLloaddb{cardinals}{cardinals.csv}
\newif\ifHabemusPapam
\newcounter{sumVotes}
\newcounter{numberOfTopCardinals}
%%%%% Number of Cardinals that will be marked if no one reached two thirds %%%
\setcounter{numberOfTopCardinals}{5}% > 2 %%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\foreach \i in {1,...,\value{numberOfTopCardinals}}{%
\expandafter\gdef\csname votesForPlace\i\endcsname{0}%
}
\DTLforeach{cardinals}{\votes=Votes}{%
\addtocounter{sumVotes}{\votes}%
\foreach \i in {1,...,\value{numberOfTopCardinals}} {
\ifnum\csname votesForPlace\i\endcsname=\votes\breakforeach\fi
\ifnum\csname votesForPlace\i\endcsname<\votes
\foreach \j in {\the\numexpr\value{numberOfTopCardinals}-1\relax,...,\i} {%
\global\expandafter\let
\csname votesForPlace\the\numexpr\j+1\relax\expandafter\endcsname
\csname votesForPlace\j\endcsname
}%
\expandafter\xdef\csname votesForPlace\i\endcsname{\votes}%
\breakforeach
\fi
}%
}
%\errmessage{\csname votesForPlace1\endcsname}% (debug)
\def\votesOfTopCardinals{}%
\def\votesOfPapa{10000}% = infinity
\foreach \i in {1,...,\value{numberOfTopCardinals}} {%
\xdef\votesOfTopCardinals{\votesOfTopCardinals,\csname votesForPlace\i\endcsname,}%
}
%\errmessage{\votesOfTopCardinals}% (debug)
\pgfmathparse{2/3*\the\value{sumVotes}}
%\errmessage{\pgfmathresult}% (debug)
\ifdim\pgfmathresult pt>\csname votesForPlace1\endcsname pt
\else\HabemusPapamtrue\fi
\makeatletter
\def\qrr@pgfutil@in@#1#2{% to save \expandafters
\edef\pgf@tempa{{#1}{#2}}%
\expandafter\pgfutil@in@\pgf@tempa}
\newcommand*{\setStyleForVotes}[2]{% #1 = votes
% #2 = macro to save style
\def\myStyle{not papa}%
\ifHabemusPapam
\ifnum\csname votesForPlace1\endcsname=#1\relax
\def#2{papa}%
\fi
\else
\qrr@pgfutil@in@{,#1,}\votesOfTopCardinals
\ifpgfutil@in@
\def#2{top}%
\fi
\fi
}
\makeatother
\tikzset{
not papa/.style={draw=none, fill=none},
papa/.style={draw=blue},
top/.style={draw=red},
expand me/.style={#1},
every name/.style={
font=\scshape,
anchor=base,
rounded corners,
}
}
\begin{document}
\pagestyle{empty}
\begin{center}
{\Huge\textsc{Vota Scrutinii}}
\end{center}
\vspace{1em}
\begin{multicols}{2}
\begin{enumerate}
\DTLforeach{cardinals}{\surname=Surname,\name=Name,\votes=Votes}{%
\setStyleForVotes\votes\myStyle
\item \tikz[baseline]\node[expand me/.expand once=\myStyle,every name]{\surname};%
\xspace\drawvotes{\votes}%
}%
\end{enumerate}
\end{multicols}
\end{document}