![TikZ 日历的 \foreach 中的前导零](https://linux22.com/image/315495/TikZ%20%E6%97%A5%E5%8E%86%E7%9A%84%20%5Cforeach%20%E4%B8%AD%E7%9A%84%E5%89%8D%E5%AF%BC%E9%9B%B6.png)
TikZcalendar
库为每一天创建一个名为 的节点。但是从 到有(<name>-<year>-<month>-<day>)
一个前导零,也就是说,要使用第一天的节点,我们必须通过 来引用它。<day>
1
9
(<name>-<year>-<month>-01)
由于我尝试使用\foreach
循环连接一些节点,因此在处理前导零时遇到了麻烦。例如,
! Package pgf Error: No shape named cal-2015-01-2 is known.
! Package pgf Error: No shape named cal-2015-09-4 is known.
但如果我插入前导零,(cal-2015-09-0\x.north east)
错误就会变为
! Package pgf Error: No shape named cal-2015-01-016 is known.
因此,我认为只有两位数的整数可以解决问题。
我希望有与下面第一个日历相同的两条虚线,但可以将其转换为分隔其他周末。
平均能量损失
\documentclass[11pt]{report}
\usepackage[margin=1cm,landscape,a4paper]{geometry}
\usepackage{tikz}
\usetikzlibrary{calendar,calc,math}
\begin{document}
\begin{tikzpicture}%
[every day/.style={anchor=mid},
every node/.style={inner sep=2pt,rectangle,thick}
]
\calendar (cal)%
[dates=\the\year-1-1 to \the\year-12-last,
month list,
month label left,
month text=\textcolor{black}{\%mt},
month yshift=1.7em,
black
]
if (Saturday) [blue]
if (Sunday) [red]
;
\draw[dashed]
( $(cal-\the\year-01-02.north east)!.5!(cal-\the\year-01-03.north west)$ ) --
( $(cal-\the\year-12-04.south east)!.5!(cal-\the\year-12-05.south west)$ )
%%
( $(cal-\the\year-01-04.north east)!.5!(cal-\the\year-01-05.north west)$ ) --
( $(cal-\the\year-12-06.south east)!.5!(cal-\the\year-12-07.south west)$ )
;
\end{tikzpicture}
\vfill\noindent\hrulefill\vfill
\begin{tikzpicture}%
[every day/.style={anchor=mid},
every node/.style={inner sep=2pt,rectangle,thick}
]
\calendar (cal)%
[dates=\the\year-1-1 to \the\year-12-last,
month list,
month label left,
month text=\textcolor{black}{\%mt},
month yshift=1.7em,
black
]
if (Saturday) [blue]
if (Sunday) [red]
;
%% use only one foreach below
%% the first has problems with leading zeros on day numbers
%%
\foreach \i in {0,7,...,31}{% should be tested if is >31
%\foreach \i in {16,23,...,31}{% should be tested if is >31
%%
%% January 02 and 04 are starting days
\tikzmath{integer \xaa; \xaa = 2+\i;}
\tikzmath{integer \xab; \xab = \xaa+1;}
\tikzmath{integer \xba; \xba = 4+\i;}
\tikzmath{integer \xbb; \xbb = \xba+1;}
%% December 04 and 06 are ending days
\tikzmath{integer \yaa; \yaa = 4+\i;}
\tikzmath{integer \yab; \yab = \yaa+1;}
\tikzmath{integer \yba; \yba = 6+\i;}
\tikzmath{integer \ybb; \ybb = \yba+1;}
\draw[dashed]
( $(cal-\the\year-01-\xaa.north east)!.5!(cal-\the\year-01-\xab.north west)$ ) --
( $(cal-\the\year-12-\xba.south east)!.5!(cal-\the\year-12-\xbb.south west)$ )
%%
( $(cal-\the\year-01-\yaa.north east)!.5!(cal-\the\year-01-\yab.north west)$ ) --
( $(cal-\the\year-12-\yba.south east)!.5!(cal-\the\year-12-\ybb.south west)$ )
;
}
\end{tikzpicture}
\end{document}
答案1
更新
整个问题的优雅解决方案:
这是另一个简化的解决方案,它避免了两位数问题,并添加了 OP 最终请求的最后两列。这个想法是日历列之间有一段默认距离。这里,对于 11pt 文档,它是。我们通过明确设置选项并将其传递给日历命令来3.5ex
确保它是。3.5ex
day xshift=3.5ex
接下来,我们执行一个\foreach
循环来绘制两条垂直线,并在一周后重复此操作,如下xshift
所示7*3.5ex
:
\foreach \i in {0,...,4}{%
\pgfmathparse{3.5*7*\i} \edef\w{\pgfmathresult}
\pgfmathparse{\w+2*3.5} \edef\x{\pgfmathresult}
\draw[dashed]
([xshift=\w ex]$(cal-\the\year-01-02.north east)!.5!(cal-\the\year-01-03.north west)$) --
([xshift=\w ex]$(cal-\the\year-12-04.south east)!.5!(cal-\the\year-12-05.south west)$)
([xshift=\x ex]$(cal-\the\year-01-02.north east)!.5!(cal-\the\year-01-03.north west)$) --
([xshift=\x ex]$(cal-\the\year-12-04.south east)!.5!(cal-\the\year-12-05.south west)$);
}
该循环将所有垂直线绘制成如下形式:
现在总的简化代码如下:
\documentclass[11pt]{report}
\usepackage[margin=1cm,landscape,a4paper]{geometry}
\usepackage{tikz}
\usetikzlibrary{calendar,calc,math}
\begin{document}
\begin{tikzpicture}%
[every day/.style={anchor=mid},
every node/.style={inner sep=2pt,rectangle,thick}
]
\calendar (cal)%
[dates=\the\year-1-1 to \the\year-12-last,
month list,
month label left,
month text=\textcolor{black}{\%mt},
month yshift=1.7em,
black
]
if (Saturday) [blue]
if (Sunday) [red];
\draw[dashed]
( $(cal-\the\year-01-02.north east)!.5!(cal-\the\year-01-03.north west)$ ) --
( $(cal-\the\year-12-04.south east)!.5!(cal-\the\year-12-05.south west)$ )
%%
( $(cal-\the\year-01-04.north east)!.5!(cal-\the\year-01-05.north west)$ ) --
( $(cal-\the\year-12-06.south east)!.5!(cal-\the\year-12-07.south west)$ );
\end{tikzpicture}
\vfill\noindent\hrulefill\vfill
\begin{tikzpicture}%
[every day/.style={anchor=mid},
every node/.style={inner sep=2pt,rectangle,thick}
]
\calendar[day xshift=3.5ex](cal)%
[dates=\the\year-1-1 to \the\year-12-last,
month list,
month label left,
month text=\textcolor{black}{\%mt},
month yshift=1.7em,
black
]
if (Saturday) [blue]
if (Sunday) [red];
% use only one foreach below
% the first has problems with leading zeros on day numbers
\foreach \i in {0,...,4}{%
\pgfmathparse{3.5*7*\i} \edef\w{\pgfmathresult}
\pgfmathparse{\w+2*3.5} \edef\x{\pgfmathresult}
\draw[dashed]
([xshift=\w ex]$(cal-\the\year-01-02.north east)!.5!(cal-\the\year-01-03.north west)$) --
([xshift=\w ex]$(cal-\the\year-12-04.south east)!.5!(cal-\the\year-12-05.south west)$)
%
([xshift=\x ex]$(cal-\the\year-01-02.north east)!.5!(cal-\the\year-01-03.north west)$) --
([xshift=\x ex]$(cal-\the\year-12-04.south east)!.5!(cal-\the\year-12-05.south west)$);
}
\end{tikzpicture}
\end{document}
解决方案 1
受@clemens提到的错误消息的启发,一个简单的解决方案可能是避免超过31天。为了实现这一点,观察最大的节点号\ybb = \yba+1
,它等于\i+7
因为\yba=\i+6
。后者的值应该最大化为31。所以,,max{ \i }= 24
这仅仅意味着条件:
\ifnum\i<25\draw ... \else\fi
以下是第二种解决方案的完整代码(其结果与上述相同):
\documentclass[11pt]{report}
\usepackage[margin=1cm,landscape,a4paper]{geometry}
\usepackage{tikz}
\usetikzlibrary{calendar,calc,math}
\makeatletter
\let\twodigits\two@digits
\makeatother
\begin{document}
\begin{tikzpicture}%
[every day/.style={anchor=mid},
every node/.style={inner sep=2pt,rectangle,thick}
]
\calendar (cal)%
[dates=\the\year-1-1 to \the\year-12-last,
month list,
month label left,
month text=\textcolor{black}{\%mt},
month yshift=1.7em,
black
]
if (Saturday) [blue]
if (Sunday) [red];
\draw[dashed]
( $(cal-\the\year-01-02.north east)!.5!(cal-\the\year-01-03.north west)$ ) --
( $(cal-\the\year-12-04.south east)!.5!(cal-\the\year-12-05.south west)$ )
%%
( $(cal-\the\year-01-04.north east)!.5!(cal-\the\year-01-05.north west)$ ) --
( $(cal-\the\year-12-06.south east)!.5!(cal-\the\year-12-07.south west)$ );
\end{tikzpicture}
\vfill\noindent\hrulefill\vfill
\begin{tikzpicture}%
[every day/.style={anchor=mid},
every node/.style={inner sep=2pt,rectangle,thick}
]
\calendar(cal)%
[dates=\the\year-1-1 to \the\year-12-last,
month list,
month label left,
month text=\textcolor{black}{\%mt},
month yshift=1.7em,
black
]
if (Saturday) [blue]
if (Sunday) [red];
%% use only one foreach below
%% the first has problems with leading zeros on day numbers
%%
\foreach \i in {0,7,...,31}{% should be tested if is >31
%\foreach \i in {16,23,...,31}{% should be tested if is >31
%%
%% January 02 and 04 are starting days
\tikzmath{integer \xaa; \xaa = 2+\i;}
\tikzmath{integer \xab; \xab = \xaa+1;}
\tikzmath{integer \xba; \xba = 4+\i;}
\tikzmath{integer \xbb; \xbb = \xba+1;}
%% December 04 and 06 are ending days
\tikzmath{integer \yaa; \yaa = 4+\i;}
\tikzmath{integer \yab; \yab = \yaa+1;}
\tikzmath{integer \yba; \yba = 6+\i;}
\tikzmath{integer \ybb; \ybb = \yba+1;}
\ifnum\i<25
\draw[dashed]
($(cal-\the\year-01-\twodigits\xaa.north east)!.5!(cal-\the\year-01-\twodigits\xab.north west)$) --
($(cal-\the\year-12-\twodigits\xba.south east)!.5!(cal-\the\year-12-\twodigits\xbb.south west)$)
%%
($(cal-\the\year-01-\twodigits\yaa.north east)!.5!(cal-\the\year-01-\twodigits\yab.north west)$) --
($(cal-\the\year-12-\twodigits\yba.south east)!.5!(cal-\the\year-12-\twodigits\ybb.south west)$);
\else\fi
}
\end{tikzpicture}
\end{document}
答案2
LaTeX 有(可扩展的)函数\two@digits
,它接受一个整数作为输入,如果数字小于 10,则在前导 0 处添加。因此,你可以放置
\makeatletter
\let\twodigits\two@digits
\makeatother
在你的序言中的某个地方,然后使用
\draw[red]
($(cal-2015-09-\twodigits\x.north east)!.5!(cal-2015-09-05.north west)$)--
($(cal-2016-02-\twodigits\y.south east)!.5!(cal-2016-02-06.south west)$) ;
在你的第一个例子中
$\frac{\twodigits\i}{\twodigits\x}$
在你的第二个例子中。
编辑根据更新后的问题,代码部分如下:
\draw[dashed]
( $(cal-\the\year-01-\twodigits\xaa.north east)!.5!(cal-\the\year-01-\twodigits\xab.north west)$ ) --
( $(cal-\the\year-12-\twodigits\xba.south east)!.5!(cal-\the\year-12-\twodigits\xbb.south west)$ )
%%
( $(cal-\the\year-01-\twodigits\yaa.north east)!.5!(cal-\the\year-01-\twodigits\yab.north west)$ ) --
( $(cal-\the\year-12-\twodigits\yba.south east)!.5!(cal-\the\year-12-\twodigits\ybb.south west)$ )
;
顺便说一句:这仍然会产生错误
! Package pgf Error: No shape named cal-2015-12-32 is known.
但现在不是由于缺少零,而是因为4+\i
最终大于 31。