Calendrier des phases de la Lune – Python

Un code Python calcule les dates des phases, et les place dans un calendrier annuel.

Le module Ephem pour Python permet de calculer de nombreux paramètres astronomiques.

https://pypi.org/project/ephem/

https://rhodesmill.org/pyephem/tutorial.html

Pour exploiter ce module, il faut également d’avoir quelques notions sur la gestion des dates et du temps, avec le module datetime.

Voici le début du code :

#Ce programme calcule les dates des phases de la Lune au cours d'une année, et affiche un calendrier

import ephem#module d'éphémérides astronomiques
import matplotlib.pyplot as plt
import datetime#Gestion des dates
import matplotlib.font_manager#pour un caractère spécifique d'une police

#Récupération du caractère "Demi-Lune" dans la police DejaVuSans :
"""
ATTENTION : le chemin indiqué entre guillemets ci-dessous est celui de la police DeJaVuSans,
installée sur l'ordinateur.
Ce chemin doit  être adapté à votre ordinateur.
"""
path ='/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf'#chemin de cette police sur le disque
f0 = matplotlib.font_manager.FontProperties()
f0.set_file(path)

annee=2022#AU CHOIX DE L'UTILISATEUR

Les symboles de pleine lune (rond blanc) et de nouvelle lune (rond noir) sont facilement obtenus avec plt.scatter (nuage de points), mais pour les symboles des premier et dernier quartier, c’est autre chose : la police DeJaVuSans possède un tel caractère ; j’ai trouvé sur un forum une solution qui va chercher ce caractère dans le fichier de la police. L’inconvénient est qu’il faut indiquer dans le code le chemin complet de cette police sur l’ordinateur (à adapter selon votre installation).

Je définis ensuite 4 fonctions qui recherchent les dates des phases et affichent le symbole accompagné de la date abrégée :

#Définitions des fonction de recherche des phases, au cours d'un mois
def NouvelleLune(date_debut, date_fin):
    Date=date_debut
    while Date<date_fin:
        NL=ephem.next_new_moon(Date)#calcul de la prochaine date de la phase
        Date=ephem.localtime(NL)#conversion en temps local
        if Date<date_fin:
            Y=float(Date.strftime('%d'))#numéro du jour
            ax=axs[N-1]
            ax.scatter(0, -Y, c='k')#point noir
            ax.text(0.1, -Y, Date.strftime('%d %b'), va='center')

def PremierQuartier(date_debut, date_fin):
    Date=date_debut
    while Date<date_fin:
        PQ=ephem.next_first_quarter_moon(Date)#calcul de la prochaine date de la phase
        Date=ephem.localtime(PQ)#conversion en temps local
        if Date<date_fin:
            Y=float(Date.strftime('%d'))#numéro du jour
            ax=axs[N-1]
            ax.text(0, -Y, u'\u25D0', fontproperties=f0, ha='center', va='center')#symbole quartier de Lune
            ax.text(0.1, -Y, Date.strftime('%d %b'), va='center')

def PleinLune(date_debut, date_fin):
    Date=date_debut
    while Date<date_fin:
        PL=ephem.next_full_moon(Date)#calcul de la prochaine date de la phase
        Date=ephem.localtime(PL)#conversion en temps local
        if Date<date_fin:
            Y=float(Date.strftime('%d'))#numéro du jour
            ax=axs[N-1]
            ax.scatter(0,  -Y, c='w', edgecolor='k')#point blanc
            ax.text(0.1, -Y, Date.strftime('%d %b'), va='center')

def DernierQuartier(date_debut, date_fin):
    Date=date_debut
    while Date<date_fin:
        DQ=ephem.next_last_quarter_moon(Date)#calcul de la prochaine date de la phase
        Date=ephem.localtime(DQ)#conversion en temps local
        if Date<date_fin:
            Y=float(Date.strftime('%d'))#numéro du jour
            ax=axs[N-1]
            ax.text(0, -Y, u'\u25D0', fontproperties=f0, rotation=180, ha='center', va='center')#symbole quartier de Lune
            ax.text(0.1, -Y, Date.strftime('%d %b'), va='center')

La méthode Date.strftime(‘%d %b’) d’une date affiche une chaîne de caractère de la variable Date. Ici, %d est le numéro du jour, et %b le mois abrégé.

Les paramètres passés à ces fonctions sont les dates de début et de fin de mois.

Étant donné qu’une même phase peut parfois se produire deux mois par mois, il est nécessaire d’utiliser des fonctions ‘while’. Après avoir trouvé la première date après la date de début, la date trouvée fait office de nouvelle date de début. La seconde date trouvée est affichée si elle se trouve dans les limites du mois en cours.

La variable ‘Y’ prend la valeur du numéro du jour de la date trouvée. Elle sert de coordonnée verticale pour l’affichage du texte et du symbole. Les graphes vont de 0.5 à -32 en ordonnées, pour laisser la place d’écrire les 31 jours.

Ensuite vient la création de la figure et des graphes :

#Paramètres du graphique :
plt.rcParams["font.family"] = "Ubuntu"#ou autre police installée
plt.rcParams["font.size"] = 10#à adapter aux dimensions des axes

fig, axs=plt.subplots(nrows=2, ncols=6)#création d'une figure et de 12 axes (1 par mois)
#Les graphes forment une grille de 2 lignes et 6 colonnes
#on peut modifier le nombre de grilles et colonnes, pourvu que le produit fasse 12.
axs=axs.flatten()#pour accéder à chaque graphe par axs[N]
fig.set_size_inches(7, 6)#dimensions de la figure, en pouces
"""
En modifiant les dimensions de la figure, il faudra peut-être ajuster :
- la taille de la police
- les limites des axes en x et en y
Et réciproquement.
"""
plt.suptitle("Éphémérides de la lune en %i"%(annee), fontsize=16, color='royalblue', fontweight='bold')

Une commande crée simultanément la figure et une grille de 12 graphes pour les 12 mois de l’année. Là encore, une heureuse recherche sur un forum m’a fait découvrir la commande axs.flatten() : quelle que soit la forme de la grille (2×6, 3×4, 1×12), les 12 axes sont numérotés de 0 à 11, dans le sens de la lecture, afin qu’ensuite une simple commande ax=axs[N-1] identifie le graphe en cours.

Il reste ensuite à parcourir un par un les mois de l’année et les graphes de la grille, via une boucle ‘for’ :

for N in range(1, 12+1):#N : numéro du mois courant, de 1 à 12
    ax=axs[N-1]
    date_debut=datetime.datetime(annee, N, 1)
    ax.set_title(date_debut.strftime("%B"), fontsize=13)#nom complet du mois
    ax.set_xticks([])#suppression des graduations
    ax.set_yticks([])#suppression des graduations
    ax.set_ylim(-32, 0.5)#hauteur suffisante pour les listes de dates
    ax.set_xlim(-0.1, 0.5)#largeur suffisante pour le texte
    if N==12:
        date_fin=datetime.datetime(annee+1, 1, 1)
    else:
        date_fin=datetime.datetime(annee, N+1, 1)
    NouvelleLune(date_debut, date_fin)
    PremierQuartier(date_debut, date_fin)
    PleinLune(date_debut, date_fin)
    DernierQuartier(date_debut, date_fin)

On crée une variable date-debut pour le premier jour du mois courant.

La méthode date_debut.strftime(“%B”) extrait de cette date le nom complet du mois, affiché en titre du graphe.

On crée également une date de fin ; c’est logiquement la date de fin du mois, cependant :

  • j’ai choisi plutôt le premier jour du mois suivant (pas besoin d’avoir à gérer les mois de différentes longueurs).
  • pour décembre (N=12), il faut plutôt que ce soit le premier jour de l’année suivante, d’où deux cas différents, gérés par une condition avant d’appeler les fonctions des phases de la Lune.

Pour terminer : il reste à créer un fichier image et/ou PDF. Le nom du fichier est une chaîne de caractère. En Python, il est facile de concaténer les chaînes de caractères afin que le nom du fichier se termine par l’année choisie. str(annee) est la chaîne de caractère de l’année choisie.

plt.tight_layout()
NomFichier="ephemeridesLune"+str(annee)
#Le nom de fichier se terminera par l'année
fig.savefig(NomFichier+".png", dpi=200)#création d'un fichier image PNG
fig.savefig(NomFichier+".pdf")#création d'un fichier PDF
plt.show()

Avec le module datetime, pour afficher les noms des jours et des mois en français, il faut ajouter en début de code les deux lignes suivantes :

import locale
locale.setlocale(locale.LC_ALL, 'fr_FR.UTF-8')#dates en français

Le code Python complet (compressé) :

Soyez le premier à commenter

Laisser un commentaire