Introduction à l'utilisation des notebooks Jupyter

In [1]:
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
from IPython.core.display import HTML
from IPython.display import display,Image
#
from IPython.display import display, Markdown, clear_output
def printmd(string):
    display(Markdown(string))
# test si numero étudiant spécifier
try: NUMERO_ETUDIANT
except NameError: NUMERO_ETUDIANT = None 
if type(NUMERO_ETUDIANT) is not int :
    printmd("## ERREUR: numéro d'étudiant non spécifié!!!")
    NUMERO_ETUDIANT = 1234
    NOM = "toto"
    PRENOM = "toto"
    #raise AssertionError("NUMERO_ETUDIANT non défini")
# parametres spécifiques
_uid_    = NUMERO_ETUDIANT
np.random.seed(_uid_)
printmd("## Etudiant {} {}  id={}".format(NOM,PRENOM,NUMERO_ETUDIANT))

ERREUR: numéro d'étudiant non spécifié!!!

Etudiant toto toto id=1234

Ressources en ligne à consulter

Introduction :

Vous allez au cours de ce TP vous familiariser avec Python, matplotlib et le format notebook.
Python est un langage de programmation très générique et utilisé dans beaucoup de contexte différent. Pour le calcul scientifique, nous allons surtout utiliser les modules Matplotlib, numpy, Scipy

Python

Python est un language de programmation moderne de haut niveau, logiciel libre, généraliste, multi-plateformes, multi-architecture, multi-OS (linux, windows, MacOS,..). Un programme python peut s'exécuter sur un tout petit raspberry Pi à 30€ (ARM), sur des smartphones, des portables, des PC jusqu'aux super-calculateurs HPC avec $10^9$ coeurs de calcul.

historique

Guido Von Rossum, un informaticien hollandais, crée en 1989 un nouveau langage de programmation, qu'il décide de partager avec la communauté internationale sous une licence de logiciel libre. Fan de la série télévisée Monty Python's Flying Circus, il décide de baptiser ce projet Python. Les Monty Python ont eu une grande influence sur l'informatique puisqu'ils sont aussi à l'origine du terme spam (nom utiliser dans un de leurs sketchs).

Le langage Python est devenu l'un des langages de programmation le plus utilisé au monde et est géré par la Python Software Foundation (PSF), une association sans but lucratif fondée en 2001.

Bases d'un notebook

Notebook

Le notebook est une interface web riche qui permet d'associer du code, la réponse du code et du texte.
Le document que l'on travaille est composé de cellules.
Pour chaque cellule, il faut indiquer à l'avance comment le notebook doit l'interpréter.

Les différents types de cellule

  • code

L'interprétation par défaut est en code, c'est à dire que le programme interprète le contenu de la cellule comme s'il s'agissait d'un code en python. Pour changer cela, il faut selectionner la cellule puis utiliser le menu déroulant de la barre d'outils en haut.

  • texte (markdown)

Une cellule peut être interprétée comme du texte, selon un langage spécifique, le markdown. Il s'agit de texte enrichi de quelques règles supplémentaires qui permettet une mise en page sommaire (mais efficace) du texte. Nous allons en voir quelques exemples.

  • cellules non modifiables : cellules avec une clé que vous ne pouvez pas modifier.

cellules avec des questions et des tests

cellule de code contenant votre réponse (noté)

ces cellules de code permettent de rentrer une ou plusieurs ligne de code python. Elles affichent:

  # YOUR CODE HERE
  raise NotImplementedError()

Il faut effacer ces 2 lignes pour les remplacer par les lignes de code pour répondre à la question posée.

Dans la cellule suivante, vous avez un test qui permet de valider la réponse et vérifier si celle-ci est correcte. Si votre réponse est correcte elle affiche Validation OK

cellule de texte pour rentrez vos commentaires et analyses demandées (noté)

Ces cellules de texte contiennent le texte suivant:

  YOUR ANSWER HERE

qu'il faut remplacer par votre réponse au format markdown (voir plus loin)

Exercice :

dans la cellule de code évalué suivante entrée la ligne de code suivante (sans espace avant)

   x = np.sqrt(2)/2.

qui calcule la valeur approchée de $\frac{\sqrt{2}}{2}$. Dans la cellule de texte suivante expliquée pourquoi ce n'est pas la valeur exacte. On pourra analyser le résultat de $x^2=x*x$.

In [2]:
# calculer la valeur approchée dans la variable x
x = 0
### BEGIN SOLUTION
x = np.sqrt(2)/2
### END SOLUTION
In [3]:
print("x=",x)
print("x*x=",x*x)
assert (np.abs(x-0.70710678118654)<1.e-14)
printmd("### Validation OK")
x= 0.7071067811865476
x*x= 0.5000000000000001

Validation OK

Quelques commandes de base :

  • exécuter une cellule : bouton run (ou raccourci shift+enter)
  • créer une nouvelle cellule : bouton + (ou raccourci alt+entrer)
  • changer le type de la cellule : : menu déroulant

Attention

Il faut bien veiller à exécuter le notebook dans l'ordre, en commençant à la première cellule.

astuce : utiliser le menu Noyau -> Redemmarer & tout exécuter ou Kernel -> Restart & Run all pour executer tout le notebook sans effet de bord

Exercice :
Ajoutez à la suite cette cellule avec le bouton + deux cellules, une en code et une en markdown.
Dans la première cellule de code, écrivez 'a=1;print(a);' (sans les guillemets), puis executez.
Dans la deuxième cellule, en markdown, commenter le résultat. (1 ligne maximum)

In [ ]:
 

Règles de formattage du texte

Il est possible de mettre en page (un minimum) le texte dans une cellule markdown.
Ces règles sont assez sommaires, mais suffisent en général pour ce qu'on veut écrire. Pour une mise en page plus complète, il faudra utiliser des logiciels tiers (Latex, openoffice, etc...)

italique, gras :
On utilise le caractère * pour mettre du texte en :

  • italique : *texte* --> texte
  • gras : **texte** --> texte

Saut de ligne, nouveau paragraphe : Pour commencer une nouvelle ligne, il faut ajouter deux espaces à la fin d'une ligne.
Pour commencer un nouveau paragraphe, il faut sauter deux lignes.

Titres Pour inclure un titre, il faut utiliser le caractère # en début de ligne. Tout le reste de la ligne sera alors formaté comme un titre (grande police, gras).
Si on utilise plusieurs caractères en début de ligne, le niveau de titre diminue :

  • # --> titre principal
  • ## --> sous-titre
  • ### --> sous-sous-titre
  • etc...

Exercice :
Formatter le texte suivant suivante en utilisant :

  • italique
  • gras
  • saut de ligne
  • paragraphe
  • un titre de second niveau

Un peu d’histoire Ce language a été créé en 2004 par John Gruber et Aaron Swartz et n’a pas évolué depuis. Même si de nombreuses extensions et “extras” sont venues se greffer au projet originel. Le projet initial avec sa documentation est sur daringfireball. Dès le départ, Gruber a écrit un script Perl pour convertir du texte markdown en XHTML. C’est tout l’intérêt du système : éditer un fichier texte simple avec quelques caractères spéciaux supplémentaires, puis le faire passer dans un script qui va l’enrichir des balises requises pour l’afficher mise en forme dans le navigateur.

Equations

Il est possible d'inclure des équations mathématiques dans une cellule markdown. C'est même d'ailleurs là un de ses intérêts principaux.
Les équations sont écrites suivant une syntaxe Latex (simplifiée). On utilise pour cela le symbole dollar (\$) de la façon suivante :

  • équation dans la même ligne: 1x(\$) soit `$ texte de l'équation $`
  • équation avec retour à la ligne: 2x(\$) soit `$ $ texte de l'équation $ $`

Le texte de l'équation suit aussi la syntaxe latex. Celle-ci est très riche et ne peut pas être expliquée en quelques minutes, vous êtes invités à consulter des tutoriels sur internet. Voici quelques indications de syntaxe de base :

  • exposant : \^{texte}
  • indice : _{texte}
  • fraction : \frac{numérateur}{denominateur}
  • grec : \pi, \alpha, \lambda, etc...
  • racine carrée : \sqrt{texte}

Exemple :
La formule d'euler relie les nombres les plus importants des mathématiques : $$ e^{i\pi}+1=0 $$ avec $e = 2.71828182846...$ et $\pi = 3.14159265359...$

Attention :
Markdown n'est pas prévu pour utiliser toute la richesse de Latex. En particulier, il est impossible (ou très difficile...) d'inclure des packages permettant des caractères qui ne sont pas prévus dans le latex de base. Il est recommandé de simplifier au maximum les équations.

Exercice :
écrire dans la cellule suivante l'équation des gazs parfaits pour un fluide , en définissant chacun des termes.

Eléments de programmation avec Python

Nous allons maintenant nous concentrer sur le code en python, et ses applications pour le calcul scientifique.

Bases : variables, types, listes

Pour commencer, nous allons voir les variables en python. Pour définir une variable, la syntaxe est simple :

In [4]:
a=1

Nous venons de définir la variable 'a', et elle a pour valeur 1.
a est donc une variable.

Types des variables:

la valeur de a est 1, c'est une variable numérique. De plus, le nombre n'a pas de décimales : c'est un entier. On peut le vérifier avec la fonction type :

In [5]:
type(a)
Out[5]:
int

Pour déinir une variable réelle à virgule flottante, il faut lui mettre des décimales :

In [6]:
b=1.0
type(b)
Out[6]:
float

Il y a plusieurs types de variables dans python (int, float, string, ...), il y en a en plus dans les modules, et il est même possible de créer de nouveaux types de variables, mais nous ne rentrerons pas dans ce sujet sans fin.
La principale difficulté que vous allez rencontrer est lors de l'association de différents types, par exemple dans une opération mathématique. Dans ce cas il faut parfois être vigilant.

Exercice :
Expliquez les différents résultats donnés par les opérations ci-dessous dans la dernière cellule de texte

In [7]:
a=1;b=3;
print(a+b)
print(a//b)
4
0
In [8]:
a=1.;b=3;
print(a/b)
0.3333333333333333
In [9]:
a='1'; b='3';
print(a+b)
13

Réponse :

  • cellule 1

  • cellule 2

  • cellule 3

Tests, Boucles, fonctions

En python, les structures (boucles, if, fonctions, etc...) sont indiquées avec l'indentation. Il est donc primordial de respecter l'indentation lors de l'écriture d'un programme !! La syntaxe est en général :
for var in liste: (action)

if (condition): (action)

L'indentation et les deux points sont absolument nécessaire à l'éxecution du code !!

Exemple :

In [10]:
for i in [0,1,2,3,4,5]:
    print(i)
0
1
2
3
4
5

Pour imbriquer des structures les unes dans les autres, il suffit d'ajouter un cran à l'indentation.

Attention à bien respecter l'indentation lors de la sortie d'une structure

In [11]:
for i in [0,1,2,3,4,5,6,7,8]:
    if i<4:          # première indentation 
        print(i)     # deux indentations : on est dans le cas (if), lui-même dans la boucle
    print('done')    # plus qu'une indentation : on est sorti du cas, mais pas de la boucle
0
done
1
done
2
done
3
done
done
done
done
done
done

Pour définir une fonction, la syntaxe respecte aussi l'indentation. Tout ce qui est indenté sera executé au sein de la fonction.
Exemple :

In [12]:
def my_func(a,b):
    print(a)
    print(b)
    print('on va multiplier les deux')
    return a*b
In [13]:
my_func(3.,4.2)
3.0
4.2
on va multiplier les deux
Out[13]:
12.600000000000001
In [14]:
b=my_func(1.3,1.8) # On remarque qu'il n'y a pas de retour de la cellule. 
                   # Les commandes d'impression de la fonction, elles, sont toujours appliquées lors de son appel.
1.3
1.8
on va multiplier les deux

Modules

Bien que déjà très riche, la version de base de Python ne suffit pas à faire proprement du calcul scientifique. Par exemple, il n'y a pas de fonction de base pour calculer la racinne carrée d'un nombre.
Il serait possible de tout définir de zéro, mais ce serait fastidieux, et surtout complètement inutile car il y a déjà beaucoup de codes déjà écrits qui font le travail. Ces codes sont regroupés dans des bibliothèques, appellées en python MODULES.

Pour charger un module, il y a plusieurs syntaxes possibles en python.
Voyons quelques exemples avec le module numpy et la fonction sqrt qu'il contient.

In [15]:
import numpy # importe le module math dans le notebook
numpy   # Le nom du module lui-même ne nous avance pas trop...
Out[15]:
<module 'numpy' from '/usr/local/lib/python3.8/dist-packages/numpy/__init__.py'>

Pour accéder aux fonctions contenues dans le module, il faut les appeler avec le nom du module suivi d'un point :

In [16]:
numpy.sqrt(2)
Out[16]:
1.4142135623730951

Notons que sqrt seul ne suffit pas :

Il est parfois fastidieux de devoir taper le nom de tout le module à chaque utilisation. Il est possible alors de lui donner un nom plus court :

In [17]:
import numpy as np      # np est le nom classique donné au module numpy
np.array([1,2,3,4])
Out[17]:
array([1, 2, 3, 4])

Pour connaître la liste des fonctions disponibles dans un module, on peut utiliser dir :

    dir(np)

ou consulter l'aide en ligne (Aide -> Numpy)

Aide dans le notebook :

Si on veut connaître les détails d'une fonction, on peut utiliser le point d'interrogation ?

Si on ne connait pas à l'avance la fonction à utiliser, le plus simple est une recherche sur internet.
Exercice :
taper dans google 'python numpy renverser'. En déduire comment renverser un array numpy.

In [18]:
A=np.array([1,2,3,4,5,6,7,8]);
#B =        # écrire ici la définition de B
#print(B)

Remarques: Dans les exercices de programmation, les commandes d'importation des modules nécessaires seront déjà écrites dans la première cellule.

Numpy et matplotlib

Le format de base des tableaux dans python est les listes. Pour certaines raisons, il n'est pas adapté au calcul scientifique.

In [19]:
A=[1,2,3,4,5] # une liste A
B=[1,1,1,1,1] # une liste B
print(A+B)
[1, 2, 3, 4, 5, 1, 1, 1, 1, 1]

Pour cela, il est plus pratique d'utiliser la bibliothèque numpy et le format de base qui lui est associé : les arrays

In [20]:
import numpy as np
A=np.array([1,2,3,4,5]) # une liste A
B=np.array([1,1,1,1,1]) # une liste B
print(A+B)
[2 3 4 5 6]

Pour générer un array, il existe plusieurs méthodes :

  • np.array([une liste]) transforme une liste en array
  • np.zeros(n) créée une liste de zeros de taille n
  • np.arange(x1,x2,dx) créée un tableau qui va de x1 à x2 tous les dx. x2 n'est PAS inclus
  • np.linspace(x1,x2,num=n) créée un tableau de taille n qui va de x1 à x2. x2 est inclus.
  • B = fonction_mathematique(A) crée un tableau B de même taille que A, où tous les éléments de B sont le résultat de la fonction pour les éléments de A (exemple : exp, log, tan, cos, ...)

Il y a d'autres façons de faire (importer un fichier texte, etc...)
Exemple :

In [21]:
A=np.zeros(14)+1  # zeros(n) : crée un tableau rempli de zeros, de taille n
B=np.arange(0,1,1./14) # arange(a,b,dx) : va de a à b tous les dx (b n'est PAS inclus !!) 
A+B
C=np.linspace(-100,100,num=14) # linspace(a,b,num=n) : place n valeurs entre deux bornes a et b, inclues.
print(A)
print(B)
print(C)
[1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]
[0.         0.07142857 0.14285714 0.21428571 0.28571429 0.35714286
 0.42857143 0.5        0.57142857 0.64285714 0.71428571 0.78571429
 0.85714286 0.92857143]
[-100.          -84.61538462  -69.23076923  -53.84615385  -38.46153846
  -23.07692308   -7.69230769    7.69230769   23.07692308   38.46153846
   53.84615385   69.23076923   84.61538462  100.        ]

Pour accéder à un élément d'un array en position i, on utilise la syntaxe :
A[i]

Attention !

La numérotation commence à $0$, et finit à $n-1$

In [22]:
B[3]
Out[22]:
0.21428571428571427

Il est possible de représenter graphiquement un tableau (array) en fonction d'un autre de même taille grâce à matplotlib. Pour cela, on utilise la fonction plt.plot(A,B) de matplotlib

In [23]:
%matplotlib inline     
# cette ligne est nécessaire si on veut afficher les graphes entre les cellules
import numpy as np
import matplotlib as mp
import matplotlib.pyplot as plt
In [24]:
X=np.linspace(0,2*np.pi,400)       # On crée un tableau X, de taille 400, qui va de 0 à 2 pi
                                   # Attention, pi n'est pas connu d'avance par matplotlib
Y=np.tanh(X)                       # On crée un tableau Y avec les tangentes hyperboliques des valeurs de X
plt.plot(X,Y)                      # On trace la courbe Y(X), avec des traits reliant les couples de points formés
                                   # par les éléments de X et Y
Out[24]:
[<matplotlib.lines.Line2D at 0x7f67fd37f1f0>]

ATTENTION ! Un graphe qui n'a pas de titre aux axes, pas de légende, pas d'explication, n'est pas un bon graphe !

S'il est admissible de faire un graphe sans rien lorsqu'on recherche la bonne visualisation, il faut à la fin PENSER à mettre un titre, à nommer les axes et à mettre une légende !!!

L'ensemble des modifications possibles pour un graphe est assez étendu, voici un exemple sommaire mais déjà suffisant.

In [25]:
x=np.arange(0,2*np.pi,.03) # définition des tableaux à tracer
y=np.tanh(x)
yy=np.cos(x)
In [26]:
plt.figure(0, figsize=(12,7))     # Crée la figure 0, de taille 7(horiz.) x 5(vert.)
plt.plot(x,y)                     # Trace y vs x
plt.plot(x,yy, '--', color='red') # Trace yy en fonction de x, en ligne --, de couleur rouge
plt.ylim(-1.1,1.1)                # Change l'échelle en y
plt.xlim(0,7)                     # change l'échelle en x

plt.xlabel('temps (s)', fontsize=14)                  # titre de l'axe x, en taille de font 14
plt.ylabel("amplitude d'oscillation", fontsize=14)    #  Idem axe y
plt.title('Exemple de graphe commente', fontsize=18)  # Titre du graphe
plt.legend(['tan. hyperb.','cosinus'],loc='lower right', fontsize = 12)
#           ici une liste dea courbes 
#           DANS l"ORDRE D'APPARITION
#           loc : pour situer la légende dans le graphe   
Out[26]:
<matplotlib.legend.Legend at 0x7f67fd2f4610>

Galleries de graphes de matplotlib (très utiles)

Les examples :

In [27]:
from IPython.display import HTML
HTML('<iframe src=https://matplotlib.org/gallery.html width=800 height=500></iframe>')
/usr/local/lib/python3.8/dist-packages/IPython/core/display.py:717: UserWarning: Consider using IPython.display.IFrame instead
  warnings.warn("Consider using IPython.display.IFrame instead")
Out[27]:

FIN