EC 321 : examen terminal

Durée : 2 heures
Tous documents autorisés

1. Saisie & calculs

Exercice 1

Calculez la concentration en µg/m3 d'un gaz à partir de sa masse molaire M, sa densité D, la température T et la pression atmosphérique P sachant que :

C = D . P . M / ( R . T )

Température (°C) ? 26
Pression atmosphérique (hPa) ? 1024
Nature du gaz (CO2, NO2, O3) ? CO2
Densité (ppm) ? 12

Concentration de CO2 : 21.7 µg/m3

---------------------------------------------

Température (°C) ? -2
Pression atmosphérique (hPa) ? 990
Nature du gaz (CO2, NO2, O3) ? O3
Densité (ppm) ? 27

Concentration de O3 : 56.9 µg/m3

Attention !

Conversion d'unités entre la saisie et la formule !

Correction
temperature = float(input('Température (°C) ? '))
pressure = float(input('Pression atmosphérique (hPa) ? '))
gas = input('Nature du gaz (CO2, NO2, O3) ? ')
ppm = float(input('Concentration (ppm) ? '))

if gas == 'CO2':
    molar_mass = 44.01
if gas == 'NO2':
    molar_mass = 46.01
if gas == 'O3':
    molar_mass = 48

con = ppm * pressure * 0.1 * molar_mass / ( 8.314510 * (temperature + 273.15) )
print('Concentration de ' + gas + ' : ' + str(round(con, 1)) + ' µg/m3')

2. Formats GPX, TCX

Exercice 2

Calculez et affichez la vitesse moyenne de chaque tour (élément Lap) contenu dans le fichier running.tcx.

Vitesses moyennes par tour :
----------------------------

Tour N°1: 2.4 m/s
Tour N°2: 2.5 m/s
Tour N°3: 2.5 m/s
Tour N°4: 2.4 m/s
Tour N°5: 2.5 m/s
Tour N°6: 2.6 m/s
Correction
from bs4 import BeautifulSoup

# Chargement du fichier XML 
content = open('running.tcx')

# Construction de l'arborescence
soup = BeautifulSoup(content, 'lxml')

print('Vitesses moyennes par tour :')
print('----------------------------\n')

# Parcours des éléments Lap
lap_count = 1
for lap in soup.select('lap'):
    mean_speed = float(lap.select_one('distancemeters').string) / float(lap.select_one('totaltimeseconds').string)
    print('Tour N°' + str(lap_count) + ': ' + str(round(mean_speed, 1)) + ' m/s')
    lap_count += 1

Exercice 3

Écrivez un script Python qui, à partir des données contenues dans le fichier clecy.gpx, génère un graphique superposant le relevé d'altitude et l'évolution de la fréquence cardiaque.

Correction
from bs4 import BeautifulSoup
import matplotlib.pyplot as plt

# Chargement du fichier XML
content = open('clecy.gpx')

# Construction de l'arborescence
soup = BeautifulSoup(content, 'lxml')

heart_rate = []
elevation = []
for trkpt in soup.select('trkpt'):
    heart_rate.append(float(trkpt.select_one('heartrate').string))
    elevation.append(float(trkpt.select_one('ele').string))

plt.plot(range(len(elevation)), elevation, label='Altitude')
plt.plot(range(len(heart_rate)), heart_rate, label='Fréquence cardiaque')
plt.xlabel('N° du relevé')
plt.ylabel('altitude (m), fréquence cardiaque (ppm)')
plt.legend()
plt.show()

Exercice 4

Générez une carte OpenStreetMap centrée sur la trace GPS du fichier clecy.gpx en plaçant un marqueur tous les 1km le long du parcours.

Astuce

Pour calculer la distance entre deux relevés GPS, vous pouvez utiliser la fonction great_circle_distance() vue dans le chapitre Calcul de distances.

Correction
from math import *
import numpy as np
from bs4 import BeautifulSoup
import folium

def great_circle_distance(lat1, lon1, lat2, lon2):
    lat1 = radians(lat1)
    lat2 = radians(lat2)
    dLon = radians(fabs(lon2-lon1))

    cosLat1 = cos(lat1)
    sinLat1 = sin(lat1)
    cosLat2 = cos(lat2)
    sinLat2 = sin(lat2)
    cosDLon = cos(dLon)
    sinDLon = sin(dLon)

    A = cosLat2*sinDLon
    B = cosLat1*sinLat2 - sinLat1*cosLat2*cosDLon

    return 6371009 * atan2(sqrt(A*A + B*B),
                            sinLat1*sinLat2 + cosLat1*cosLat2*cosDLon)


# Chargement du fichier XML
content = open('clecy.gpx')

# Construction de l'arborescence
soup = BeautifulSoup(content, 'lxml')

# Liste des latitudes exprimées en degrés
latitude = []

# Liste des longitudes exprimées en degrés
longitude = []

for trkpt in soup.select('trkpt'):
    latitude.append(float(trkpt['lat']))
    longitude.append(float(trkpt['lon']))

# Création d'une carte

center_latitude  = ( np.min(latitude) + np.max(latitude) ) / 2
center_longitude = ( np.min(longitude) + np.max(longitude) ) / 2
fmap = folium.Map(location=[center_latitude, center_longitude], tiles='OpenStreetMap', zoom_start=14)

distance = 0
threshold = 1
for i in range(1, len(latitude)):
    distance += great_circle_distance(latitude[i-1],
                                      longitude[i-1], latitude[i], longitude[i])/1000
    if distance > threshold:
        # Ajout d'un marqueur
        folium.Marker([latitude[i], longitude[i]],
                      popup=str(threshold) + ' km',
                      icon=folium.Icon(color='purple',icon='record')).add_to(fmap)
        threshold += 1

points = list(zip(latitude, longitude))
folium.PolyLine(points, color='purple', weight=2.5, opacity=0.8).add_to(fmap)

# Génération du fichier HTML contenant la carte
fmap.save('clecy.html')

3. Format XLSX

Exercice 5

Affichez le nom et le prénom du joueur de plus grande taille de l'équipe des Los Angeles Lakers (LAL) à partir des données du fichier nba_players_stats.xlsx.

Marc Gasol (2.16 m)
Correction
import pandas as pd

df = pd.read_excel('nba_players_stats.xlsx')

lal = df[df['Team'] == 'LAL']
i = lal['Height'].idxmax()

print(lal['Firstname'][i] + ' ' + lal['Lastname'][i] + ' (' + str(round(lal['Height'][i], 2)) + ' m)')

Exercice 6

Affichez les informations des 5 joueurs de la NBA ayant le plus grand Indice de Masse Corporelle (IMC) et les 5 joueurs ayant le plus petit à partir des données du fichier nba_players_stats.xlsx.

Plus grands IMC :
-----------------
BKN Alan Williams (2.03 m, 120.2 kg) IMC = 29
OKC Deonte Burton (1.96 m, 111.13 kg) IMC = 29
BOS Guerschon Yabusele (2.03 m, 117.93 kg) IMC = 29
PHI Andre Drummond (2.11 m, 126.55 kg) IMC = 28
MIN Jared Terrell (1.9 m, 102.97 kg) IMC = 28
MIA PJ Tucker (1.98 m, 111.13 kg) IMC = 28

Plus petits IMC :
-----------------
TOR Isaac Bonga (2.03 m, 81.65 kg) IMC = 20
SAC Corey Brewer (2.06 m, 84.37 kg) IMC = 20
SAS Dejounte Murray (1.96 m, 77.11 kg) IMC = 20
IND Edmond Sumner (1.98 m, 79.83 kg) IMC = 20
NOP Brandon Ingram (2.06 m, 86.18 kg) IMC = 20
TOR Patrick McCaw (2.01 m, 83.91 kg) IMC = 21
Correction
import pandas as pd

# Chargement des données
df = pd.read_excel('nba_players_stats.xlsx')

# Ajout d'une colonne 'BMI' contenant l'IMC de chaque joueur
for i in df.index:
    df.loc[i, 'BMI'] = df['Weight'][i] / ( df['Height'][i] * df['Height'][i] )

# Tri dans l'ordre décroissant des valeurs d'IMC
df.sort_values(by='BMI', ascending=False, inplace=True)
df.reset_index(drop=True, inplace=True)

print('Plus grands IMC :')
print('-----------------')
for i in range(6):
    print(df['Team'][i] + ' ' + df['Firstname'][i] + ' ' + df['Lastname'][i] + ' (' + str(round(df['Height'][i], 2)) + ' m, ' + str(round(df['Weight'][i], 2)) + ' kg) IMC = ' + str(round(df['BMI'][i])))

# Tri dans l'ordre croissant des valeurs d'IMC
df.sort_values(by='BMI', ascending=True, inplace=True)
df.reset_index(drop=True, inplace=True)

print('\nPlus petits IMC :')
print('-----------------')
for i in range(6):
    print(df['Team'][i] + ' ' + df['Firstname'][i] + ' ' + df['Lastname'][i] + ' (' + str(round(df['Height'][i], 2)) + ' m, ' + str(round(df['Weight'][i], 2)) + ' kg) IMC = ' + str(round(df['BMI'][i])))

Exercice 7

À partir des fichiers teams.xlsx et nba_players_stats.xlsx, générez un fichier Excel pour chaque équipe NBA contenant les informations (nom, prénom, taille, poids) des joueurs concernés.

Correction
import pandas as pd

df_teams = pd.read_excel('teams.xlsx')
df_players = pd.read_excel('nba_players_stats.xlsx')

for team in df_teams['abbreviation']:
  df = df_players[ df_players['Team'] == team ]
  df.sort_values(by='Lastname', ascending=True, inplace=True)
  df.reset_index(drop=True, inplace=True)
  
  # Enregistrement du DataFrame df au format Excel
  writer = pd.ExcelWriter(team + '.xlsx', engine = 'xlsxwriter')
  df.to_excel(writer, index = False)
  print('Saving ' + team + '.xlsx...')
  writer.save()