Créer un calendrier à l’aide de Python et de LaTeX (le langage de programmation) n’est pas si compliqué que cela quand on se penche sur la question sérieusement.
C’est un peu long, mais pas compliqué.
Créer un calendrier à l’aide de Python et LaTeX: quel module choisir ?
Il existe un module Python dédié aux calendriers: le bien nommé calendar.
La première fois que je m’y suis penché, c’est à dire ce jour, j’ai trouvé la documentation bien merdique… Aucun exemple n’est donné, et je n’aime pas ça car je suis obligé de lire tout ce qui est écrit, et j’étais pressé! Donc ça, c’est un mauvais point, mais peu importe!
Comme je suis motivé, je me mets à lire et m’aperçois au final que je n’ai pas à lire beaucoup. En effet, itermonthdates
semble convenir à mes attentes. C’est un itérateur que l’on peut parcourir.
Créer un calendrier à l’aide de Python et LaTeX: la structure du fichier tex
Il fallait avant tout que je réfléchisse à l’apparence du calendrier que je voulais. Un truc tout simple: une grille avec le mois affiché dessous (par exemple) et les dates dans chaque coin de case, en bas à droite (par exemple).
C’est assez rudimentaire, mais c’est suffisant pour avoir une base sur laquelle travailler.
Créer un calendrier à l’aide de Python et LaTeX: la fonction Python
Je vais générer un fichier \(\LaTeX\) puis le compiler pour obtenir un PDF.
Je vais utiliser TiKZ pour la solution graphique car je suis plus à l’aise avec celle-ci qu’avec PSTricks par exemple.
Je voudrais une fonction de la forme:
>>> calendarTEX(6,2022)
Bien entendu, il faudra inclure des options pour customiser ce calendrier.
Alors voilà ce que cela donne:
from calendar import Calendar import os.path def calendarTEX( current_month , current_year , hauteur = '2cm' , largeur = '3cm' , calendarGridStyle = 'line width = 0.5pt , draw = black', calendarBgStyle = 'fill = white', monthStyle = 'text = black , font = \\Huge\\bfseries', dayStyle = 'text = black , font = \\Large\\bfseries', dayInStyle = 'text = black , above left', dayOutStyle = 'text = gray , above left', preambuleTEX= '', out = True, name = None): """ current_month : mois souhaité current_year : année souhaitée options : dictionnaire contenant : ....... (hauteur) la hauteur des cases (par défaut : 2cm) ....... (largeur) la largeur des cases (par défaut : 3cm) ....... (calendarGridStyle) le style TiKZ de la grille (traits) ....... (calendarBgStyle) le style TiKZ du fond ....... (monthStyle) le style TiKZ du mois écris en bas ....... (dayStyle) le style TiKZ dans lequel doivent être écris les jours en en-tête des colonnes ....... (dayInStyle) le style TiKZ de la date du jour ....... (dayOutStyle) le style TiKZ de la date du jour si le jour est en-dehors du mois (gris par défaut) ....... (preambuleTEX) l'éventuel préambule au fichier LaTeX ....... (out) (True|False) pour savoir s'il faut générer un PDF/fichier TEX ....... (name) le nom du fichier s'il faut en générer un """ C = Calendar() nb_lines = sum(1 for _ in C.itermonthdates(current_year,current_month) ) // 7 days = [ 'Lundi' , 'Mardi' , 'Mercredi' , 'Jeudi' , 'Vendredi' , 'Samedi' , 'Dimanche' ] months = [ 'janvier' , 'février' , 'mars' , 'avril' , 'mai' , 'juin' , 'juillet', 'août' , 'septembre' , 'octobre' , 'novembre' , 'décembre' ] tex = "\\documentclass{standalone}\n" tex += "\\usepackage{tikz}\n" tex += "\\usetikzlibrary{calc}\n" tex += "\\newlength{\\hauteur}\n" tex += preambuleTEX tex += "\\newlength{\\largeur}\n" tex += "\\setlength{\\hauteur}{"+hauteur+"}\n" tex += "\\setlength{\\largeur}{"+largeur+"}\n" tex += "\\begin{document}\n" tex += "\\tikzset{month/.style = { "+monthStyle+"}}%\n" tex += "\\tikzset{day/.style = { "+dayStyle+"}}%\n" tex += "\\tikzset{calendarGrid/.style = { "+calendarGridStyle+"}}%\n" tex += "\\tikzset{calendarBG/.style = { "+calendarBgStyle+"}}%\n" tex += "\\begin{tikzpicture}\n" tex += "\\node[month] at (10.5,-1) {"+months[current_month-1].upper()+" "+ str(current_year) +"};\n" tex += f"\\filldraw[calendarBG] (0,0) rectangle (7*\\largeur,{nb_lines}*\\hauteur);\n" tex += f"\\filldraw[calendarGrid] (0,0) grid[xstep = \\largeur , ystep = \\hauteur] (7*\\largeur,{nb_lines}*\\hauteur);\n" for d in days: tex += "\\node[day] at ({\\largeur/2+\\largeur*"+str(days.index(d))+"},{"+str(nb_lines)+"*\\hauteur+0.5cm}) {"+d+"};\n" column , line = 1, nb_lines-1 for d in C.itermonthdates(current_year,current_month): if d.month != current_month: styleday = dayOutStyle else: styleday = dayInStyle tex += "\\node["+styleday+"] at (\\largeur*" + str(column) + " , \\hauteur*" + str(line) + " ) {"+str(d.day)+"};\n" column += 1 if column == 8: column = 1 line -= 1 tex += "\\end{tikzpicture}\n" tex += "\\end{document}" if out: if name == None: file = "calendar-"+str(current_year)+str(current_month)+".tex" else: file = name + ".tex" if os.path.exists(file): os.remove(file) fichier = open(file , "x") # "x" pour la création et l'écriture fichier.write(tex) fichier.close() instructions = "pdflatex " + file os.system(instructions) readpdf = "START " + file[:-4] + ".pdf" os.system(readpdf) else: return tex
Les options de la fonction sont:
def calendarTEX( current_month , current_year , hauteur = '2cm' , largeur = '3cm' , calendarGridStyle = 'line width = 0.5pt , draw = black', calendarBgStyle = 'fill = white', monthStyle = 'text = black , font = \\Huge\\bfseries', dayStyle = 'text = black , font = \\Large\\bfseries', dayInStyle = 'text = black , above left', dayOutStyle = 'text = gray , above left', preambuleTEX= '', out = True, name = None): """ current_month : mois souhaité current_year : année souhaitée options : dictionnaire contenant : ....... (hauteur) la hauteur des cases (par défaut : 2cm) ....... (largeur) la largeur des cases (par défaut : 3cm) ....... (calendarGridStyle) le style TiKZ de la grille (traits) ....... (calendarBgStyle) le style TiKZ du fond ....... (monthStyle) le style TiKZ du mois écris en bas ....... (dayStyle) le style TiKZ dans lequel doivent être écris les jours en en-tête des colonnes ....... (dayInStyle) le style TiKZ de la date du jour ....... (dayOutStyle) le style TiKZ de la date du jour si le jour est en-dehors du mois (gris par défaut) ....... (preambuleTEX) l'éventuel préambule au fichier LaTeX ....... (out) (True|False) pour savoir s'il faut générer un PDF/fichier TEX ....... (name) le nom du fichier s'il faut en générer un """
Un exemple customisé
calendarTEX(7 , 2022 ,
preambuleTEX = "\\usepackage{emerald}\\usetikzlibrary{fadings}\n",
calendarGridStyle = 'line width=1pt, draw = blue, path fading = south',
calendarBgStyle = 'line width=0pt,fill=white,draw=white',
monthStyle = 'text = blue!50!black , font = \\ECFJD\\Huge\\bfseries, rounded corners = 3mm, draw = blue!50!black , line width = 3pt, fill = blue!20',
dayStyle = 'text = green!50!black , font = \\ECFJD\\Large , rounded corners = 2mm , draw = green!50!black , fill = green!20',
dayInStyle = 'text = orange , above left , font = \\ECFJD',
dayOutStyle = 'text = gray!50!orange , above left , opacity = 0.5 , font = \\ECFJD')
calendarTEX(7 , 2022 ,
preambuleTEX = "\\usepackage{emerald}\\usetikzlibrary{fadings}\n\\tikzfading[name=fade right, left color=transparent!0, right color=transparent!100]",
calendarBgStyle = 'blue!20, path fading = fade right',
calendarGridStyle = 'blue!50!black, line width=1pt',
monthStyle = 'text = blue!50!black , font = \\ECFJD\\Huge\\bfseries, rounded corners = 3mm, draw = blue!50!black , line width = 3pt, fill = blue!20, inner sep = 3mm',
dayStyle = 'text = green!50!black , font = \\ECFJD\\Large , rounded corners = 2mm , draw = green!50!black , fill = green!20',
dayInStyle = 'text = orange , above left , font = \\ECFJD',
dayOutStyle = 'text = gray!50!orange , above left , opacity = 0.5 , font = \\ECFJD')