Un tableau périodique avec le module Python “mendeleev”

Le module mendeleev fournit une grande quantité de données numériques sur les éléments chimiques (électronégativité, rayon atomique,…).

Je l’ai utilisé pour tracer un tableau périodique personnalisé (avec le module matplotlib pour le graphique) :

Code Python compressé :


La principale différence avec le code présenté dans un précédent article : les données ne sont pas stockées dans un fichier .csv associé.

Vous aurez besoin d’installer le module mendeleev sur votre ordinateur.

Je cherchais à rédiger mon propre code afin d’obtenir un tableau périodique dans lequel je peux modifier moi-même les réglages suivants :

  • affichage optionnel de la masse molaire.
  • affichage de la masse molaire avec un nombre de chiffres significatifs cohérent.
  • noms des éléments en français (ce que ne propose pas le module mendeleev).
  • affichage optionnel des couleurs par bloc.

Vous pourrez donc facilement ajuster ces réglages, dans le code commenté en téléchargement ci-dessus. Quelques commentaires du code :

def chiffSignif(n):#renvoie un nombre n avec 3 chiffres significatifs
    if n<10:
        valeur='{:.2f}'.format(n)
    elif n<100:
        valeur= '{:.1f}'.format(n)
    else:
        valeur= '{:.0f}'.format(n)
    return valeur.replace('.',',')#virgule à la place du point

Cette fonction renvoie un nombre sous forme de chaîne de caractères, avec 3 chiffres significatifs. En effet, je n’ai pas trouvé de fonction native dans Python pour ce résultat. Cette fonction remplace également le point décimal par la virgule.

noms=['Hydrogène','Hélium','Lithium','Béryllium','Bore','Carbone','Azote','Oxygène',
      'Fluor','Néon','Sodium','Magnésium','Aluminium','Silicium','Phosphore','Soufre',
      'Chlore','Argon','Potassium','Calcium','Scandium','Titane','Vanadium','Chrome',
      'Manganèse','Fer','Cobalt','Nickel','Cuivre','Zinc','Gallium','Germanium',
      'Arsenic','Sélénium','Brome','Krypton','Rubidium','Strontium','Yttrium',
      'Zirconium','Niobium','Molybdène','Technétium','Ruthénium','Rhodium',
      'Palladium','Argent','Cadmium','Indium',
'Étain','Antimoine','Tellure','Iode','Xénon','Césium','Baryum','Lanthane','Cérium',
'Praséodyme','Néodyme','Prométhium','Samarium','Europium','Gadolinium','Terbium',
'Dysprosium','Holmium','Erbium','Thulium','Ytterbium','Lutetium','Hafnium','Tantale',
'Tungstène','Rhénium','Osmium','Iridium','Platine','Or','Mercure','Thallium','Plomb',
'Bismuth','Polonium','Astate','Radon','Francium','Radium','Actinium','Thorium','Protactinium',
'Uranium','Neptunium','Plutonium','Americium','Curium','Berkelium','Californium','Einsteinium',
'Fermium','Mendelevium','Nobelium','Lawrencium','Rutherfordium','Dubnium','Seaborgium','Bohrium',
'Hassium','Meitnerium','Darmstadtium','Roentgenium','Copernicium','Nihonium','Flerovium',
'Moscovium','Livermorium','Tennessine','Oganesson',
]

Cette liste de noms d’éléments en français vient pallier l’impossibilité de traduire en français les noms fournis par le module mendeleev. Je l’ai obtenue par copier-coller depuis un jeu de données obtenu sur www.datastro.eu, que j’ai traduits en français.

En début de code, deux variables booléennes sont créées :

blocs=False#True : cases colorées selon les blocs. False : incolores
masses_molaires=True#affichage ou pas
#création des listes de coordonnées des éléments
"""
La ligne est la valeur de la période de l'élément.
La colonne est la valeur du paramètre "group_id" de l'élément.
Pour les terres rares, le module ne fournit pas de valeur pour "group_id" ; 
je me base donc sur la valeur de N pour établir un numéro de colonne.
Les listes "ligne" et "colonne" serviront ensuite pour toutes les indications
(masse molaire, N° atomique, symbole, nom).
"""
ligne=[]
colonne=[]

for N in range(1,118+1):
    if N>=58 and N<=71:#lanthanides
        colonne.append((3+N-57)*a)
        ligne.append((element(N).period+y_offset_La)*b)
    elif N>=90 and N<=103:#actinides
        colonne.append((3+N-89)*a)
        ligne.append((element(N).period+y_offset_Ac)*b)
    else:
        colonne.append((element(N).group_id)*a)
        ligne.append((element(N).period)*b)

À partir des listes de coordonnées établies dans le code ci-dessus, le programme affiche tour à tour, pour chaque élément :

  • la case rectangle (avec une couleur soumise à condition : booléen “blocs”).
  • le symbole
  • le numéro atomique
  • le nom
  • la masse molaire (soumise à condition : booléen “masses_molaires”)
fig=plt.figure(figsize=(29.7/2.54,21 /2.54),tight_layout=True,facecolor='slateblue')

Création d’une figure au format A4 (avec 1 pouce = 2.54 cm)

Pour les noms les plus longs, la case n’est pas assez large… Mais je ne voulais pas choisir une taille trop faible. Je crée donc une condition sur la taille de la police pour certains éléments chimiques :

 if N in [91,101,104,110,116]:#éléments aux noms longs
        tailleDuNom=6
    else:tailleDuNom=taille_nom

Le remplissage des cases d’une couleur selon le bloc de l’élément est rendu possible par la donnée fournie par le module mendeleev : la commande element(26).block fournit la lettre ‘d’, par exemple.

    if blocs==True:
        if elem.block=='s':
            couleur_case=c_bloc_s
        elif elem.block=='p':
            couleur_case=c_bloc_p
        elif elem.block=='d':
            couleur_case=c_bloc_d
        else : couleur_case=c_bloc_f
    else: couleur_case='none'

Enfin, un mot sur la police de caractères : je conseille une police Serif (avec empattements) pour les symboles (risque de confusion entre I majuscule et l minuscule).

J’ai inséré dans le code un réglage optionnel pour utiliser la police LaTeX. Dans ce cas, l’affichage des noms en très petits caractères étant peu esthétique, j’ai fait le choix d’écrire les noms en format sans Serif :

    plt.text(colonne[N-1]+x_offset_nom*a,-ligne[N-1]+y_offset_nom*b,r'\textsf{%s}'%(noms[N-1]),c=c_nom,fontsize=tailleDuNom,ha='center')#nom

Il est facile de modifier ce réglage selon vos préférences.


Tendances dans le tableau périodique

En choisissant une grandeur fournie par le module mendeleev (l’électronégativité, par exemple), et avec l’aide d’un colormap (carte de couleur), on peut visualiser d’un coup d’oeil les tendances dans le tableau périodique :

Le principe d’un colormap est d’associer une gamme de couleurs à une gamme de valeurs. On crée une liste de valeurs d’électronégativités pour l’ensemble des éléments chimiques ; puis on normalise le colormap en associant les valeurs extrêmes (ici, 0 et 4) aux couleurs extrêmes du colormap choisi (ici, de blanc à vert foncé).

Les données atomiques sont à choisir parmi (liste non exhaustive) :
abundance_crust (mg/kg)
abundance_sea (mg/L)
atomic_volume
boiling_point
melting_point
evaporation_heat
fusion_heat
heat_of_formation
ionenergy
is_radioactive (booléen)
lattice_constant
metallic_radius
specific_heat
thermal_conductivity (W/(mK))
vdw_radius

Attention, il faut absolument se référer à la documentation du module mendeleev, car selon la grandeur choisie les données fournies peuvent prendre des formes différentes (flottants, tuples…) ce qui nécessite quelques aménagement pour le code.

Quelques exemples : sélection de l’électronégativité, ou de l’énergie d’ionisation, ou encore de la conductivité thermique.

symbole=[]
grandeur=[]
for N in range(1,Zmax+1):
    symbole.append(element(N).symbol)
    # valeur=element(N).electronegativity('pauling') # CHOIX DE LA GRANDEUR 
    # valeur=element(N).ionenergies[1]#énergie d'ionisation (eV)(Zmax=108)
    valeur=element(N).thermal_conductivity
    if valeur is None:
        valeur=np.nan
    grandeur.append(valeur)

Il arrive qu’aucune valeur ne soit définie (comme l’électronégativité de la plupart des gaz nobles, selon Pauling). Le module renvoie ‘None’, ce qui entraîne une erreur pour la normalisation du colormap ensuite. Il faut alors remplacer ‘None’ par l’indication ‘NaN’, ce que le colormap tolère.

La couleur associée est alors par défaut celle de la valeur la plus faible.

Plus loin dans le code, au moment de tracer les cases colorées, on passe comme couleur la commande c=cmap(norm(grandeur[Z-1])) : ainsi l’association est faite entre la valeur contenue dans grandeur[Z-1] et la couleur.

Dans mon code, j’ai attribuée une couleur gris clair (‘gainsboro’) si la donnée est ‘NaN’.

for Z in range(1,Zmax+1):
    plt.text(colonne[Z-1], -ligne[Z-1], symbole[Z-1], fontsize=taille_symbole, va='center', ha='center')
    plt.text(colonne[Z-1]+x_offset_Z*a,-ligne[Z-1]+y_offset_Z*b,Z,c=c_Z,fontsize=taille_Z,ha='left')#numéro atomique
    plt.text(colonne[Z-1]+x_offset_nom*a,-ligne[Z-1]+y_offset_nom*b,r'\textsf{%s}'%(noms[Z-1]),c=c_nom,fontsize=taille_nom,ha='center')#nom
    if grandeur[Z-1] is np.nan:
        couleur_case='gainsboro'
    else:
        couleur_case=cmap(norm(grandeur[Z-1]))
    rectangle=plt.Rectangle((colonne[Z-1]-0.5*a,-(ligne[Z-1]+0.5*b)),a,b,facecolor=couleur_case,edgecolor='k')#case
    ax1.add_patch(rectangle)

Les valeurs d’électronégativité n’étant pas affichées ici, j’ajoute une ‘colorbar‘ servant de légende pour une lecture approximative de la valeur selon la couleur :

#tracé de la barre de couleurs :
divider = make_axes_locatable(ax1)
cax = divider.append_axes('bottom', size='6%', pad=0.3)
cb=cbar.ColorbarBase(cax, cmap=cmap, norm=norm, orientation='horizontal')

Si vous préférez afficher l’électronégativité, inspirez-vous de la ligne affichant le numéro atomique pour afficher la valeur contenue dans grandeur[Z-1] (en limitant les décimales !).

Le code complet :

Un document PDF reprenant tous ces tableaux :


Le nombre d’isotopes par élément chimique, avec un colormap :

Le code Python :

Soyez le premier à commenter

Laisser un commentaire