Population stellaire de l'amas M13

Réalisation d'un diagramme couleur / luminosité...

En n'utilisant que des bibliothèques du langage Python.

Les lignes qui suivent exposent pas par pas, en n'excluant pas les tâtonnements et les erreurs.

Bibliothèques à installer

En plus des bibliothèques usuelles : numpy, astropy, matplotlib, il faut installer astroquery.

Dans le contexte du MOOC FUN sur la recherche reproductible

Celui-ci définit un environnement spécifique appelé mooc-rr-jupyter pour les personnes qui veulent utiliser les notebook Jupyter (qui est l'outil utilisé pour réaliser cette note).

Pour installer les bibliothèques qui peuvent manquer, il faut, dans l'ordre :

  • Activer l'environnement conda activate mooc-rr-jupyter
  • Installer astropy et scipy s'ils ne le sont pas. Par exemple : conda install -n mooc-rr-jupyter -c astropy
  • Installer astroquery : conda install -n mooc-rr-jupyter -c conda-forge/label/cf202003 astroquery

Suite à des erreurs dans l'exécution du code, j'ai utilisé la commande conda update -n base -c defaults conda qui semble "réaccorder" les paquets (sans exclure certains messages d'alarme.

Test : astroquery est-il reconnu ?

In [1]:
from astroquery.simbad import Simbad
result_table = Simbad.query_object("m13")
result_table.pprint(show_unit=True)
WARNING: WrongDBMModuleWarning: Existing astropy cache is in an unsupported format, either install the appropriate package or use astropy.utils.data.clear_download_cache() to delete the whole cache; db type is dbm.gnu, but the module is not available [astropy.utils.data]
MAIN_ID      RA          DEC      ... COO_WAVELENGTH     COO_BIBCODE    
          "h:m:s"      "d:m:s"    ...                                   
------- ------------ ------------ ... -------------- -------------------
  M  13 16 41 41.634 +36 27 40.75 ...              I 2006AJ....131.1163S

Un message d'alarme qui n'empêche pas l'obtention d'un résultat.

Passons à l'étape suivante, et initialisons les bibliothèques.

In [2]:
import numpy as np
import matplotlib.pyplot as plt
from astropy.modeling import models, fitting
from astroquery.vizier import Vizier
import scipy.optimize

Chargement d'un catalogue des étoiles de M13. Celui qui a été trouvé (par des méthodes non expliquée ici), porte le numéro : J/A+AS/102/397G

In [3]:
# Vizier.ROW_LIMIT.set('999999999')
catalog = Vizier.get_catalogs('J/A+AS/102/397G')

Important : pour le moment on n'effectue aucun choix sur les champs importés, ni sur le nombre de lignes chargées en mémoire.

Par défaut, c'est 50 lignes. Mais comment paramétrer cette valeur ?

In [4]:
print(catalog)
TableList with 1 tables:
	'0:J/A+AS/102/397/table1' with 7 column(s) and 50 row(s) 

Pour le moment on est limité à 50 lignes. Comment accéder à tout ? Quels sont les noms de colonnes ?

In [5]:
print(catalog[0][0])
Num  Bmag  B-V    X      Y       _RA       _DE   
     mag   mag   pix    pix      deg       deg   
--- ----- ----- ------ ------ --------- ---------
  1 20.19  0.17  64.29   5.61 250.43755  36.53253

Il est possible maintenant d'extraire les deux colonnes qui importent et de tracer un premier graphique.

Premiers graphiques

In [6]:
a = catalog[0]['Bmag']
b = catalog[0]['B-V']
plt.scatter(a,b)
Out[6]:
<matplotlib.collections.PathCollection at 0x7f3ab92f3ed0>

Paramétrer le nombre de lignes chargées

La table de données, correspond avec l'argument [0] qui suit le nom du catalogue.

On fait ici l'hypothèse que la paire de chrochets qui suit permet de définir "à la Python" les lignes chargées. Par exemple : première table et lignes de 0 à 10 se paramétrera : [0][0:10]. Faisons le test :

In [7]:
table = Vizier.get_catalogs('J/A+AS/102/397G')[0][0:10]
print(table)
Num  Bmag  B-V    X      Y       _RA       _DE   
     mag   mag   pix    pix      deg       deg   
--- ----- ----- ------ ------ --------- ---------
  1 20.19  0.17  64.29   5.61 250.43755  36.53253
  2 18.72  0.40  70.35   7.12 250.43650  36.53229
  3 20.03  0.58 278.13   9.99 250.40016  36.53078
  5 18.68  0.50 201.68  13.56 250.41356  36.53068
  6 18.53  0.44  34.34  14.15 250.44285  36.53150
  7 18.63  0.49 145.39  15.77 250.42343  36.53068
  8 19.83  0.55 250.47  17.25 250.40505  36.52990
  9 20.01  0.43 154.31  17.83 250.42188  36.53034
 10 15.99  0.81 308.99  18.00 250.39481  36.52948
 11 18.33  0.45 171.57  23.11 250.41889  36.52950

Si l'on veut charger les lignes 2 à 5, on peut supposer ceci (qui pourra être vérifié avec le listage précédent) :

In [8]:
table2 = Vizier.get_catalogs('J/A+AS/102/397G')[0][2:6]
print(table2)
Num  Bmag  B-V    X      Y       _RA       _DE   
     mag   mag   pix    pix      deg       deg   
--- ----- ----- ------ ------ --------- ---------
  3 20.03  0.58 278.13   9.99 250.40016  36.53078
  5 18.68  0.50 201.68  13.56 250.41356  36.53068
  6 18.53  0.44  34.34  14.15 250.44285  36.53150
  7 18.63  0.49 145.39  15.77 250.42343  36.53068

Et cela fonctionne comme attendu.

Diagramme pour les mille premières lignes

Partant sur les hypothèses suivantes, on va essayer de charger les 1000 premières lignes, et de tracer le diagramme.

In [9]:
table3 = Vizier.get_catalogs('J/A+AS/102/397G')[0][0:1000]
print(table3)
a = table3['Bmag']
b = table3['B-V']
plt.scatter(a,b)
Num  Bmag  B-V    X      Y       _RA       _DE   
     mag   mag   pix    pix      deg       deg   
--- ----- ----- ------ ------ --------- ---------
  1 20.19  0.17  64.29   5.61 250.43755  36.53253
  2 18.72  0.40  70.35   7.12 250.43650  36.53229
  3 20.03  0.58 278.13   9.99 250.40016  36.53078
  5 18.68  0.50 201.68  13.56 250.41356  36.53068
  6 18.53  0.44  34.34  14.15 250.44285  36.53150
  7 18.63  0.49 145.39  15.77 250.42343  36.53068
  8 19.83  0.55 250.47  17.25 250.40505  36.52990
  9 20.01  0.43 154.31  17.83 250.42188  36.53034
 10 15.99  0.81 308.99  18.00 250.39481  36.52948
 11 18.33  0.45 171.57  23.11 250.41889  36.52950
...   ...   ...    ...    ...       ...       ...
 59 18.23  0.54 228.11 107.85 250.40957  36.51730
 60 18.81  0.44 190.62 110.71 250.41615  36.51710
 61 20.30  0.56 164.45 112.12 250.42073  36.51705
 62 18.93  0.49 248.95 120.03 250.40600  36.51548
 63 19.00  0.52  91.93 124.34 250.43350  36.51572
 64 18.09  0.57 291.26 124.68 250.39863  36.51460
 65 18.10  0.53 212.98 127.03 250.41234  36.51469
 66 19.12  0.50 165.06 128.29 250.42073  36.51477
 67 18.27  0.56  10.90 137.04 250.44776  36.51437
 68 19.07  0.47 255.60 144.73 250.40501  36.51198
Length = 50 rows
Out[9]:
<matplotlib.collections.PathCollection at 0x7f3ab924ab50>

En fait, c'est raté. Le paramétrage de forme [0][0:10]ne fonctionne que pour le chargement par défaut, c'est à dire les 50 premières lignes.

Il faut trouver autre chose.

Dans les échanges sur un forum, trouvé ce paramètre : Vizier.ROW_LIMIT = -1

In [10]:
Vizier.ROW_LIMIT = -1
table4 = Vizier.get_catalogs('J/A+AS/102/397G')[0][0:1000]
print(table4)
a = table4['Bmag']
b = table4['B-V']
plt.scatter(a,b)
Num   Bmag  B-V    X      Y       _RA       _DE   
      mag   mag   pix    pix      deg       deg   
---- ----- ----- ------ ------ --------- ---------
   1 20.19  0.17  64.29   5.61 250.43755  36.53253
   2 18.72  0.40  70.35   7.12 250.43650  36.53229
   3 20.03  0.58 278.13   9.99 250.40016  36.53078
   5 18.68  0.50 201.68  13.56 250.41356  36.53068
   6 18.53  0.44  34.34  14.15 250.44285  36.53150
   7 18.63  0.49 145.39  15.77 250.42343  36.53068
   8 19.83  0.55 250.47  17.25 250.40505  36.52990
   9 20.01  0.43 154.31  17.83 250.42188  36.53034
  10 15.99  0.81 308.99  18.00 250.39481  36.52948
  11 18.33  0.45 171.57  23.11 250.41889  36.52950
 ...   ...   ...    ...    ...       ...       ...
1373 18.78  0.97 105.66 371.60 250.43274  36.48093
1375 18.03  0.64  76.11 375.23 250.43794  36.48058
1376 18.16  0.75 192.00 376.64 250.41768  36.47976
1377 19.92  1.27   9.48 376.68 250.44960  36.48073
1378 18.07  0.71  59.08 376.74 250.44092  36.48046
1379 18.74  0.92  42.16 378.43 250.44389  36.48031
1380 16.89  0.77 297.72 382.53 250.39923  36.47837
1381 16.44 -0.04 269.27 381.81 250.40420  36.47862
1383 17.26  0.69 244.69 383.57 250.40851  36.47851
1385 17.77  0.95  63.48 384.70 250.44021  36.47932
Length = 1000 rows
Out[10]:
<matplotlib.collections.PathCollection at 0x7f3ab91535d0>

Paramétrer la taille des points dans le diagramme

In [11]:
Vizier.ROW_LIMIT = -1
table4 = Vizier.get_catalogs('J/A+AS/102/397G')[0][0:1000]
a = table4['Bmag']
b = table4['B-V']
plt.scatter(a,b,s=1) # s=1 : un point de 1 pixel de diamètre
Out[11]:
<matplotlib.collections.PathCollection at 0x7f3ab91005d0>

Couleur / luminosité ?

Cela fait curieusement penser au diagramme H.R. Mais sans lui ressembler. Et si l'on croisait les axes ?

In [12]:
Vizier.ROW_LIMIT = -1
table4 = Vizier.get_catalogs('J/A+AS/102/397G')[0][0:1000]
a = table4['Bmag']
b = table4['B-V']
plt.scatter(b,a,s=1) # s=1 : un point de 1 pixel de diamètre
Out[12]:
<matplotlib.collections.PathCollection at 0x7f3ab9070dd0>

L'échelle des magnitude est dans l'ordre inverse.

Voici maintenant un diagramme HR, selon la disposition conventionnelle, réalisé avec 3000 étoiles.

In [19]:
Vizier.ROW_LIMIT = -1
table4 = Vizier.get_catalogs('J/A+AS/102/397G')[0][0:3000]
a = table4['Bmag']
b = table4['B-V']
fig = plt.figure(1, figsize=(5,6)) # dimensions du cadre 
plt.plot(b, a, linestyle='none', marker = 'o', c = 'red', markersize = 2)
axes = plt.gca()
axes.set_xlim(-0.25,1.60) # échelle des températures
axes.set_xlabel("Couleur : B-V")
axes.set_ylim(13, 21)   # échelle des magnitudes 
axes.set_ylabel("Magnitudes")
# affiche les points dans l'ordre du diagramme HR
axes.invert_yaxis()
# axes.invert_xaxis()

Comparaison avec un diagramme "standard"

L'image qui sert de fond est tiré de l'article de Wikipedia.

Explications

Le diagramme HR utilise une échelle des magnitudes graduée en magnitudes absolues. Celle-ci n'étant pas disponible dans le catalogue d'étoiles de M13, on ne pourra caler "en hauteur" les deux diagrammes.

Par contre, M13 étant très loin, on peut considérer que les étoiles sont toutes à la même distance de nous, ce qui permet d'avoir une perception cohérente des rapports de magnitudes (des étoiles entre elles).

L'indice de couleur (B-V) est cohérente sur les deux graphiques.

L'image ci-jointe est un montage où un cadre blanc situe le diagramme des étoiles de M13 sur le diagramme standard.

Montage.

Bilan.

  • Ouverture et chargement du catalogue.
  • Paramétrage du nombre de lignes chargées.
  • Pas de paramétrage des colonnes chargées.
  • Diagramme avec une taille de point défini.
  • Étiquettes le long des axes et orientation des graduations.

Envies

À défaut de termes plus savants...

Maintenant que l'on a compris que l'on réalisait un diagramme HR de l'amas M13, il est tentant de voir ce que donneront les diagrammes d'autres amas globulaires de la Galaxie.

Sont-ils tous nés à une même époque ? Le nuage de matière initial était-il de même composition pour tous ?

Si on ne sait pas répondre, la densité relative d'un amas, ou le nombre d'étoiles ont-ils une incidence sur le diagramme ?

Si deux diagrammes sont légèrement différents "au pif", existe-t-il des "outils" qui permettent de trancher "par les quantités" (les nombres) : moyennes, courbes, pente de celle-ci. Et que sais-je encore ? Si ces outils existent, vais-je y comprendre quelque chose ?

Et, plus important, comment aider d'autres à y comprendre aussi quelque chose ?

Pour finir par une phrase rassurante : le travail ne manquera pas.