我想定义一个带有日期的集合 chemistryclasses={2021-05-25,2021-06-01,2021-06-08,2021-06-15,2021-06-22,2021-06-29,2021-07-06,2021-07-13},然后我希望代码在 tikz-calendar 中绘制相应的日期。在下面的 MWE 中,我可以做到这一点。但是,我想使例程自动化。编写所有这些很乏味if (equals=2021-05-25)
。目前,我使用 Python 编写 .tex 文件。它读取带有日期的 CSV 文件并生成 .tex 文件。但我正在考虑一个全 LaTeX 解决方案。我尝试了类似
\foreach \x in {2021-05-25,2021-06-01,2021-06-08,2021-06-15,2021-06-22,2021-06-29,2021-07-06,2021-07-13} {%
if (equals=\x) {\node [fill=yellow,draw,regular polygon,regular polygon sides=4] {};}
}
但它不起作用。那么我如何在 LaTeX 中自动化这些事情呢?一个好的工作流程是:
1)将日期写入文件中
2)LaTeX 读取日期并保存到变量
3)LaTeX生成日历。
梅威瑟:
\documentclass[12pt]{article}
\usepackage{hyperref}
\hypersetup{bookmarks=true,colorlinks=true,citecolor=blue}
\usepackage{tikz}
\usetikzlibrary{positioning,calc,calendar,shapes.geometric}
% =============
% = TColorBox =
% =============
\usepackage[most]{tcolorbox}
\tcbuselibrary{breakable}
\tcbset{left=4mm,sharpish corners,colback=white}
% ============
% = Calendar =
% ============
\newcommand{\calrow}[1]{
\node[anchor=base,xshift=0.5ex](mon){M}; % Shift first weekday
\node[base right=0.1em of mon](tue){T};
\node[base right=0.0em of tue](wed){W};
\node[base right=0.0em of wed](thu){T};
\node[base right=0.1em of thu](fri){F};
\node[base right=0.2em of fri](sat){S};
\node[base right=0.2em of sat](sun){S};
\node[black,above=0.1em of thu]{\textbf{#1}};}
\newcommand{\calperiod}[1]{%
\calendar (month-#1)[dates=2021-#1-01 to 2021-#1-last,
every day/.style={anchor=base}, % Center days
day text={\%d=},rounded corners=0,
anchor=base,text height=1ex,text depth=-0.5ex] % Make node placement easier
if(Sunday) [red]
\teachingdays;
}
\newcommand{\teachingdays}{
if (equals=2021-05-11) {\node [fill=yellow,draw,regular polygon,regular polygon sides=4] {};}
if (equals=2021-05-18) {\node [fill=yellow,draw,regular polygon,regular polygon sides=4] {};}
if (equals=2021-05-25) {\node [fill=yellow,draw,regular polygon,regular polygon sides=4] {};}
if (equals=2021-06-01) {\node [fill=yellow,draw,regular polygon,regular polygon sides=4] {};}
if (equals=2021-06-08) {\node [fill=yellow,draw,regular polygon,regular polygon sides=4] {};}
if (equals=2021-06-15) {\node [fill=yellow,draw,regular polygon,regular polygon sides=4] {};}
if (equals=2021-06-22) {\node [fill=yellow,draw,regular polygon,regular polygon sides=4] {};}
if (equals=2021-06-29) {\node [fill=yellow,draw,regular polygon,regular polygon sides=4] {};}
if (equals=2021-07-06) {\node [fill=yellow,draw,regular polygon,regular polygon sides=4] {};}
if (equals=2021-07-13) {\node [fill=yellow,draw,regular polygon,regular polygon sides=4] {};}
if (equals=2021-05-11) [blue]
if (equals=2021-05-18) [blue]
if (equals=2021-05-25) [blue]
if (equals=2021-06-01) [blue]
if (equals=2021-06-08) [blue]
if (equals=2021-06-15) [blue]
if (equals=2021-06-22) [blue]
if (equals=2021-06-29) [blue]
if (equals=2021-07-06) [blue]
if (equals=2021-07-13) [blue]
}
\newcommand{\generatehyperlinks}{
\node [hyperlink node=data01,draw=none,regular polygon,regular polygon sides=4] at (month-05-2021-05-11) {};
\node [hyperlink node=data02,draw=none,regular polygon,regular polygon sides=4] at (month-05-2021-05-18) {};
\node [hyperlink node=data03,draw=none,regular polygon,regular polygon sides=4] at (month-05-2021-05-25) {};
\node [hyperlink node=data04,draw=none,regular polygon,regular polygon sides=4] at (month-06-2021-06-01) {};
\node [hyperlink node=data05,draw=none,regular polygon,regular polygon sides=4] at (month-06-2021-06-08) {};
\node [hyperlink node=data06,draw=none,regular polygon,regular polygon sides=4] at (month-06-2021-06-15) {};
\node [hyperlink node=data07,draw=none,regular polygon,regular polygon sides=4] at (month-06-2021-06-22) {};
\node [hyperlink node=data08,draw=none,regular polygon,regular polygon sides=4] at (month-06-2021-06-29) {};
\node [hyperlink node=data09,draw=none,regular polygon,regular polygon sides=4] at (month-07-2021-07-06) {};
\node [hyperlink node=data10,draw=none,regular polygon,regular polygon sides=4] at (month-07-2021-07-13) {};
}
\tikzset{
hyperlink node/.style={
alias=sourcenode,
append after command={
let \p1 = (sourcenode.north west),
\p2=(sourcenode.south east),
\n1={\x2-\x1},
\n2={\y1-\y2} in
node [inner sep=0pt, outer sep=0pt,anchor=north west,at=(\p1)] {\hyperlink{#1}{\XeTeXLinkBox{\phantom{\rule{\n1}{\n2}}}}}
%xelatex needs \XeTeXLinkBox, won't create a link unless it
%finds text --- rules don't work without \XeTeXLinkBox.
%Still builds correctly with pdflatex and lualatex
}
}
}
\linespread{1.3}
\begin{document}
% ============
% = Calendar =
% ============
\begin{tikzpicture}[every calendar/.style={week list}]
\matrix[%
row 1/.style={black,node distance=.3ex},%
row 3/.style={black,node distance=.3ex},
column sep=1ex,draw=none]{%
% first row: week day and month
\calrow{May} & \calrow{June} & \calrow{July} \\
% second row: calendar
\calperiod{05} & \calperiod{06} & \calperiod{07} \\
};
\generatehyperlinks
\end{tikzpicture}
\newpage
\begin{itemize}
\item \hypertarget{data01}{01}
\item \hypertarget{data02}{02}
\item \hypertarget{data03}{03}
\item \hypertarget{data04}{04}
\item \hypertarget{data05}{05}
\item \hypertarget{data06}{06}
\item \hypertarget{data07}{07}
\item \hypertarget{data08}{08}
\item \hypertarget{data09}{09}
\item \hypertarget{data10}{10}
\end{itemize}
\end{document}
答案1
写下这些内容是很乏味的
if (equals=2021-05-25)
。
那么就不要。看一下/pgf/calendar/equals-strip
将参数作为#1/#2
并转发#1
到的键equals
。后面的第二部分/
仅用于将\item
s 放在后面。
我们可以使用扩展后的列表\teachingdays
并将其作为列表输入到equals-strip
:
if (equals-strip/.list/.expand once=\teachingdays) [teaching day]
那么宏\teachingdays
可以简单地为:
\newcommand*\teachingdays{%
2021-05-11/Intro,
2021-05-18/Basics I,
2021-05-25/Basics II,
…
}
这应该会使使用calendar
TikZ/PGF 库变得更加容易。
代码
\documentclass[12pt]{article}
\usepackage{hyperref}
\hypersetup{colorlinks=true, citecolor=blue}
\usepackage{tikz}
\usetikzlibrary{calc,calendar}
%%% Shorthand w- for Weekday
\expandafter\def\csname pgfcalendar@shorthand@w-\endcsname{\ifcase\pgfcalendarcurrentweekday M\or T\or W \or T\or F\else S\fi}
%%% equal key that strips /<text>
\pgfqkeys{/pgf/calendar}{equals-strip/.style args={#1/#2}{equals={#1}}}
%%% A simple parser for <year>-<month>-<day> so we can use shorthands outside of a calendar
\def\pgfcalendarsimpleparse#1-#2-#3\relax{%
\def\pgfcalendarcurrentyear{#1}%
\def\pgfcalendarcurrentmonth{#2}%
\def\pgfcalendarcurrentday{#3}}
%%% hyperling node
\tikzset{
hyperlink node/.style={
alias=@hyper,
append after command={
let \p1 = (@hyper.north west),
\p2 = (@hyper.south east),
\n1 = {\x2-\x1}, \n2 = {\y1-\y2} in
node [inner sep=+0pt, outer sep=+0pt, anchor=center, at=(@hyper)] {\hyperlink{ref-#1}{\XeTeXLinkBox{\phantom{\rule{\n1}{\n2}}}}}}}}
\newcommand*{\calrow}[1]{\node[draw,black, minimum width=7*\csname tikz@lib@cal@xshift\endcsname]{\textbf{#1}};}
\newcommand{\calperiod}[1]{%
\calendar [
dates=2021-#1-01 to 2021-#1-last,
day text={\%d=},
%
% we name every weekday node (even though we only need the Thursday)
weekday node/.style={
black, name=weekday-\pgfcalendarcurrentmonth-\pgfcalendarcurrentweekday},
%
% teaching day, include hyperlink node based on the date
teaching day/.style={
days={text=blue, fill=yellow, hyperlink node=\pgfcalendarcurrentyear-\pgfcalendarcurrentmonth-\pgfcalendarcurrentday}}]
%
% standard stuff
%
if (Saturday) [red!50!black]
if (Sunday) [red]
%
% the first day of the month is in the upmost row,
% let's place the weekday above it and align it properly
% the name @firstweekday can be referenced later
%
if (day of month=1) [days={append after command={
node [anchor=base east, at={(\tikzlastnode.base east)}, alias=@firstweekday,
yshift=\csname tikz@lib@cal@yshift\endcsname, weekday node/.try] {\%w-}}}]
%
% for all other days 2 to 7 we place the weekday text similar but we use the
% the first placed weekday text to make sure we align it at the same height
%
if (day of month=2, day of month=3, day of month=4, day of month=5, day of month=6, day of month=7) [days={append after command={
node [anchor=base east, at={(@firstweekday.base east-|\tikzlastnode.base east)}, weekday node/.try] {\%w-}}}]
%
% and go
%
if (equals-strip/.list/.expand once=\teachingdays) [teaching day]
;
}
\newcommand*\teachingdays{%
2021-05-11/Intro,
2021-05-18/Basics I,
2021-05-25/Basics II,
2021-06-01/And,
2021-06-08/Much,
2021-06-15/More,
2021-06-22/Stuff,
2021-06-29/To Do,
2021-07-06/In,
2021-07-13/Class}
\linespread{1.3}
\begin{document}\noindent
\begin{tikzpicture}[every calendar/.style={week list}]
\matrix[column sep=1.5ex]{%
\calperiod{05} & \calperiod{06} & \calperiod{07} \\
};
\foreach \mon/\t in {05/May, 06/Jun, 07/Jul}
\node[anchor=south, yshift=2ex, at=(weekday-\mon-3)] {\textbf{\t}};
\end{tikzpicture}
\pagebreak
\setlength{\labelwidth}{4em}
\begin{itemize}
\foreach \target/\name[/utils/exec=\let\%\pgfcalendarshorthand] in \teachingdays {
\expandafter\pgfcalendarsimpleparse\target\relax
\item[\%m. \%d= \%y-] \hypertarget{ref-\target}{\name}}
\end{itemize}
\end{document}