如何在 TikZ 循环中创建行高不均匀的时间图表?

如何在 TikZ 循环中创建行高不均匀的时间图表?

下面的代码生成给定的图表。(感谢 Sandy G!- 请参阅如何创建类似这种风格的时间线图表?建议

我对此进行了许多修改,甚至添加了其他变量(即水平和垂直拉伸因子)。但是,我现在陷入困境。我想进行修改以处理左侧标签跨越多行的情况。我对编程并不陌生,但我对 Tikz 编程还不熟悉。我想创建一个变量来存储 Y 偏移量(累积的),最初设置为 0,用于 foreach 循环。

简化问题:
在 foreach 循环中,如何编写以下代码而不出现错误,其中 yoffset 最初设置为零:

\yoffset = \yoffset + 1

\documentclass{article}

\usepackage{tikz}
\definecolor{linecolor}{rgb}{0, 0.5, 0.5}

\newcommand{\timeline}[6][2]{\begin{tikzpicture}
    \node[anchor=base] at (0,.15){\textsf{\textbf{\scriptsize#2}}};
    \foreach [var=\n, evaluate=\n as \l using int(\n*#4+#3-#4)] in {1,...,#5}{
        \node[anchor=base] at (\n,.15){\textsf{\textbf\l}};}
    \foreach [var=\timea, var=\timeb, var=\event, count=\n] in {#6}{
        \pgfmathsetmacro{\col}{\ifodd\n"linecolor"\else"white"\fi}
        \fill[color=\col!15](-#1,-\n+1) rectangle (#5+1,-\n);
        \foreach \m in {0,...,#5}{\draw[linecolor](\m,-\n+1)--(\m,-\n);}
        \fill[linecolor,rounded corners=1.5mm]({(\timea-#3+#4)/#4},-\n+.65) rectangle ({(\timeb-#3+#4)/#4},-\n+.35);
        \node[anchor=base, right] at (-#1,-\n+.5) {\textsf{\textbf\event}};}
    \draw[linecolor](-#1,0)--(#5+1,0);
    \foreach [var=\timea, var=\timeb, count=\n] in {#6}{\draw[linecolor](-#1,-\n)--(#5+1,-\n);}
    \end{tikzpicture}}
%\timeline{label}{start}{step}{number}{intervals}

\begin{document}

\timeline[2.5]{A.D.}{30}{5}{11}{29/33/event 1,32/34.5/event 2,35.5/38/something,44/48/??,45.5/48/X,47/49.5/Y,47.5/52/Z,52/57.5/,61.5/63/,64/67/A}

\end{document}

在此处输入图片描述

答案1

我认为这个想法使事情变得复杂。相反,我建议使用(是可选的标签宽度参数)\yoffset为标签设置最大宽度。然后让它自己换行。\node[anchor=base, right, text width=#1cm]#1TikZ

\timeline[2.5]{A.D.}{30}{5}{11}{29/33/event 1,32/34.5/event 2,35.5/38/something,44/48/??,45.5/48/X,47/49.5/Y,47.5/52/Z,52/57.5/,61.5/63/,64/67/here is a very long label}

将产生输出

在此处输入图片描述

\documentclass{article}

\usepackage{tikz}
\definecolor{linecolor}{rgb}{0, 0.5, 0.5}

\newcommand{\timeline}[6][2]{\begin{tikzpicture}
    \node[anchor=base] at (0,.15){\textsf{\textbf{\scriptsize#2}}};
    \foreach [var=\n, evaluate=\n as \l using int(\n*#4+#3-#4)] in {1,...,#5}{
        \node[anchor=base] at (\n,.15){\textsf{\textbf\l}};}
    \foreach [var=\timea, var=\timeb, var=\event, count=\n] in {#6}{
        \pgfmathsetmacro{\col}{\ifodd\n"linecolor"\else"white"\fi}
        \fill[color=\col!15](-#1,-\n+1) rectangle (#5+1,-\n);
        \foreach \m in {0,...,#5}{\draw[linecolor](\m,-\n+1)--(\m,-\n);}
        \fill[linecolor,rounded corners=1.5mm]({(\timea-#3+#4)/#4},-\n+.65) rectangle ({(\timeb-#3+#4)/#4},-\n+.35);
        \node[anchor=base, right, text width=#1cm] at (-#1,-\n+.5) {\textsf{\textbf\event}};}
    \draw[linecolor](-#1,0)--(#5+1,0);
    \foreach [var=\timea, var=\timeb, count=\n] in {#6}{\draw[linecolor](-#1,-\n)--(#5+1,-\n);}
    \end{tikzpicture}}
%\timeline{label}{start}{step}{number}{intervals}

\begin{document}

\timeline[2.5]{A.D.}{30}{5}{11}{29/33/event 1,32/34.5/event 2,35.5/38/something,44/48/??,45.5/48/X,47/49.5/Y,47.5/52/Z,52/57.5/,61.5/63/,64/67/here is a very long label}

\end{document}

答案2

在此处输入图片描述

代码可能看起来很乱...但是,我对最终的结果很满意。

这仍然没有真正回答原来的陈述的问题(如何在 Tikz foreach 循环中改变变量的值?) - 但它实现了目标。

我仍然不知道如何在 Tikz 的 foreach 循环中更改变量的值。似乎已计算的常数必须输入到循环中。可以使用这些常量进行数学运算,以计算矩形、直线等的 X 和 Y。

但是...在下面的代码中,我确实可以控制垂直网格因子、水平网格因子和跨越一行的文本的行高;我还完成了以统一高度居中时间标签。我甚至可以跨越公元前广告边界......(只需在输入中使用任何公元前日期的负数即可)。

感谢 Sandy G 的建议。这个建议是最终解决方案的关键,因为文本锚定在中心,并在给定的阈值处自动执行换行 - 这确实简化了很多!

我的解决方案不是定义宏 - 更像是复制和粘贴;但我确实有一个顶部部分来控制变量。

对于感兴趣的人,这里有代码:

\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{math} % to store vars 
\definecolor{shadecolor}{RGB}{212,233,249}
\definecolor{dkshadecolor}{RGB}{122,145,159}

\begin{document}

\noindent\scalebox{0.70}{
\begin{tikzpicture}
    % define some variable for readability below
    \tikzmath{
              \eventwidth = 13;
              \hfact = 1.2; 
              \vfact = 0.9;            
              \numTopLabels = 2;
              \capsulOffset = 1;
              \nlabels = 9;
              \labelrise = 0.25;
              \datestart = 10;
              \dateincr = 10; 
              \lastrow = 19;  
               }. % \lastrow needs to be manually set to last record's \rowend below. Might be better named "ychartheight".

% I think a few of the vars above ended up not being used.  I left them in just in case, and have not tested deleting them, numTopLabels is one that I think is not used; capsuleOffset is handy for situations where the math is correct, but off by a grid-unit due to timeline start between BC and AD.  set it to zero for more standard cases  

               
    % Top Labels
    % yeah, this could probably be placed into a loop - but it was easy enough 
    \node[anchor=base] at (0*\hfact,\labelrise){\textsf{\textbf{\scriptsize 10 \textsubscript{B.C.}}}};    
    \node[anchor=base] at (1*\hfact,\labelrise){\textsf{\textbf{\scriptsize 1  \textsubscript{A.D.}}}};     
    \node[anchor=base] at (2*\hfact,\labelrise){\textsf{\textbf{\scriptsize 10 }}};         
    \node[anchor=base] at (3*\hfact,\labelrise){\textsf{\textbf{\scriptsize 20 }}};         
    \node[anchor=base] at (4*\hfact,\labelrise){\textsf{\textbf{\scriptsize 30 }}};         
    \node[anchor=base] at (5*\hfact,\labelrise){\textsf{\textbf{\scriptsize 40 }}};         
    \node[anchor=base] at (6*\hfact,\labelrise){\textsf{\textbf{\scriptsize 50 }}};         
    \node[anchor=base] at (7*\hfact,\labelrise){\textsf{\textbf{\scriptsize 60 }}};         
    \node[anchor=base] at (8*\hfact,\labelrise){\textsf{\textbf{\scriptsize 70 }}}; 
      
    % Rows 
    
    % data:  timea / timeb / rowstart / rowend / text describing event / (the next record's rowstart needs to be last record's rowend ... which are used to control a row's height . ) 
    
    \foreach [var=\timea, var=\timeb, var=\rowstart, var=\rowend, var=\event, count=\n] in {   
         -6/-6/0/1/John the Baptist is born (6 \textsubscript{B.C.}),
         -5/-5/1/2/Jesus is born (5 \textsubscript{B.C.}),
         -4/-4/2/3.5/Jesus' family flees to Egypt; Herod the Great dies; Jesus' family goes to Nazareth (4 \textsubscript{B.C.}),
         8/8/3.5/4.5/Jesus (age 12) talks with teachers in the temple (\textsubscript{A.D.} 8\textsuperscript{*}),
         8/30/4.5/5.5/Jesus works as a carpenter in Nazareth (8\textsuperscript{*}--28\slash 30),
         28/29/5.5/6.5/John the Baptist begins his ministry (28\slash 29),
         28/30/6.5/7.5/Jesus begins his ministry; Peter becomes a disciple of Jesus (28\slash 30),
         30/33/7.5/8.5/Jesus is crucified and resurrected (33 [or 30])\textsuperscript{\textdagger},
         44/47/8.5/10.5/{``John, whose other name was Mark'', joins Paul and Barnabus's party for their famine-relief visit to Jerusalem; Mark accompanies Barnabus and Paul on part of the first missionary journey (44--47\textsuperscript{*})},
         48/51/10.5/11.5/Barnabus takes John Mark to Cyprus (48\slash 49--51\textsuperscript{*}),
         50/54/11.5/12.5/John Mark meets with Peter in Rome (50\slash 54),
         53/54/12.5/13.5/Gospel according to Mark written (53--55\textsuperscript{*}),
         60/62/13.5/15/{Paul, under house arrest in Rome, summons Mark, who serves as his delegate to Asia Minor (60--62\textsuperscript{*})},
         62/63/15/16/{Peter, in Rome, writes 1 Peter; Mark is with him (62--63\textsuperscript{*})},
         64/67/16/17/Peter is martyred in Rome (64--67\textsuperscript{*}),
         67/67/17/18/The church flees to Pella (67\textsuperscript{*}),
         70/70/18/19/Destruction of Jerusalem temple (70)
         } {
        
                                                        
        % compute alternating \rowcolor variable                                                
        \pgfmathsetmacro{\rowcolor}{\ifodd\n"shadecolor"\else"white"\fi}
        
        % row stripes      
        \fill[color=\rowcolor] (-\eventwidth, -\rowstart*\vfact) 
                               rectangle 
                               ( {(\nlabels)*\hfact},{(-\rowend)*\vfact});
                               
        % the horizontal grid lines                       
        \draw[dkshadecolor](-\eventwidth, -\rowstart*\vfact)--( {(\nlabels)*\hfact},-\rowstart*\vfact);
         
        % the time marks (capsules; the rounded rectangles) 
        \fill[dkshadecolor,rounded corners=1.55mm]   (   
                                                        { ( (\timea-\datestart+\dateincr) * \hfact/\dateincr ) + \capsulOffset*\hfact - 1.1/\dateincr*\hfact}, 
                                                       -{ \rowstart*\vfact + (\rowstart-\rowend)*0.5*\vfact - .15 } 
                                                    ) 
                                                    rectangle 
                                                    (   
                                                        { ( (\timeb-\datestart+\dateincr) * \hfact/\dateincr ) + \capsulOffset*\hfact + 1.1/\dateincr*\hfact},        
                                                       -{\rowstart*\vfact + (\rowstart-\rowend)*0.5*\vfact + .15 } 
                                                    );
       % the time-event text                                              
       \node[anchor=east, right, text width=12cm] at 
       (-\eventwidth + 0.3,  -{\rowstart*\vfact + (\rowstart-\rowend)*0.5*\vfact  }
       ) 
       {\textsf{\event}};

    }
     
    % manually draw last horizontal line
    \draw[dkshadecolor](-\eventwidth, -\lastrow*\vfact)--( {(\nlabels)*\hfact},-\lastrow*\vfact);  
    
    % vertical grid lines
    \draw[ultra thin, gray](-\eventwidth,-0)--(-\eventwidth,-\lastrow*\vfact);          % left-most vertical line 
     
    \foreach \m in {0,...,\nlabels}{                                           % remaining vertical grid lines
          \draw[gray]( (\m*\hfact, 0) -- (\m*\hfact,-\lastrow*\vfact);
    }


\end{tikzpicture}
}



\end{document}

相关内容