在 Tikz 日历中过滤日期

在 Tikz 日历中过滤日期

语境

我有很多(约 20+ 个)日期(或范围)出于兴趣 已派遣超过 5 年calendar

浪费了太多空间!

在此处输入图片描述

我的问题

日期很少的日历有点帮助(给“无用”的日期上色),但是我怎样才能在下面过滤日历,只有当其中使用日期时我才能获得月份?

在上面的例子中,日历从 2018 年 5 月到 2022 年 8 月。它对应 52 行,52 个月。然而,这 52 行中有 44 行是“空的”,因为我输入的日期都没有显示在那里。因此,我想按月显示相同的内容,但我只能得到 8 行月份。

May18
Jun18
Jul18
Jul19
Jul20
Jul21
Jul22
Aug22

更接近于 在此处输入图片描述

平均能量损失

\documentclass[12pt,tikz]{standalone}
%\usepackage[french]{babel}
%\usepackage[french]{translator}
\usetikzlibrary{calendar}

\makeatletter

\pgfkeys{/pgf/calendar/start of year/.code={%
    \ifnum\pgfcalendarifdateday=1\relax%
        \ifnum\pgfcalendarifdatemonth=1\relax\pgfcalendarmatchestrue\fi%
    \fi%
}}%

% Define our own style
\tikzset{week list sunday/.style={execute at begin day scope={%
        % Because for TikZ Monday is 0 and Sunday is 6,
        % we can't directly use \pgfcalendercurrentweekday,
        % but instead we define \c@pgf@counta (basically) as:
        % (\pgfcalendercurrentweekday + 1) % 7
        \pgfmathsetlength\pgf@x{\tikz@lib@cal@xshift}%
        \ifnum\pgfcalendarcurrentweekday=6
            \c@pgf@counta=0
        \else
            \c@pgf@counta=\pgfcalendarcurrentweekday
            \advance\c@pgf@counta by 1
        \fi
        \pgf@x=\c@pgf@counta\pgf@x
        % Shift to the right position for the day.
        \pgftransformxshift{\pgf@x}
    }},
    tikz@lib@cal@width=7}

% New style for drawing the year, it is always drawn
% for January

\tikzset{year label left/.style={    
    execute before day scope={
        \ifdate{start of year}{
            \drawyear
            }{}
    },
    % Right align
    every year/.append style={
        anchor=east,
        xshift=-6em
    }},
    N_date/.style={circle,very thick,draw=red}
    }


% This actually draws the year.
\newcommand{\drawyear}{
    \pgfmathsetlength{\pgf@x}{\tikz@lib@cal@xshift}%
    \pgftransformxshift{-\pgf@x}
    % \tikzyearcode is defined by default
    \tikzyearcode
    \pgfmathsetlength{\pgf@x}{\tikz@lib@cal@xshift}%
    \pgftransformxshift{\pgf@x}
}

\makeatother

% I define my dates of interest


\def\SCal{2018-05-01}
\def\ECal{2022-08-last}
\def\SNego{2018-05-11}
\def\ENego{2018-06-11}
\def\Deal{2018-06-12}
\def\PreStrike{2018-06-12}
\def\Issue{2018-06-27}
\def\SComm{2018-06-28}
\def\EComm{2018-07-28}
\def\Strike{2018-07-29}
\def\ConstatOne{2019-07-29}
\def\ConstatTwo{2020-07-29}
\def\ConstatThree{2021-07-29}
\def\ConstatFour{2022-07-29}
\def\ConstatFive{2022-07-29}
\def\FinalValue{2022-07-29}
\def\Maturity{2022-08-10}


\begin{document}

\begin{tikzpicture}
        
    \calendar (CalPS)[
        dates=\SCal to \ECal,
        year label left,
        every year/.append style={font=\Large\sffamily\bfseries,
        orange!50!black},
        month list, 
        month label left, 
        month yshift=1.25em,
        days={
            gray!20,
            text width=width("00"),
            align=center,
            %       inner xsep=
            %       .5*\csname tikz@lib@cal@xshift\endcsname-.5*\csname tikz@text@width\endcsname,
            %       inner ysep=.5*\csname tikz@lib@cal@month@yshift\endcsname-.5*height("0")
        }
    ]
    %---------- Phase 1 ------------------------------
    if (between=\SNego and \ENego)  [days={fill=green!50}]
    %---------- Phase 2 ------------------------------
    if (equals=\Deal) [days={fill=green!80,rectangle}, red]
    %---------- Phase 3------------------------------
    if (equals=\PreStrike) [days={fill=red!80,rectangle}]
    %---------- Phase 4 ------------------------------
    if (equals=\Issue) [days={fill=blue!80,rectangle}]
    %---------- Phase 5------------------------------
    if (between=\SComm and \EComm)  [days={fill=green!90}]
    %---------- Phase 6------------------------------
    if (equals=\Strike) [days={fill=red!80,rectangle}]
    %---------- Phase 7 ------------------------------
    if (    equals=\ConstatOne,
    equals=\ConstatTwo,
    equals=\ConstatThree,
    equals=\ConstatFour,
    equals=\ConstatFive,
    ) [days={fill=orange!80,rectangle}]
    %---------- Phase 8 ------------------------------
    if (equals=\FinalValue) [days={fill=red!80,rectangle}]
    %---------- Phase 9 ------------------------------
    if (equals=\Maturity) [days={fill=blue!80,rectangle}]
    ;
\end{tikzpicture}

\end{document}

注意:是不是只有我一个人注意到calendarTexSE 上的大多数例子都很旧了Tikzstyle

答案1

我没有看到图书馆有任何界面可以跳过日期,尤其是不if适用的月份。您需要更改\ifdate以收集所有日期,以便在月份/年份开始时查找这些日期。

我的解决方案是检查当前月份/年份是否在要跳过的日期列表中,然后直接跳到该月份/年份的最后一天,而不对跳过的月份/年份的第一天执行任何操作。

我将其重写month listmonth list with skipped months,它接受两个参数:

  1. 整整一年要跳过,
  2. 需要跳过的月份

我没有使用年份,也没有测试过,所以祝你好运。月份以列表格式给出,因此无需手动提供后续月份:

month list with skipped months={}{
  2018:8 to 12,
  2019:1 to  6,
  2019:8 to 12,
  2020:1 to  6,
  2020:8 to 12,
  2021:2 to  6, % kept January in to test a proper start of the year
  2021:8 to 12,
  2022:1 to  6
},

我们需要在方向,因为我们必须抵消在月初进行的降档,而我们在检查跳过时并没有这样做。

我不喜欢它,但它是我能想到的最干净的办法。

代码

every month/.append code=\ifdate{skipped month}{\pgfkeysalso{shape=coordinate}}{},

用于隐藏跳过的月份名称。

代码

\documentclass[12pt,tikz,convert]{standalone}
\usetikzlibrary{calendar}

\pgfset{
  calendar/start of year/.code={% check for start of year
    \ifnum\pgfcalendarifdateday=1\relax%
        \ifnum\pgfcalendarifdatemonth=1\relax\pgfcalendarmatchestrue\fi%
    \fi}}
\tikzset{% setting up the collections, used by month list with skipped months
  skipper/setup year skips/.style={
    /utils/exec=\def\listSkipYear{,},
    skipper/years/.list={#1}},
  skipper/years/.code=%
    \edef\listSkipYear{\listSkipYear#1,},
  skipper/setup month skips/.style={
    /utils/exec=\def\listSkipMonth{,},
    skipper/months/.list={#1}},
  skipper/months/.style args={#1:#2to#3}{
    skipper/@/.code=%
      \edef\listSkipMonth{\listSkipMonth#1-\ifnum##1<10 0\fi##1,},
    skipper/@/.list={#2,...,#3}},
}
\makeatletter
\pgfset{% \ifdate lookups for year or year-months
  calendar/skipped year/.code=%
    \edef\pgf@cal@temp{{,\pgfcalendarifdateyear,}{\listSkipYear}}%
    \expandafter\pgfutil@in@\pgf@cal@temp
    \let\ifpgfcalendarmatches\ifpgfutil@in@,
  calendar/skipped month/.code=%
    \edef\pgf@cal@temp
      {{,\pgfcalendarifdateyear-\pgfcalendarifdatemonth,}{\listSkipMonth}}%
    \expandafter\pgfutil@in@\pgf@cal@temp
    \let\ifpgfcalendarmatches\ifpgfutil@in@
}

\newif\ifSkipDay
\tikzset{
  month list with skipped months/.style 2 args={%
    skipper/setup year skips={#1},
    skipper/setup month skips={#2},
    every month/.append code=%
      \ifdate{skipped month}{\pgfkeysalso{shape=coordinate}}{},
    execute before day scope={%
      \SkipDayfalse
      \ifdate{day of month=1}{% do the test only on the first of the month
        \ifdate{skipped year}{% skip straight to the nye
          \pgfcalendardatetojulian
            {\pgfcalendarcurrentyear-12-31}\pgfcalendarcurrentjulian
          \SkipDaytrue
        }{%
          \ifdate{equals=\pgfcalendarbeginiso}{% start of the calendar is never skipped
            \drawyear % every first (even the very first) we shift down, counteract %
            \pgfmathsetlength{\pgf@y}{\tikz@lib@cal@month@yshift}%                  %
            \pgftransformyshift{+\pgf@y}%                                           %
            \begingroup % from original month list style %%%%%%%%%%%%%%%
              \c@pgf@counta=\pgfcalendarcurrentjulian%                 %
              \advance\c@pgf@counta by-\pgfcalendarcurrentday%         %
              \advance\c@pgf@counta by1\relax%                         %
              \pgfcalendarjuliantoweekday{\c@pgf@counta}{\c@pgf@countb}%
              \xdef\pgf@temp{\the\c@pgf@countb}%                       %
            \endgroup                                                  %
            \let\tikz@lib@cal@month@list@start=\pgf@temp%              %
          }{%
            \ifdate{start of year}{%
              \pgfmathsetlength{\pgf@y}{\tikz@lib@cal@month@yshift}%
              \pgftransformyshift{+-\pgf@y}%
              \drawyear % every first (even the very first) we shift down, counteract %
              \pgfmathsetlength{\pgf@y}{\tikz@lib@cal@month@yshift}%                  %
              \pgftransformyshift{+\pgf@y}%                                           %
            }{}%
          }%
          \ifdate{skipped month}{%
            \pgfcalendardatetojulian
              {\pgfcalendarcurrentyear-\pgfcalendarcurrentmonth-last}%
              \pgfcalendarcurrentjulian
            \SkipDaytrue
          }{}%
         }%
      }{}%
      %
      \ifSkipDay\else
        \ifdate{day of month=1}{% from original month list style %%%%%%%%%
          \pgfmathsetlength{\pgf@y}{\tikz@lib@cal@month@yshift}%         %
          \pgftransformyshift{+-\pgf@y}%                                 %
          \edef\tikz@lib@cal@month@list@start{\pgfcalendarcurrentweekday}%
        }{}%
      \fi
    },%
    execute at begin day scope={% from original month list style %
      \pgfmathsetlength\pgf@xa{\tikz@lib@cal@xshift}%            %
      \pgf@xb=\pgfcalendarcurrentday\pgf@xa%                     %
      \advance\pgf@xb by\tikz@lib@cal@month@list@start\pgf@xa%   %
      \advance\pgf@xb by-\pgf@xa\relax%                          %
      \pgftransformxshift{\pgf@xb}%                              %
    },                                                           %
    tikz@lib@cal@width=37                                        %
  },
}

% This actually draws the year.
\newcommand{\drawyear}{
    \pgfmathsetlength{\pgf@x}{\tikz@lib@cal@xshift}%
    \pgftransformxshift{-\pgf@x}
    % \tikzyearcode is defined by default
    \tikzyearcode
    \pgfmathsetlength{\pgf@x}{\tikz@lib@cal@xshift}%
    \pgftransformxshift{\pgf@x}
}
\makeatother

% I define my dates of interest
\def\SCal{2018-05-01}
\def\ECal{2022-08-last}
\def\SNego{2018-05-11}
\def\ENego{2018-06-11}
\def\Deal{2018-06-12}
\def\PreStrike{2018-06-12}
\def\Issue{2018-06-27}
\def\SComm{2018-06-28}
\def\EComm{2018-07-28}
\def\Strike{2018-07-29}
\def\ConstatOne{2019-07-29}
\def\ConstatTwo{2020-07-29}
\def\ConstatThree{2021-07-29}
\def\ConstatFour{2022-07-29}
\def\ConstatFive{2022-07-29}
\def\FinalValue{2022-07-29}
\def\Maturity{2022-08-10}


\begin{document}
\begin{tikzpicture}
    \calendar (CalPS)[
        dates=\SCal to \ECal,
        every year/.append style={
          font=\sffamily\bfseries, orange!50!black, anchor=base east, xshift=-6em},
        month list with skipped months={}{
          2018:8 to 12,
          2019:1 to  6,
          2019:8 to 12,
          2020:1 to  6,
          2020:8 to 12,
          2021:2 to  6,
          2021:8 to 12,
          2022:1 to  6
        },
        month label left, 
        month yshift=1.25em,
        days={gray!20, text width=width("00"), align=center}
    ]
    %---------- Phase 1 ------------------------------
    if (between=\SNego and \ENego)  [days={fill=green!50}]
    %---------- Phase 2 ------------------------------
    if (equals=\Deal) [days={fill=green!80,rectangle}, red]
    %---------- Phase 3------------------------------
    if (equals=\PreStrike) [days={fill=red!80,rectangle}]
    %---------- Phase 4 ------------------------------
    if (equals=\Issue) [days={fill=blue!80,rectangle}]
    %---------- Phase 5------------------------------
    if (between=\SComm and \EComm)  [days={fill=green!90}]
    %---------- Phase 6------------------------------
    if (equals=\Strike) [days={fill=red!80,rectangle}]
    %---------- Phase 7 ------------------------------
    if (equals=\ConstatOne,
        equals=\ConstatTwo,
        equals=\ConstatThree,
        equals=\ConstatFour,
        equals=\ConstatFive,
    ) [days={fill=orange!80,rectangle}]
    %---------- Phase 8 ------------------------------
    if (equals=\FinalValue) [days={fill=red!80,rectangle}]
    %---------- Phase 9 ------------------------------
    if (equals=\Maturity) [days={fill=blue!80,rectangle}];
\end{tikzpicture}
\end{document}

输出

在此处输入图片描述

相关内容