Positions héliocentriques des planètes (Python)

Où l’on contemple le ballet des planètes autour du Soleil.

Dans un précédent article, je proposais un code Python destiné à placer sur un diagramme polaire les positions héliocentriques des planètes, les données étant stockées dans un fichier d’éphémérides distinct.

Pour éviter d’avoir à télécharger au préalable les données calculées par des éphémérides, une solution est d’utiliser un module pour Python qui calcule lui-même ces données.

Le module PyEphem : dédié aux calculs d’éphémérides, que j’ai déjà utilisé pour construire un calendrier lunaire.

Le module Astropy : il semble extrêmement complet, et utilisé par des astronomes professionnels. Le pendant de cette polyvalence est une prise en main assez exigeante. Je ne m’y suis pas encore penché.

Le module Skyfield : conçu par l’auteur de PyEphem, et vraisemblablement destiné à le supplanter.

C’est Skyfield que j’ai utilisé ici, qu’il est nécessaire d’installer au préalable. Rendez-vous sur la page du module.

L’idée est de choisir facilement un intervalle de temps délimité par deux dates (époque), ainsi qu’un pas de calcul en nombre de jours.

Voici les modules à appeler en début de script :

import matplotlib.pyplot as plt
import numpy as np
import locale # règles locales (noms des mois)
from skyfield.api import load
from skyfield.framelib import ecliptic_frame

Définition des dates :

Le module Skyfield propose son propre système de génération de dates (uniques, ou en séries). Pour les personnes plus familiarisées avec le module Datetime (gestion de dates), la documentation Skyfield explique comment convertir une date d’un système à l’autre.

periode = ts.utc(2023, 4, range(1, 60, pasJours)) # année, n° mois, série de jours, qui peut même excéder 30 jours
# periode = ts.utc(2023, 4, range(1, 365, 15)) # exemple pour 1 an, tous les 15 jours

Je définis un dict, qui associe un nom de planète à une couleur. Je me suis basé sur les couleurs approximatives des planètes, tout en les choisissant assez différentes.

#Liste des couleurs par planète :
couleurs={
'Mercure':'gray',
'Vénus':'tan',
'Terre':'royalblue', 
'Mars':'orangered',
'Jupiter':'orange',
'Saturne':'goldenrod', 
'Uranus' : 'skyblue', 
'Neptune' : 'mediumblue'
}

Je définis plusieurs fonctions :

def coordonnees(planete, date): # calcule et renvoie la longitude écliptique (degrés) et la distance (UA)
    """
    planete : astre défini par Skyfield
    date : date ou série de dates Skyfield
    renvoie la longitude écliptique en radians, et la distance au Soleil en UA
    """
    lat, lon, distance = soleil.at(date).observe(planete).frame_latlon(ecliptic_frame)
    lon = lon.radians
    lon = angleComplem(lon) # si discontinuité de la longitude pendant la période
    distance = distance.au
    return lon, distance
def date_JMA(date): # renvoie une date Skyfield au format Jour Mois Année (string)
    return date.utc_strftime('%d %b %Y')
def trajectoire(planete, date):
    """
    planete : astre défini par Skyfield
    date : date ou série de dates définies par Skyfield
    Trace les positions de la planète sur le graphique.
    """
    long, dist = coordonnees(planete, date)
    couleur, nom = attributs_planete(planete)
    plt.scatter(long,dist,s=taillePoint, color=couleur, label=nom)
    plt.scatter(long[0],dist[0],s=taillePoint, color='black') # 1e position en noir
def attributs_planete(planete):
    """
    planete : astre défini par Skyfield
    Renvoie la couleur et le nom (string) de l'astre
    RANG est le rang de la planète dans la liste.
    """
    rang = liste_planetes.index(planete)
    couleur= list(couleurs.values())[rang]
    nom= list(couleurs.keys())[rang]
    return couleur, nom
def indicateur_planete(planete,date):
    """
    planete : astre défini par Skyfield
    date : periode définie par Skyfield
    Trace une flèche dirigée vers la position moyenne de la planète sur la période considérée.
    La flèche est légendée avec le nom de la planète.
    Cette représentation évite des problèmes d'échelle pour les planètes très lointaines.
    En supposant que l'époque considérée soit suffisamment courte pour que la longitude de ces planetes
    varie très peu.
    Attention : si durant l'époque considérée, la longitude de la planète prend des valeurs de part et d'autre de 0°,
    la discontinuité de la longitude va donner une moyenne fantaisiste.
    La fonction AngleComplémentaire() permet de contourner le problème, le cas échéant.
    """
    lon, dist = coordonnees(planete, date)
    long_m= mean(lon)
    couleur, nom = attributs_planete(planete)
    plt.annotate("", xy=(long_m, 1), xytext=(0, 0),arrowprops=dict(arrowstyle="->", color=couleur), zorder=3)
    plt.text(long_m, 1.01, nom, ha='left',va='center', rotation=np.degrees(long_m))
def opposition(planete,dates):
    """
    Trace des segments entre la position de la Terre et celle de la planète, pour illustrer la rétrogradation
    """
    L_Terre, D_Terre =  coordonnees(terre, dates)
    L_planete, D_planete = coordonnees(planete, dates)
    plt.plot((L_Terre, L_planete), (D_Terre, D_planete), 'k')

Le module Skyfield se base sur des fichiers d’éphémérides disponibles sur le web. Une commande Skyfield permet de les télécharger automatiquement. Ces fichiers d’éphémérides couvrent les positions de nombreux astres sur plusieurs siècles, voire millénaires. Comme ils sont assez volumineux, il est possible de télécharger une fois pour toutes le fichier souhaité, puis de l’appeler en indiquant son adresse sur le disque dur.

# (Télé)chargement du fichier d'ephémérides de421.bsp (16 MB, période 1849-2050)
eph = load('../../skyfield-ephemerides/de421.bsp')# si le fichier est déjà chargé sur le disque (chemin à adapter).
# eph=api.load('de421.bsp')# pour télécharger automatiquement le fichier, dans le dossier du fichier Python

soleil = eph['sun']
mercure = eph['mercury']
venus = eph['venus']
terre= eph['earth']
mars = eph['mars']
jupiter = eph['jupiter barycenter']
saturne = eph['saturn barycenter']
uranus = eph['uranus barycenter']
neptune = eph['neptune barycenter']
liste_planetes=[mercure,venus,terre,mars,jupiter,saturne,uranus,neptune]

Viennent ensuite les paramètres du graphique créé avec le module Matplotlib :

#Paramètres du graphique : --------------------------------------

#fig=plt.figure(figsize=(21/2.54, 29.7/2.54 ), tight_layout=True) # dimensions A4
fig=plt.figure(figsize=(10, 10), tight_layout=True, facecolor=couleurFond)
ax=plt.subplot(projection='polar')
plt.title("Position héliocentrique des planètes", pad=20, fontsize=16)
plt.scatter(0, 0, s=200, c='orange', zorder=2)    #Soleil

#plt.yticks([], [])#suppression des cercles et graduations en rayon.
# plt.yticks([1], [])#conserver un cercle de rayon 1 UA.
plt.yticks(np.arange(0, 2, 0.5), [])#graduer tous les 0.5 UA,sans chiffraison
plt.xticks(np.radians(np.arange(0, 360, 15)))#lignes d'angles, tous les 15°

Les graduations en cercle peuvent être utilisées pour faire ressortir la forme non circulaire des planètes.

Il ne reste plus qu’à appeler les fonctions pour obtenir le tracé :

for planete in liste_planetes[0:4] :
    trajectoire(planete,periode)

for planete in liste_planetes[4:]:
    indicateur_planete(planete, periode)

Fin du script :

#Affichage des dates :
texte="Période : \ndu " + date_JMA(periode[0]) +"\nau " +date_JMA(periode[-1]) + f'\ntous les {pasJours} jours'
plt.text(0.10, 0.90, texte, transform=fig.transFigure, c='white', va='top', bbox=dict(fc='orangered'))

plt.legend()
ax.set_axisbelow(True)#place la grille sous les points tracés.

# signature
fig.text(0.99,0.02,'David ALBERTO (www.astrolabe-science.fr)',rotation=90,
        ha='right',transform=fig.transFigure)

fig.savefig("PositionHelioPlanetes.png", dpi=300)
fig.savefig("PositionHelioPlanetes.pdf")
# plt.show()

Les paramètres “zorder=3” servent à éviter que les points des planètes soient recouverts par les lignes grises de la grille.

En fonction de la planète choisie, de sa période orbitale et de la durée de l’époque choisie, on peut avoir une trajectoire complète avec des positions qui se superposent. En plaçant le premier point en noir, on repère plus facilement la position de la première date.

Pour les planètes gazeuses, la méthode précédente fonctionne, mais l’échelle des distances est comprimée. J’ai fait le choix de tracer une flèche pointant vers la planète. La méthode consiste à calculer la longitude moyenne de la planète gazeuse sur l’époque considérée, et de supposer que la longitude varie assez peu si l’époque inférieure à quelques mois.

Attention cependant : si la longitude de la planète passe d’une valeur inférieure à 360 à une valeur supérieure à 0, la discontinuité des angles va renvoyer une valeur fantaisiste pour la moyenne de l’angle. Pour éviter cela, j’ai défini une fonction calculant l’angle complémentaire, ce qui a pour effet de reporter la position de la discontinuité. Cette méthode est un pis-aller car elle est à ajuster au cas par cas.

L’image suivante montre que l’on peut exploiter ce graphique pour visualiser les périodes d’opposition des planètes et expliquer le mouvement de rétrogradation de Mars :

Le code complet (compressé) :


Ce document permet de déterminer une foule d’informations lors d’un atelier astronomie :

  • périodes de révolution
  • dates d’opposition
  • périodes de visibilité (début de nuit, fin de nuit)

Ajout mai 2023

J’ajoute ici le script générant un GIF animé de la rétrogradation de Mars (2024-25), adapté du script précédent.

Le rendu :

Soyez le premier à commenter

Laisser un commentaire