![如何在 LaTeX 中创建垂直时间线并按比例划分条目(可能避免年份重复)?](https://linux22.com/image/465815/%E5%A6%82%E4%BD%95%E5%9C%A8%20LaTeX%20%E4%B8%AD%E5%88%9B%E5%BB%BA%E5%9E%82%E7%9B%B4%E6%97%B6%E9%97%B4%E7%BA%BF%E5%B9%B6%E6%8C%89%E6%AF%94%E4%BE%8B%E5%88%92%E5%88%86%E6%9D%A1%E7%9B%AE%EF%BC%88%E5%8F%AF%E8%83%BD%E9%81%BF%E5%85%8D%E5%B9%B4%E4%BB%BD%E9%87%8D%E5%A4%8D%EF%BC%89%EF%BC%9F.png)
我需要一些帮助来创建具有特定要求的垂直时间轴。时间轴应在垂直线的左侧显示日期,右侧显示相应的标签。日期应采用英文格式,即“年、月、日”(例如“1938 年 1 月 13 日”)。理想情况下,只有在第一次使用新年时才会打印年份。条目应根据其确切日期沿时间轴的长度按比例分布。
我提供了一段代码来尝试实现这一点,但我无法获得所需的输出。它确实在 1 - 3 点上取得了成功,但我在 4 和 5 点上遇到了困难——尽管对我来说,第 5 点比第 4 点重要得多。如果能提供任何帮助或建议来修改代码并实现所需的垂直时间线,我将不胜感激。
\documentclass[10pt]{article}
\usepackage[paperwidth=210mm,paperheight=297mm,tmargin=7.5mm,rmargin=7.5mm,bmargin=7.5mm,lmargin=7.5mm,vscale=1,hscale=1]{geometry}
\usepackage{tikz}
\usetikzlibrary{arrows, calc, decorations.markings, positioning}
\pagestyle{empty}
\makeatletter
\newenvironment{timeline}[6]{%
\newcommand{\startyear}{#1}
\newcommand{\tlendyear}{#2}
\newcommand{\yearcolumnwidth}{#3}
\newcommand{\rulecolumnwidth}{#4}
\newcommand{\entrycolumnwidth}{#5}
\newcommand{\timelineheight}{#6}
\newcommand{\templength}{}
\newcommand{\entrycounter}{0}
\long\def\ifnodedefined##1##2##3{%
\@ifundefined{pgf@sh@ns@##1}{##3}{##2}%
}
\newcommand{\ifnodeundefined}[2]{%
\ifnodedefined{##1}{}{##2}
}
\newcommand{\drawtimeline}{%
\draw[timelinerule] (\yearcolumnwidth+5pt, 0pt) -- (\yearcolumnwidth+5pt, -\timelineheight);
\draw (\yearcolumnwidth+0pt, -10pt) -- (\yearcolumnwidth+10pt, -10pt);
\draw (\yearcolumnwidth+0pt, -\timelineheight+15pt) -- (\yearcolumnwidth+10pt, -\timelineheight+15pt);
\pgfmathsetlengthmacro{\templength}{neg(add(multiply(subtract(\startyear, \startyear), divide(subtract(\timelineheight, 25), subtract(\tlendyear, \startyear))), 10))}
\node[year] (year-\startyear) at (\yearcolumnwidth, \templength) {\startyear};
\pgfmathsetlengthmacro{\templength}{neg(add(multiply(subtract(\tlendyear, \startyear), divide(subtract(\timelineheight, 25), subtract(\tlendyear, \startyear))), 10))}
\node[year] (year-\tlendyear) at (\yearcolumnwidth, \templength) {\tlendyear};
}
\newcommand{\entry}[4]{%
% #1 is the year
% #2 is the month
% #3 is the day
% #4 is the entry text
\pgfmathtruncatemacro{\lastentrycount}{\entrycounter}
\pgfmathtruncatemacro{\entrycounter}{\entrycounter + 1}
\ifdim \lastentrycount pt > 0 pt%
\node[entry] (entry-\entrycounter) [below of=entry-\lastentrycount] {##4};
\else%
\pgfmathsetlengthmacro{\templength}{neg(add(multiply(subtract(\startyear, \startyear), divide(subtract(\timelineheight, 25), subtract(\tlendyear, \startyear))), 10))}
\node[entry] (entry-\entrycounter) at (\yearcolumnwidth+\rulecolumnwidth+10pt, \templength) {##4};
\fi
\ifnodeundefined{year-##1-##2-##3}{%
\pgfmathsetlengthmacro{\templength}{neg(add(multiply(subtract(##1, \startyear), divide(subtract(\timelineheight, 25), subtract(\tlendyear, \startyear))), 10))}
\draw (\yearcolumnwidth+2.5pt, \templength) -- (\yearcolumnwidth+7.5pt, \templength);
\node[year] (year-##1-##2-##3) at (\yearcolumnwidth, \templength) {##1, ##3 \ifcase##2\or January\or February\or March\or April\or May\or June\or July\or August\or September\or October\or November\or December\fi};
}
\draw ($(year-##1-##2-##3.east)+(2.5pt, 0pt)$) -- ($(year-##1-##2-##3.east)+(7.5pt, 0pt)$) -- ($(entry-\entrycounter.west)-(5pt,0)$) -- (entry-\entrycounter.west);
}
\begin{tikzpicture}
\tikzstyle{entry} = [align=left,text width=\entrycolumnwidth,node distance=10mm,anchor=west]
\tikzstyle{year} = [anchor=east]
\tikzstyle{timelinerule} = [draw,decoration={markings, mark=at position 1 with {\arrow[scale=1.5]{latex'}}},postaction={decorate},shorten >=0.4pt]
\drawtimeline
}
{
\end{tikzpicture}
\let\startyear\@undefined
\let\tlendyear\@undefined
\let\yearcolumnwidth\@undefined
\let\rulecolumnwidth\@undefined
\let\entrycolumnwidth\@undefined
\let\timelineheight\@undefined
\let\entrycounter\@undefined
\let\ifnodedefined\@undefined
\let\ifnodeundefined\@undefined
\let\drawtimeline\@undefined
\let\entry\@undefined
}
\makeatother
\begin{document}
\begin{timeline}{1935}{1950}{2cm}{1.5cm}{13cm}{26cm}
\entry{1938}{9}{17}{Sudeten German Freikorps and other German paramilitary groups attacked Czechoslovak troops and institutions in the border areas}
\entry{1938}{9}{30}{Signing of the Betrayal of Munich by Hitler, Chamberlain, Daladier, and Mussolini: annexation of Sudetenland by Germany}
\entry{1939}{3}{15}{German army occupies Prague and establishes the Protectorate of Bohemia and Moravia, a puppet state with Konstantin Freiherr von Neurath at the helm}
\entry{1939}{7}{6}{Zentralstelle für jüdische Auswanderung in Böhmen und Mähren [Center for Jewish Emigration in Bohemia and Moravia] is established following the one in Vienna}
\entry{1939}{12}{1}{Jewish children are excluded from state schools}
\entry{1940}{6}{14}{Auschwitz extermination camp is established}
\entry{1941}{9}{27}{Reinhard Heydrich becomes the new Reichsprotektor and orders mass deportation of Jewish people and the reorganization of Terezín into a ghetto}
\entry{1941}{10}{16}{First transport from Prague to the Lodz ghetto}
\entry{1941}{11}{24}{First transport of Jewish people arrives in Terezín}
\end{timeline}
\end{document}
答案1
一种不同的方法,希望有所帮助。
这是轴向下,其刻度设置为使得每年为1
(→ year length
)。
该pgfcalendar
包/模块用于评估每个日期的年份分数。
该宏\tikz@timeline@<year>
用于缓存该年份的一些计算,同时也用于检查该年份是否已在此图表中使用过,并在内部用于\tlDate
省略年份数字。
我添加了第二个示例,其中日期和条目的文本位于同一侧。我认为这更易于阅读。它还展示了环境的灵活性,因为所有内容都可以通过名称、链、数字或样式访问。
代码
%\documentclass[10pt]{article}
%\usepackage[paperwidth=210mm,paperheight=297mm,tmargin=7.5mm,rmargin=7.5mm,bmargin=7.5mm,lmargin=7.5mm,vscale=1,hscale=1]{geometry}
\documentclass[tikz]{standalone}
\usepackage{tikz, pgfcalendar}
\newcommand*\tikztimelineset{\pgfqkeys{/tikz/timeline}}
\usetikzlibrary{arrows.meta, chains}
\tikzset{west below/.style={below=#1.south west, anchor=north west},
east below/.style={below=#1.south east, anchor=north east}}
\tikztimelineset{
start year/.initial=1900,
end year/.initial=2000,
year length/.initial=1.5cm,
entry text distance/.initial=2cm,
entry date distance/.initial=1.5cm,
every tick length/.initial=5pt,
every rule/.style={->, draw, shorten <=+-5pt, shorten >=+-5pt},
every tick line/.style={draw=gray},
every diagram/.style={
> = Latex[{round,open}],
start chain=entry text going west below,
start chain=entry date going east below,
node distance=.5em,
},
every entry line/.style={rounded corners={.5*(\pgfkeysvalueof{/tikz/timeline/every tick length})}},
every entry text/.style n args={4}{
timeline/every entry text@, on chain=entry text, align=left, text width=10cm},
every entry date/.style n args={4}{timeline/every entry date@, on chain=entry date},
dates left and text right/.style={
every entry text@/.style={% only the first, after that it's on the chain
anchor=base west, at=(right:{\pgfkeysvalueof{/tikz/timeline/entry text distance}})},
every entry date@/.style={% only the first, after that it's on the chain
anchor=base east,
at=(left:{\pgfkeysvalueof{/tikz/timeline/entry date distance}})},
every entry text line/.style={
timeline/every entry line,
to path={
(\tikztostart.mid west)
-- +(left:{\pgfkeysvalueof{/tikz/timeline/every tick length}})
-- ([xshift=\pgfkeysvalueof{/tikz/timeline/every tick length}]\tikztotarget)
-- (\tikztotarget)}},
every entry date line/.style={
timeline/every entry line,
to path={
(\tikztostart.east)
-- +(right:{\pgfkeysvalueof{/tikz/timeline/every tick length}})
-- ([xshift=-(\pgfkeysvalueof{/tikz/timeline/every tick length})]\tikztotarget)
-- (\tikztotarget)}}},
dates and text right/.style={
/tikz/continue chain=entry date going cal date,
/tikz/continue chain=entry text going cal entry,
/tikz/cal date/.style={below left=3.5em and 0pt of entry text-end.south west},
/tikz/cal entry/.style={base right=0pt of entry date-end},
every entry date@/.style={at=(right:1.5cm), anchor=base west},
every entry text@/.style={at=(entry date-1.base east), anchor=base west},
every entry text line/.style={path only, overlay, to path=}, % disable
every entry date line/.append style={
timeline/every entry line,
to path={
--([xshift=-width("{0000, 00 September}")-1em]\tikztostart.east)
\expanded{--([xshift=5pt]\tikztotarget)--([xshift=-5pt]\tikztotarget)}}},
every tick line/.append style={every to/.append style={edge node={
node[at start, below right, rotate=-90, append after command={
edge[->, to path=(\tikzlastnode.north west)-|(\tikzlastnode.south east)]()}]{\tlYear}}}}},
}
\newcommand*{\tlDate}[3]{\tlIfYearNew{#1}{#1, }{}#3 \pgfcalendarmonthname{#2}}
\makeatletter
\newcommand*\tlIfYearNew[1]{\ifcsname tikz@timeline@#1\endcsname\expandafter\@secondoftwo\else\expandafter\@firstoftwo\fi}
\newenvironment{timeline}[1][]{
\tikzpicture[timeline/every diagram,timeline/.cd,#1]%
\pgfmathtruncatemacro\tlYearDifference{\pgfkeysvalueof{/tikz/timeline/end year}
-(\pgfkeysvalueof{/tikz/timeline/start year})}%
\tikzset{y=-(\pgfkeysvalueof{/tikz/timeline/year length})}%
\path[timeline/every rule] (0,0) -- ++(0,\tlYearDifference);
\foreach[count=\tlYear from \pgfkeysvalueof{/tikz/timeline/start year}]\tlY in {0,...,\tlYearDifference}
\path[timeline/every tick line]
([xshift=-(\pgfkeysvalueof{/tikz/timeline/every tick length})]up:\tlY)
to +(right:{2*(\pgfkeysvalueof{/tikz/timeline/every tick length})});
\def\entry##1##2##3##4{% only defined inside timeline environment
\tlIfYearNew{##1}{% calculate needed values
\pgfcalendardatetojulian{##1-1-1}{\count@}%
\edef\tlYearFirstDay{\the\count@}%
\pgfcalendardatetojulian{\pgfinteval{##1+1}-1-1}{\count@}%
\edef\tlYearTotalDays{\pgfinteval{\count@-\tlYearFirstDay}}%
}{% extract previously stored values
\edef\tlYearFirstDay {\expandafter\expandafter\expandafter\@firstoftwo \csname tikz@timeline@##1\endcsname}%
\edef\tlYearTotalDays{\expandafter\expandafter\expandafter\@secondoftwo\csname tikz@timeline@##1\endcsname}%
}%
\pgfcalendardatetojulian{##1-##2-##3}{\count@}%
\advance\count@ by -\tlYearFirstDay\relax % too big for PGFMath
\pgfmathsetmacro\tlYearFraction{\count@/\tlYearTotalDays}%
\coordinate(timeline point) at (up:{##1-(\pgfkeysvalueof{/tikz/timeline/start year})+\tlYearFraction});
\node[timeline/every entry date={##1}{##2}{##3}{##4}]{\tlDate{##1}{##2}{##3}} edge[timeline/every entry date line] (timeline point);
\node[timeline/every entry text={##1}{##2}{##3}{##4}]{##4} edge[timeline/every entry text line] (timeline point);
\tlIfYearNew{##1}{\expandafter\edef\csname tikz@timeline@##1\endcsname{{\tlYearFirstDay}{\tlYearTotalDays}}}{}% store values for next time
}%
}{\endtikzpicture}
\makeatother
\begin{document}
\noindent
\begin{timeline}[
start year=1935,
end year=1945,
dates left and text right,
every entry date@/.append style={node distance=3.5em},
]
\entry{1938}{9}{17}{Sudeten German Freikorps and other German paramilitary groups attacked Czechoslovak troops and institutions in the border areas}
\entry{1938}{9}{30}{Signing of the Betrayal of Munich by Hitler, Chamberlain, Daladier, and Mussolini: annexation of Sudetenland by Germany}
\entry{1939}{3}{15}{German army occupies Prague and establishes the Protectorate of Bohemia and Moravia, a puppet state with Konstantin Freiherr von Neurath at the helm}
\entry{1939}{7}{6}{Zentralstelle für jüdische Auswanderung in Böhmen und Mähren [Center for Jewish Emigration in Bohemia and Moravia] is established following the one in Vienna}
\entry{1939}{12}{1}{Jewish children are excluded from state schools}
\entry{1940}{6}{14}{Auschwitz extermination camp is established}
\entry{1941}{9}{27}{Reinhard Heydrich becomes the new Reichsprotektor and orders mass deportation of Jewish people and the reorganization of Terezín into a ghetto}
\entry{1941}{10}{16}{First transport from Prague to the Lodz ghetto}
\entry{1941}{11}{24}{First transport of Jewish people arrives in Terezín}
\end{timeline}
\begin{timeline}[
start year=1937,
end year=1944,
year length=3cm,
dates and text right,
]
\entry{1938}{9}{17}{Sudeten German Freikorps and other German paramilitary groups attacked Czechoslovak troops and institutions in the border areas}
\entry{1938}{9}{30}{Signing of the Betrayal of Munich by Hitler, Chamberlain, Daladier, and Mussolini: annexation of Sudetenland by Germany}
\entry{1939}{3}{15}{German army occupies Prague and establishes the Protectorate of Bohemia and Moravia, a puppet state with Konstantin Freiherr von Neurath at the helm}
\entry{1939}{7}{6}{Zentralstelle für jüdische Auswanderung in Böhmen und Mähren [Center for Jewish Emigration in Bohemia and Moravia] is established following the one in Vienna}
\entry{1939}{12}{1}{Jewish children are excluded from state schools}
\entry{1940}{6}{14}{Auschwitz extermination camp is established}
\entry{1941}{9}{27}{Reinhard Heydrich becomes the new Reichsprotektor and orders mass deportation of Jewish people and the reorganization of Terezín into a ghetto}
\entry{1941}{10}{16}{First transport from Prague to the Lodz ghetto}
\entry{1941}{11}{24}{First transport of Jewish people arrives in Terezín}
\end{timeline}
\end{document}
输出
答案2
我尝试将我的评论写进实际代码中,结果如下。遗憾的是,该chronology
软件包在定制方面很糟糕,唯一的选择似乎是原始的,tikz
而我没有这方面的经验,所以我想就把这部分称为“草稿”吧。
尽管如此,我发现分离时间线和表格的一般方法比垂直一体化时间线更具可读性且更不复杂。
\documentclass{article}
\usepackage{chronology}
\usepackage{tabularx}
\usepackage{booktabs}
\begin{document}
\begin{figure}
\begin{chronology}[1]{1938}{1941}{\textwidth}
\event{\decimaldate{17}{9}{1938}}{1}
\event{\decimaldate{30}{9}{1938}}{2}
\event{\decimaldate{6}{7}{1939}}{3}
\event{\decimaldate{1}{12}{1939}}{4}
\event{\decimaldate{14}{6}{1940}}{5}
\event{\decimaldate{17}{9}{1938}}{6}
\event{\decimaldate{27}{9}{1941}}{7}
\event{\decimaldate{16}{10}{1941}}{8}
\event{\decimaldate{24}{11}{1941}}{9}
\end{chronology}
\caption{Timeline. Details in table \ref{tab}.}
\label{fig}
\end{figure}
\newcommand{\mycmidrulegroup}{
\cmidrule(r){1-1}\cmidrule(lr){2-2}\cmidrule(lr){3-3}
\cmidrule(lr){4-4}\cmidrule(l){5-5}}
\begin{table}
\begin{tabularx}{\linewidth}{
@{}rrrrX@{}}
\toprule
{N} & {Y} & {M} & {D} & Event \\
\midrule
1 & 1938 & 9 & 17 &
Sudeten German Freikorps and other German paramilitary groups attacked Czechoslovak troops and institutions in the border areas \\
\mycmidrulegroup
2 &1938 & 9 & 30 &
Signing of the Betrayal of Munich by Hitler, Chamberlain, Daladier, and Mussolini: annexation of Sudetenland by Germany \\
\mycmidrulegroup
3 &1939 & 3 & 15 &
German army occupies Prague and establishes the Protectorate of Bohemia and Moravia, a puppet state with Konstantin Freiherr von Neurath at the helm \\
\mycmidrulegroup
4 &1939 & 7 & 6 &
Zentralstelle für jüdische Auswanderung in Böhmen und Mähren [Center for Jewish Emigration in Bohemia and Moravia] is established following the one in Vienna \\
\mycmidrulegroup
5 &1939 & 12 & 1 &
Jewish children are excluded from state schools \\
\mycmidrulegroup
6 &1940 & 6 & 14 &
Auschwitz extermination camp is established \\
\mycmidrulegroup
7 &1941 & 9 & 27 &
Reinhard Heydrich becomes the new Reichsprotektor and orders mass deportation of Jewish people and the reorganization of Terezín into a ghetto \\
\mycmidrulegroup
8 &1941 & 10 & 16 &
First transport from Prague to the Lodz ghetto \\
\mycmidrulegroup
9 &1941 & 11 & 24 &
First transport of Jewish people arrives in Terezín \\
\bottomrule
\end{tabularx}
\caption{Detailed events. Overview in figure \ref{fig}.}
\label{tab}
\end{table}
\end{document}