Calendrier des phases de la Lune

Un calendrier des phases de la Lune, avec le pourcentage de zone éclairée visible.

Le module Python Skyfield (éphémérides astronomiques) permet de calculer l’angle de phase entre le Soleil, la Lune et la Terre, à une date donnée, ainsi que la fraction éclairée du disque lunaire vu depuis la Terre.

Voici un exemple de ce qu’on peut en faire :

Les pourcentages sont donnés pour minuit UTC, et arrondis à l’entier.

Pour chaque jour, à partir du pourcentage d’éclairement, je trace :

  • un disque blanc en arrière-plan
  • un demi-disque noir (soit à gauche soit à droite, selon l’angle de phase)
  • une ellipse traçant le terminateur (limite ombre/lumière). Cette ellipse est soit noire, soit blanche, selon l’angle de phase.

On peut montrer simplement que si p est le pourcentage d’éclairement, et b le demi-petit axe de l’ellipse, on a b = R * (1 – 2p), R étant le rayon du disque lunaire.

Le demi-disque noir est tracé à gauche si l’angle de phase est inférieur à 180°, à droite sinon.

L’ellipse est blanche si l’angle de phase est compris entre 90 et 270°, noire sinon.

Pour générer ce document avec un script Python, j’utilise aussi les modules :

  • matplotlib (tracé de graphiques)
  • datetime (gestion des dates)
  • locale (écriture en français pour les noms du mois et des jours)
  • la fonction ceil du module math, pour arrondir à l’entier supérieur.

Il vous faudra installer ces modules pour exécuter le script Python.

J’ai décidé de bien m’embêter en faisant en sorte que le lundi soit sur la première colonne. Oui, oui, cela vous paraît évident, mais croyez-moi j’ai passé un moment à regretter cette idée… Il faut donc calculer le nombre de cases (axes) en tenant compte du jour de la semaine où tombe le premier jour du mois, et du nombre de jours dans le mois.

En ce qui concerne les graphiques, l’idée est de calculer le nombre de lignes nécessaires, de créer un axe par jour, puis d’effacer les axes inutiles (ceux du début de la semaine avant le jour 1, et ceux après le dernier jour du mois.

Selon les mois, il y a donc 5 ou 6 lignes, ce qui modifie la taille des axes et l’espace entre eux. Il faut faire quelques ajustements sur les marges et les espacements, avec la commande plt.subplots_adjust().


Voici les fonctions que j’ai créées :

def nb_jours(mois,annee):
    """
    renvoie le nombre de jours dans le mois.
    """
    jour_un = dt.datetime(annee, mois, 1)
    if mois != 12:
        jour_mois_suivant = dt.datetime(annee, mois+1, 1)
    else:
        jour_mois_suivant = dt.datetime(annee+1, 1, 1)

    return (jour_mois_suivant - jour_un).days
def formatage_axe(axe):
    """
    met en forme l'axe
    """
    axe.set_aspect('equal')
    axe.set_xlim(-1,1)
    axe.set_ylim(-1,1)
    axe.set_xticks([])
    axe.set_yticks([])
def efface(axe):
    """
    efface un axe inutile.
    """
    axe.axis('off')
def pourcentage(t):
    """
    Parameters
    ----------
    t : TYPE        : date Skyfield

    Renvoie le pourcentage de la partie éclairée de la Lune (entre 0 et 1)
    -------
    """

    e = earth.at(t)
    s = e.observe(sun).apparent()
    m = e.observe(moon).apparent()
    
    _, slon, _ = s.frame_latlon(ecliptic_frame)
    _, mlon, _ = m.frame_latlon(ecliptic_frame)
    phase = (mlon.degrees - slon.degrees) % 360.0

    return phase, m.fraction_illuminated(sun)
def lune(p,phase, axe):
    """
    Parameters
    ----------
    p : TYPE float
        DESCRIPTION : pourcentage de la phase lunaire (0 à 1)
    phase : angle de phase (0 à 360°)
    axe : TYPE : axe où faire le tracé

    Trace l'apparence de la Lune (cercle, ellipse, moitié sombre)

    """
    b = R * (1-2 * p) # demi-petit axe de l'ellipse du terminateur

    limbe = patches.Circle((0,0),R,facecolor='white',edgecolor='k',zorder=0,
                           linewidth=0.5)
    axe.add_patch(limbe)
    
    if phase <= 180:
        moitie_noire = patches.Wedge((0,0), R, 90, 270, color='k',ec='None')
    else:
        moitie_noire = patches.Wedge((0,0), R, -90, 90, color='k',ec='None')

    axe.add_patch(moitie_noire)

    if phase > 90 and phase < 270:
        couleur_ellipse = 'white'
    else:
        couleur_ellipse = 'k'
    ellipse = patches.Ellipse((0,0), 2 * b, 2 * R,color=couleur_ellipse,lw=0)
    axe.add_patch(ellipse)

    # affichage du pourcentage :
    axe.text(0.98,0.98,f'{round(p*100)} %',ha='right',va='top',fontsize=14,
             c = 'orangered',
             transform=axe.transAxes)
def numero_j(J,axe):
    """
    Affiche le numéro du jour
    """
    axe.text(0.98,0.02,J,c='royalblue',fontsize=22,ha='right',fontweight='bold',
             transform=axe.transAxes)

Vous trouverez ci-dessous le script Python en téléchargement. Il suffit de modifier le mois et l’année pour générer le calendrier souhaité.

Soyez le premier à commenter

Laisser un commentaire