TransWikia.com

Remove last comma in list of birthdays in each day of calendar (tikz)

TeX - LaTeX Asked by Stefan Drückler on April 2, 2021

I am adopting this calendar (https://texample.net/tikz/examples/birthday-calendar/) to my needs, but I have a problem I cannot solve on my own.

In each single day grid, how can I get rid of the last comma in the list of birthdays (blue top line) and the list of special days (green bottom line)?

enter image description here

Bonus question: Is it possible that a second line of birthdays starts right of the day number?

This is my code:

% Birthday calendar
% Author: Hakon Malmedal
documentclass[fontsize=15pt]{scrartcl}
usepackage[german]{babel}
usepackage[utf8]{inputenc}
usepackage[T1]{fontenc}
usepackage{lmodern}
usepackage[paperheight=70cm,paperwidth=50cm,margin=0mm,heightrounded]{geometry}
%usepackage[margin=1cm,a4paper,landscape]{geometry}
pagestyle{empty}
usepackage{graphicx}
usepackage{tikz}
%%%<
usepackage{verbatim}
%%%>
begin{comment}
:Title: Birthday calendar
:Tags: Calendar library;Calendars
:Author: Hakon Malmedal
:Slug: birthday-calendar
end{comment}
usetikzlibrary{calendar,fit}
usepackage{expl3,xparse}

%from https://tex.stackexchange.com/questions/140948/tikz-calendar-and-conditional-tests
makeatletter
defpgfcalendar@matchesfalse{globalletifpgfcalendar@matchesiffalse}
defpgfcalendar@matchestrue{globalletifpgfcalendar@matchesiftrue}
pgfcalendar@matchesfalse
pgfqkeys{/pgf/calendar}{and/.code 2 args={%
    begingroup
      ifdate{#1}{ifdate{#2}{pgfcalendar@matchestrue}{}}{}%
    endgroup
    ifpgfcalendar@matchespgfcalendarmatchestruepgfcalendar@matchesfalsefi}}
makeatother


%% Adapted from pgf source
defpgfcalendarmonthname#1{%
  translate{ifcase#1or Januaror Februaror Märzor Aprilor
    Maior Junior Julior Augustor Septemberor Oktoberor
    Novemberor Dezemberfi}%
}

%% Adapted from http://tex.stackexchange.com/a/10199/4771
makeatletter%
tikzoption{day headings}{tikzstyle{day heading}=[#1]}
tikzstyle{day heading}=[]
tikzstyle{day letter headings}=[
    execute before day scope={ ifdate{equals=01-01}{%
      pgfmathsetlength{pgf@ya}{tikz@lib@cal@yshift}%
      pgfmathsetlengthpgf@xa{tikz@lib@cal@xshift}%
      pgftransformyshift{-pgf@ya}
      foreach d/l in {0/Montag,1/Dienstag,2/Mittwoch,3/Donnerstag,%
                         4/Freitag,5/Samstag,6/Sonntag} {
        pgf@xa=dpgf@xa%
        pgftransformxshift{pgf@xa-cellwidth/2}%
        pgftransformyshift{2pgf@ya-2pt}%
        node[below=0.5ex,day heading, inner sep=2.5mm,font=Large]{l};%
      }
    }{}%
  }%
]
makeatother%
%% End

ExplSyntaxOn

%% Adapted from http://tex.stackexchange.com/a/56214/4771
%%
% first of all we define the user level commands
NewDocumentCommand{addtext}{ m }{ bdaycal_input_add_text:n { #1 } }
NewDocumentCommand{addbirthday}{ mm }{ bdaycal_input_add_birthday:nn { #1 } { #2 } }
NewDocumentCommand{addbirthdaydead}{ mm }{ bdaycal_input_add_birthday_dead:nn { #1 } { #2 } }
NewDocumentCommand{adddateofdeath}{ mm }{ bdaycal_input_add_date_of_death:nn { #1 } { #2 } }
NewDocumentCommand{addweek}{ m }{ bdaycal_input_add_week:n { #1 } }
NewDocumentCommand{showtext}{ }{ bdaycal_output_direct_text: }
NewDocumentCommand{showbirthdays}{ }{ bdaycal_output_direct_birthday: }

% allocate variable:
% a sequence for global storage of the inputs;
seq_new:N g_bdaycal_input_seq_text
seq_new:N g_bdaycal_input_seq_birthday

% store globally an input in the sequence
cs_new:Npn bdaycal_input_add_text:n #1
 {
  seq_gput_right:Nn g_bdaycal_input_seq_text { #1 }
 }

cs_new:Npn bdaycal_input_add_birthday:nn #1 #2
 {
  seq_gput_right:Nn g_bdaycal_input_seq_birthday { #1 ~ int_to_arabic:n
    { pgfcalendarifdateyear - #2 }}
 }

cs_new:Npn bdaycal_input_add_birthday_dead:nn #1 #2
 {
  seq_gput_right:Nn g_bdaycal_input_seq_birthday {( #1 ~ int_to_arabic:n
    { pgfcalendarifdateyear - #2 })}
 }

cs_new:Npn bdaycal_input_add_date_of_death:nn #1 #2
 {
  seq_gput_right:Nn g_bdaycal_input_seq_birthday {dag  #1 ~ #2}
 }

% how to output in direct order; we simply do a mapping function calling
% bdaycal_print:n after incrementing the counter
cs_new_protected:Npn bdaycal_output_direct_text:
 {
  seq_map_inline:Nn g_bdaycal_input_seq_text
   {
    int_gincr:N g_tmpa_int
    % int_compare:nNnT {g_tmpa_int}={1}{}%vor dem ersten Eintrag
    ##1
    int_compare:nNnF {g_tmpa_int}={seq_count:N g_bdaycal_input_seq_text}{,~}%am Ende jedes Eintrags, außer nach dem letzten
   }
  seq_gclear:N g_bdaycal_input_seq_text
 }

cs_new_protected:Npn bdaycal_output_direct_birthday:
 {
  seq_map_inline:Nn g_bdaycal_input_seq_birthday
   {
    int_gincr:N g_tmpa_int
    % int_compare:nNnT {g_tmpa_int}={1}{}%vor dem ersten Eintrag
    ##1
    int_compare:nNnF {g_tmpa_int}={seq_count:N g_bdaycal_input_seq_birthday}{,~}%am Ende jedes Eintrags, außer nach dem letzten
   }
  seq_gclear:N g_bdaycal_input_seq_birthday
 }
%% End

%% Knuth's AoCP, vol 1, 2nd ed, pp 155--156
int_new:N l_easter_Y_int
int_new:N l_easter_G_int
int_new:N l_easter_C_int
int_new:N l_easter_X_int
int_new:N l_easter_Z_int
int_new:N l_easter_D_int
int_new:N l_easter_E_int
int_new:N l_easter_N_int
int_new:N l_easter_M_int
int_new:N l_easter_julian_day_int

cs_new:Nn easter_sunday:n {

  int_set:Nn l_easter_Y_int { #1 }

  int_set:Nn l_easter_G_int {
    int_mod:nn { l_easter_Y_int } { 19 } + 1
  }

  int_set:Nn l_easter_C_int {
    int_div_truncate:nn { l_easter_Y_int } { 100 } + 1
  }

  int_set:Nn l_easter_X_int {
    int_div_truncate:nn { 3 * l_easter_C_int } { 4 } - 12
  }

  int_set:Nn l_easter_Z_int {
    int_div_truncate:nn { 8 * l_easter_C_int + 5 } { 25 } - 5
  }

  int_set:Nn l_easter_D_int {
    int_div_truncate:nn { 5 * l_easter_Y_int } { 4 } - l_easter_X_int - 10
  }

  int_set:Nn l_easter_E_int {
    int_mod:nn { 11 * l_easter_G_int + 20 + l_easter_Z_int
      - l_easter_X_int } { 30 }
  }

  % int_mod:nn behaves strangely.
  int_compare:nNnT { l_easter_E_int } < { 0 }
  {
    int_add:Nn l_easter_E_int { 30 }
  }

  int_compare:nNnTF { l_easter_E_int } = { 25 }
  { % true
    int_compare:nNnT { l_easter_G_int } > { 11 }
    { % true
      int_incr:N l_easter_E_int
    }
  }
  { % false
    int_compare:nNnT { l_easter_E_int } = { 24 }
    { % true
      int_incr:N l_easter_E_int
    }
  }

  int_set:Nn l_easter_N_int { 44 - l_easter_E_int }

  int_compare:nNnT { l_easter_N_int } < { 21 }
  { % true
    int_add:Nn l_easter_N_int { 30 }
  }

  int_add:Nn l_easter_N_int {
    7 - int_mod:nn { l_easter_D_int + l_easter_N_int } { 7 }
  }

  int_compare:nNnTF { l_easter_N_int } > { 31 }
  { % true
    int_sub:Nn l_easter_N_int { 31 }
    int_set:Nn l_easter_M_int { 4 } % April
  }
  { % false
    int_set:Nn l_easter_M_int { 3 } % March
  }

  pgfcalendardatetojulian { l_easter_Y_int -
     l_easter_M_int - l_easter_N_int
  } { l_easter_julian_day_int }

}

pgfkeys{/pgf/calendar/Easter/.default = 0}
pgfkeys{/pgf/calendar/Easter/.code =
  {
    easter_sunday:n { pgfcalendarifdateyear }
    int_compare:nNnT { pgfcalendarifdatejulian }
    =  {l_easter_julian_day_int + #1}
    { pgfcalendarmatchestrue }
  }
}

int_new:N l_advent_Y_int
int_new:N l_advent_xmas_julian_day_int
int_new:N l_advent_xmas_week_day_int
int_new:N l_advent_julian_day_int

cs_new:Nn advent_sunday:n {

  int_set:Nn l_advent_Y_int { #1 }

  pgfcalendardatetojulian { l_advent_Y_int - 12 - 25 } {
    l_advent_xmas_julian_day_int }

  pgfcalendarjuliantoweekday { l_advent_xmas_julian_day_int } {
    l_advent_xmas_week_day_int }

  int_set:Nn l_advent_julian_day_int {
    l_advent_xmas_julian_day_int - l_advent_xmas_week_day_int - 22 }

}

ExplSyntaxOff

pgfkeys{/tikz/observance/.code =
  {
    addtext{#1}
  }
}

pgfkeys{/tikz/anniversary/.code 2 args=addbirthday{#1}{#2}}
pgfkeys{/tikz/anniversary_dead/.code 2 args=addbirthdaydead{#1}{#2}}
pgfkeys{/tikz/date_of_death/.code 2 args=adddateofdeath{#1}{#2}}

pgfkeys{/tikz/day code =
  {
 node (lower right) at (-1pt,1pt){};
 node (upper left) at (-cellwidth +1pt,cellheight -1pt){};
    node (day of month) at (-cellwidth + 3pt,0.3cellheight) [above right,font=bfseriesLarge] {tikzdaytext};

    node (birthdays) at (-cellwidth +2pt,cellheight -2pt)
   [below right,align=left,text width=cellwidth-3pt,
    font=tinybfseries,blue] {showbirthdays};

    node (name of day) at (-cellwidth +2pt,8pt)
   [below right,align=left,text width=cellwidth-pgflinewidth,
    font=tiny,green] {showtext};

    node[draw,
          fit=(lower right) (upper left),
          inner sep=0mm] {};
  }
}

pgfkeys{/tikz/inner sep = 0pt}
pgfkeys{/tikz/day xshift=cellwidth}
pgfkeys{/tikz/day yshift=cellheight}
pgfkeys{/tikz/month yshift=0mm}

newlength{cellheight}
setlength{cellheight}{13mm}
newlength{cellwidth}
setlength{cellwidth}{68mm}

begin{document}

centering

begin{tikzpicture}[thick]
  calendar[dates=2021-01-01 to 2021-12-last,
            week list,
           day headings={font=footnotesize},
            day letter headings
]
  if (%Sunday,
%      Easter=-3, % Maundy Thursday
      Easter=-2, % Good Friday
      Easter,    % Easter Sunday
      Easter=1,  % Easter Monday
      Easter=39, % Feast of the Ascension
      Easter=49, % Pentecost
      Easter=50, % Whit Monday
      equals=01-01,%Neujahr
      equals=03-08,%Internationaler Frauentag (nur Berlin)
      equals=05-01,%Tag der Arbeit
      equals=10-03,%Tag der deutschen Einheit
      equals=12-25,%1. und 2. Weihnachtsfeiertag
      equals=12-26) [red]
  if (Easter=-48) [observance=Rosenmontag]
  if (Easter=-46) [observance=Aschermittwoch]
  if (Easter=-7) [observance=Palmsonntag]
  if (Easter=-3) [observance=Gründonnerstag]
  if (Easter=-2) [observance=Karfreitag]
  if (Easter) [observance=Ostersonntag]
  if (Easter=1) [observance=Ostermontag]
  if (Easter=39) [observance=Christi Himmelfahrt]
  if (Easter=39) [observance=Vatertag]
  if (Easter=49) [observance=Pfingstsonntag]
  if (Easter=50) [observance=Pfingstmontag]
  if (Easter=59) [observance=Fronleichnam]
  if (equals=01-01) [observance=Neujahr]
  if (equals=01-06) [observance=Heilige drei Könige]
  if (equals=02-14) [observance=Valentinstag]
  if (equals=03-08) [observance=Internationaler Frauentag]
  if (equals=05-01) [observance=Tag der Arbeit]
  if (equals=05-08) [observance=Tag der Befreiung / Ende WWII 1945]
  if (equals=08-15) [observance=Mariä Himmelfahrt]
  if (equals=10-03) [observance=Tag der deutschen Einheit 1990]
  if (equals=10-31) [observance=Reformationstag]
  if (equals=10-31) [observance=Halloween]
  if (equals=11-01) [observance=Allerheiligen]
  if (equals=11-09) [observance=Fall der Mauer 1989]
  if (equals=11-09) [observance=Novemberprogrome 1938]
  if (equals=12-24) [observance=Heilig Abend]
  if (equals=12-25) [observance=1. Weihnachtstag]
  if (equals=12-26) [observance=2. Weihnachtstag]
  if (equals=12-31) [observance=Silvester]
  if (and={between=11-16 and 11-22}{Wednesday}) [observance=Buß- und Bettag]
  if (and={between=11-13 and 11-19}{Sunday}) [observance=Volkstrauertag]
  if (and={between=11-20 and 11-26}{Sunday}) [observance=Totensonntag]
  if (and={between=11-27 and 12-03}{Sunday}) [observance=1. Advent]
  if (and={between=12-04 and 12-10}{Sunday}) [observance=2. Advent]
  if (and={between=12-11 and 12-17}{Sunday}) [observance=3. Advent]
  if (and={between=12-18 and 12-24}{Sunday}) [observance=4. Advent]
  if (and={between=03-25 and 03-31}{Sunday}) [observance=Beginn Sommerzeit]%letzter Sonntag im März
  if (and={between=10-25 and 10-31}{Sunday}) [observance=Ende Sommerzeit]%letzter Sonntag im Oktober
  if (and={between=05-08 and 05-14}{Sunday}) [observance=Muttertag]%2. Sonntag im Mai
  if (equals=12-06) [observance=Nikolaus]
  if (equals=07-17) [anniversary={John Smith}{2018}]
  if (equals=12-07) [anniversary={John Smith}{1982}]
  if (equals=01-04) [anniversary={John Smith}{1983}]
  if (equals=01-18) [anniversary={John Smith}{1985}]
  if (equals=10-23) [anniversary={John Smith}{1986}]
  if (equals=08-29) [anniversary={John Smith}{1954}]
  if (equals=10-14) [anniversary={John Smith}{1954}]
  if (equals=03-01) [anniversary_dead={John Smith}{1923}]
  if (equals=05-24) [date_of_death={John Smith}{2011}]
  if (equals=12-01) [anniversary={John Smith}{1927}]
  if (equals=08-29) [anniversary={John Smith}{2013}]
  if (equals=08-29) [anniversary={John Smith}{1981}]
;
end{tikzpicture}

end{document}

One Answer

The following code solves the problem:

int_new:N g_counter_int
cs_new_protected:Npn bdaycal_output_direct_text:
 {
  seq_map_inline:Nn g_bdaycal_input_seq_text
   {
 int_add:Nn g_counter_int { 1 }
    ##1
    int_compare:nNnF {g_counter_int}={seq_count:N g_bdaycal_input_seq_text}{,~}
   }
  seq_gclear:N g_bdaycal_input_seq_text
 int_set:Nn g_counter_int {0}
 }

cs_new_protected:Npn bdaycal_output_direct_birthday:
 {
  seq_map_inline:Nn g_bdaycal_input_seq_birthday
   {
     int_add:Nn g_counter_int { 1 }
    ##1
    int_compare:nNnF {g_counter_int}={seq_count:N g_bdaycal_input_seq_birthday}{,~}
   }
  seq_gclear:N g_bdaycal_input_seq_birthday
 int_set:Nn g_counter_int {0}
 }

Correct answer by Stefan Drückler on April 2, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP