![在纸上的多行上创建一个时间线](https://linux22.com/image/381607/%E5%9C%A8%E7%BA%B8%E4%B8%8A%E7%9A%84%E5%A4%9A%E8%A1%8C%E4%B8%8A%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA%E6%97%B6%E9%97%B4%E7%BA%BF.png)
在浏览 tex.SE 时,我看到这在这里回答,真的很惊讶它看起来如此漂亮和干净。现在我面临的问题略有不同,而且我对 tikz 不太熟悉(我只知道如何做一些简单的事情),所以我无法真正调整代码以适应我的问题。
假设您有一张 A4 纸的空间,我想将一条时间线分成 13 条单独的“子线”,每条“子线”代表一个月,并从纸上的新行开始。然后为时间线上的每个事件创建一个彩色方块,并在该方块中写下事件的名称。
为了使它更清楚一点,这里有一张图片。
目标是创建一个新的命令,类似于提到的帖子,并包含以下信息:
\event{dd.mm.}{dd.mm.}{text}{color}{number}
其中第一个参数是事件的开始日期,第二个参数是结束日期。第三个参数应表示方块内的文本,第四个参数是方块的颜色,由于一些事件重叠,我还需要将事件放置在不同高度的选项,因此是最后一个参数。
对我来说这里最大的两个问题是:
- 我不知道如何创建一条连续的线,然后将其分成十三段,每段占一行。
- 有些活动只有一天,所以文本不可能放得下。这些情况需要一些特殊处理,但我不知道如何实现这样的事情。
或者,我也可以单独创建十三条时间线,然后将它们放在一张图中,这样至少可以解决第一个问题。当然,也可以选择直接创建,用箭头作为时间线,然后手工绘制每个方块、文本等,但由于条目将来可能会发生很大变化,这似乎不是最佳选择。
很抱歉我没有可以运行的 MWE,但说实话我有点不知道如何创建这样的命令。
编辑: 经过一些尝试,我得出了以下结论:
\documentclass[12pt]{article}
\usepackage[a4paper, margin=1cm]{geometry}
\usepackage{amsmath}
\usepackage{xstring}
\usepackage{tikz}
\usetikzlibrary{fit, calc}
\pagestyle{empty}
\newcommand{\anno}{1} % starting year
\newcommand{\target}{31} % ending year
\newcommand{\alto}{3} % height
\pgfmathsetmacro{\myend}{\target+1-\anno}
\pgfmathsetmacro{\myspacing}{16/(\target-1-\anno)}
\newcommand{\eventpoint}[4]{
\StrBefore{#1}{/}[\dstart]%x1=day_start
\StrBehind{#1}{/}[\mstart]%y1=month_start
\StrBefore{#2}{/}[\dend]%x2=day_end
\StrBehind{#2}{/}[\mend]%y2=month_end
\pgfmathsetmacro{\mmstart}{((13-\mstart)*4)}
\pgfmathsetmacro{\mmend}{((13-\mend)*4)}
\ifthenelse{\mstart = \mend}
{\filldraw[fill=#3!50, draw=#3,] (\dstart, \mmstart ) rectangle (\dend, \mmend+1) node [font=\scriptsize, text centered, midway, inner sep=0pt] {#4};}
{\filldraw[fill=#3!50, draw=#3,] (\dstart, \mmstart ) rectangle (31, \mmstart+1) node [font=\scriptsize, text centered, midway, inner sep=0pt] {#4};
\filldraw[fill=#3!50, draw=#3,] (0, \mmend ) rectangle (\dend, \mmend+1) node [font=\scriptsize, text centered, midway, inner sep=0pt] {#4};};
}
\begin{document}
\begin{tikzpicture}[x=\myspacing cm,y=5mm]
\centering
%creating the sublines needed and formating them
\foreach \y in {0,4,8,12,16,20,24,28,32,36,40,44,48}{
\draw[|->, -latex] (-.5,\y) -- (\myend+.5,\y);
\path (0,0) -- (0,\alto);
\foreach \x [evaluate=\x as \day using int(\x)] in {0,10,20,30}{
\draw (\x,\y) node[below=7pt,font=\footnotesize] {$\day$};
\draw (\x,\y -.2) -- (\x,\y +.2);
\draw[loosely dotted] (\x,\y +.2) -- (\x,\y+ \alto-0.5);
}
\foreach \tick in {0,...,\myend}{
\draw (\tick,\y +.1) -- (\tick,\y -.1);
}
}
%trying to add the events
\eventpoint{15/7}{25/7}{green}{test}
\eventpoint{17/8}{19/9}{red}{test 2}
\end{tikzpicture}
\end{document}
代码无法正常工作,但我怀疑这是由于我错误使用造成的\ifthenelse
。希望有人可以修复这个问题。
答案1
\ifthenelse
代码中的 可以用标准 轻松实现。\ifnum
此外,我通过重用 强大的 key/val 功能重新实现了日期设置/解析pgf
。
\documentclass[12pt]{article}
\usepackage[a4paper, margin=1cm]{geometry}
\usepackage{tikz}
\pagestyle{empty}
\newcommand{\anno}{1} % starting year
\newcommand{\target}{31} % ending year
\newcommand{\alto}{3} % height
\tikzset{
start date/.code args = {#1/#2}{
\def\dstart{#1}
\def\mstart{#2}
},
end date/.code args = {#1/#2}{
\def\dend{#1}
\def\mend{#2}
},
event color/.style = {
fill=#1!50, draw=#1,
},
}
\pgfmathsetmacro{\myend}{\target+1-\anno}
\pgfmathsetmacro{\myspacing}{16/(\target-1-\anno)}
\newcommand{\eventpoint}[2][]{
\begin{scope}[#1]
\pgfmathsetmacro{\mmstart}{((13-\mstart)*4)}
\pgfmathsetmacro{\mmend}{((13-\mend)*4)}
\ifnum\mstart=\mend
\filldraw (\dstart, \mmstart ) rectangle (\dend, \mmend+1) node [font=\scriptsize, text centered, midway, inner sep=0pt] {#2};
\else
\filldraw (\dstart, \mmstart ) rectangle (31, \mmstart+1) node [font=\scriptsize, text centered, midway, inner sep=0pt] {#2};
\filldraw (0, \mmend ) rectangle (\dend, \mmend+1) node [font=\scriptsize, text centered, midway, inner sep=0pt] {#2};
\fi
\end{scope}
}
\begin{document}
\centering
\begin{tikzpicture}[x=\myspacing cm,y=5mm]
%creating the sublines needed and formating them
\foreach \y in {0,4,8,12,16,20,24,28,32,36,40,44,48}{
\draw[|->, -latex] (-.5,\y) -- (\myend+.5,\y);
\path (0,0) -- (0,\alto);
\foreach \x [evaluate=\x as \day using int(\x)] in {0,10,20,30}{
\draw (\x,\y) node[below=7pt,font=\footnotesize] {$\day$};
\draw (\x,\y -.2) -- (\x,\y +.2);
\draw[loosely dotted] (\x,\y +.2) -- (\x,\y+ \alto-0.5);
}
\foreach \tick in {0,...,\myend}{
\draw (\tick,\y +.1) -- (\tick,\y -.1);
}
}
%trying to add the events
\eventpoint[start date=15/7,end date=25/7,event color=green]{test}
\eventpoint[start date=17/8,end date=19/9,event color=red,yshift=5pt]{test 2} % shift just to show you can hook into standard tikz keys to change the event's features ad-hoc
\end{tikzpicture}
\end{document}
通过使用范围的键定义日期,您可以获得许多好处:
- 提高可读性(无需猜测参数顺序)
- 提供默认值或替代方案的可能性(练习:实现
duration=months
可以替代使用的键end date
) - 能够为每个事件指定临时 tikz 密钥
- 轻松扩展附加按键
- 解析是通过匹配参数中的分隔符来完成的
可以进行的其他改进:您可以定义设置anno
、target
和alto
参数的键。
\documentclass[12pt]{article}
\usepackage[a4paper, margin=1cm]{geometry}
\usepackage{tikz}
\pagestyle{empty}
% \newcommand{\anno}{1} % starting year
% \newcommand{\target}{31} % ending year
% \newcommand{\alto}{3} % height
\tikzset{
anno/.store in=\anno,
target/.store in=\target,
alto/.store in=\alto,
start date/.code args = {#1/#2}{
\def\dstart{#1}
\def\mstart{#2}
},
end date/.code args = {#1/#2}{
\def\dend{#1}
\def\mend{#2}
},
event color/.style = {
fill=#1!50, draw=#1,
},
anno=1, target=1, alto=1,% here are the defaults
auto x/.style={x=16/(\target-1-\anno)*1cm},
}
\newcommand{\eventpoint}[2][]{
\begin{scope}[#1]
\pgfmathsetmacro{\mmstart}{((13-\mstart)*4)}
\pgfmathsetmacro{\mmend}{((13-\mend)*4)}
\ifnum\mstart=\mend
\filldraw (\dstart, \mmstart ) rectangle (\dend, \mmend+1) node [font=\scriptsize, text centered, midway, inner sep=0pt] {#2};
\else
\filldraw (\dstart, \mmstart ) rectangle (31, \mmstart+1) node [font=\scriptsize, text centered, midway, inner sep=0pt] {#2};
\filldraw (0, \mmend ) rectangle (\dend, \mmend+1) node [font=\scriptsize, text centered, midway, inner sep=0pt] {#2};
\fi
\end{scope}
}
\begin{document}
\centering
\begin{tikzpicture}[
anno=1, target=31, alto=3,
auto x, y=5mm,
]
\pgfmathsetmacro{\myend}{\target+1-\anno}
%creating the sublines needed and formating them
\foreach \y in {0,4,8,12,16,20,24,28,32,36,40,44,48}{
\draw[|->, -latex] (-.5,\y) -- (\myend+.5,\y);
\path (0,0) -- (0,\alto);
\foreach \x [evaluate=\x as \day using int(\x)] in {0,10,20,30}{
\draw (\x,\y) node[below=7pt,font=\footnotesize] {$\day$};
\draw (\x,\y -.2) -- (\x,\y +.2);
\draw[loosely dotted] (\x,\y +.2) -- (\x,\y+ \alto-0.5);
}
\foreach \tick in {0,...,\myend}{
\draw (\tick,\y +.1) -- (\tick,\y -.1);
}
}
%trying to add the events
\eventpoint[start date=15/7,end date=25/7,event color=green]{test}
\eventpoint[start date=17/8,end date=19/9,event color=red,yshift=5pt]{test 2}
\end{tikzpicture}
\end{document}
如果你想扩展活动的外观,强烈推荐
将产生事件的代码包装到pic
定义中(参见手册)。
答案2
用 Mathcha 回答了一下。作品不是最好的,但与图片相似。
\documentclass[a4paper,12pt]{article}
\usepackage{tikz}
\begin{document}
\tikzset{every picture/.style={line width=0.75pt}} %set default line width to 0.75pt
\begin{tikzpicture}[x=0.75pt,y=0.75pt,yscale=-1,xscale=1]
%uncomment if require: \path (0,300); %set diagram left start at 0, and has height of 300
\draw [color={rgb, 255:red, 0; green, 0; blue, 0 } ,draw opacity=1 ][fill={rgb, 255:red, 239; green, 100; blue, 215 } ,fill opacity=0.86 ] (381,48.33) -- (459,48.33) -- (459,80.33) -- (381,80.33) -- cycle ;
\draw (101.33,81.67) -- (459.83,80.67) ;
\draw [shift={(461.83,80.67)}, rotate = 539.8399999999999] [color={rgb, 255:red, 0; green, 0; blue, 0 } ][line width=0.75] (10.93,-3.29) .. controls (6.95,-1.4) and (3.31,-0.3) .. (0,0) .. controls (3.31,0.3) and (6.95,1.4) .. (10.93,3.29) ;
\draw (100.67,151) -- (459.17,150.01) ;
\draw [shift={(461.17,150)}, rotate = 539.8399999999999] [color={rgb, 255:red, 0; green, 0; blue, 0 } ][line width=0.75] (10.93,-3.29) .. controls (6.95,-1.4) and (3.31,-0.3) .. (0,0) .. controls (3.31,0.3) and (6.95,1.4) .. (10.93,3.29) ;
\draw (100.67,140.5) -- (100.67,161.5) ;
\draw (101.33,71.16) -- (101.33,92.17) ;
\draw (201.33,72.16) -- (201.33,93.17) ;
\draw (300.33,72.16) -- (300.33,93.17) ;
\draw (399.33,72.16) -- (399.33,93.17) ;
\draw (201.33,140.16) -- (201.33,161.17) ;
\draw (300.33,139.16) -- (300.33,160.17) ;
\draw (400.33,137.16) -- (400.33,158.17) ;
\draw [color={rgb, 255:red, 0; green, 0; blue, 0 } ,draw opacity=1 ][fill={rgb, 255:red, 126; green, 211; blue, 33 } ,fill opacity=1 ] (139,49.33) -- (242,49.33) -- (242,81.33) -- (139,81.33) -- cycle ;
\draw [color={rgb, 255:red, 0; green, 0; blue, 0 } ,draw opacity=1 ][fill={rgb, 255:red, 248; green, 231; blue, 28 } ,fill opacity=1 ] (219,17.33) -- (322,17.33) -- (322,49.33) -- (219,49.33) -- cycle ;
\draw [color={rgb, 255:red, 0; green, 0; blue, 0 } ,draw opacity=1 ][fill={rgb, 255:red, 239; green, 100; blue, 215 } ,fill opacity=0.86 ] (100.67,119) -- (159.5,119) -- (159.5,151) -- (100.67,151) -- cycle ;
\draw (341.33,140.16) -- (341.33,161.17) ;
\draw (341.33,140.16) -- (374.33,120.5) ;
\draw (70,74) node [align=left] {Apr.};
\draw (70,147) node [align=left] {May};
\draw (101,102) node [align=left] {1};
\draw (200,103) node [align=left] {10};
\draw (299,102) node [align=left] {20};
\draw (400,101) node [align=left] {30};
\draw (102,172) node [align=left] {1};
\draw (201,173) node [align=left] {10};
\draw (300,172) node [align=left] {20};
\draw (401,171) node [align=left] {30};
\draw (189,66) node [align=left] {event 1};
\draw (266,33) node [align=left] {event 2};
\draw (420,64) node [align=left] {event 3};
\draw (129,135) node [align=left] {event 3};
\draw (405,119) node [align=left] {event 4};
\end{tikzpicture}
\end{document}