Comment créer automatiquement à l’aide de Python et de LaTeX un arbre de Bernoulli en probabilités ?
Je vais vous montrer l’utilisation d’une fonction Python que je viens d’écrire, et que les abonné·e·s trouveront en fin d’article.
LaTeX et Python: exemples d’arbres de Bernoulli
La fonction Python qui créée en LaTeX un arbre de Bernoulli
L’appel de la fonction nécessite obligatoirement deux paramètres: la hauteur de l’arbre et la probabilité du succès. Par exemple,
>>> bernoulli_tree(3,0.2)
va automatiquement créer un fichier \(\LaTeX\) puis le compiler, pour ensuite afficher le PDF:
Comme on peut le remarquer, les points décimaux ont été remplacés par une virgule.
Une arbre de Bernoulli avec des probabilités fractionnaires: l’option “fraction”
Si l’on souhaite que les probabilités s’affichent sous forme fractionnaire, on utilisera l’option “fraction”:
>>> bernoulli_tree(3,0.2,fraction=True,espv=0.7)
Remarquez ici la présence d’un autre paramètre : espv, qui permet d’espacer davantage les nœuds du dernier niveau afin que les fractions s’affichent correctement.
Si la probabilité du succès ne peut pas être écrite sous forme décimale, mais uniquement sous forme fractionnaire, on pourra écrire:
>>> bernoulli_tree(3,'1/3',fraction=True,espx=1,espv=0.8,espvinter=0.5)
Un arbre moins large: l’option espx
>>> bernoulli_tree(3,0.2,espx=1,espv=0.7,espvinter=0.5)
Remarquez ici la présence du paramètre espvinter qui désigne l’espace vertical entre les “groupes” de couples (succès,échec) au dernier niveau.
Par de nom à la racine
Si vous ne souhaitez pas que \(\Omega\) apparaisse à la racine, tapez:
>>> bernoulli_tree(3,'1/3',fraction=True,espx=1,espv=0.8,espvinter=0.5,root='')
Changer les styles
On peut changer les styles TiKZ de tous les objets de l’arbre (branches, nœuds et probabilités):
>>> bernoulli_tree(3,0.2,fraction=True,espv=1.1,espvinter=0.5,stylebranche='line width=1pt,color=blue!50!black',stylenoeud='color=red',styleproba='midway,circle,scale=.5,text=red,draw=red,fill=red!20',filename='arbre-bernoulli-06')
Ici, la seule limite est celle de votre imagination ! Vous pouvez utiliser tous les styles TiKZ que vous souhaitez pour personnaliser votre arbre. Alors, lâchez-vous !
Des fractions écrites “en ligne”
Jouer avec les espaces verticaux est quelques fois pénibles. Dans ce cas, on pourra utiliser la syntaxe suivante:
>>> bernoulli_tree(3,Fraction(3,7),filename='arbre-bernoulli-07')
La fonction Python qui permet de construire en LaTeX un arbre de Bernoulli
Les paramètres utilisés pour la fonction Python permettant de construire en LaTeX un arbre de Bernoulli
- niveau : nombre entier désignant le niveau de l’arbre (nombre de répétitions de l’expérience de Bernoulli);
- proba: nombre (float) ou chaîne de caractères (de la forme ‘p/q’) ou objet type Fraction(p,q)
- succes = ‘S’: lettre désignant le succès. Par défaut, “S”
- espv = 0.5: espace vertical entre les nœuds “succès/échec”
- espvinter = 1: espace vertical (en cm) entre les blocs “succès/échec”
- espx = 2: espace horizontal (en cm) entre chaque niveau
- fraction = False: booléen pour signifier si les probabilités doivent être écrites sous forme fractionnaire ou non
- root = ‘$\Omega$’: nom de la racine (syntaxe \(\LaTeX\) mathématique ou pas)
- stylebranche = ”: style TiKZ des branches
- stylenoeud = ”: style TiKZ des nœuds (les événements “succès” et “échecs”)
- styleproba = ‘midway,fill=white,scale=.5’: style TiKZ des probabilités sur les branches
- filename = ‘arbre’: nom du fichier à sauvegarder et à compiler
Les modules
- ‘fraction’
- >>> pip install fractions ou conda install fractions
- ‘os’ et ‘os.path’ (pour manipulation système: sauvegarde, compilation)
Autres remarques
Il faut bien entendu au préalable avoir installé une distribution \(\LaTeX\).
La fonction Python
from fractions import Fraction def bernoulli_tree( niveau,\ proba,\ succes = 'S',\ espv = 0.5,\ espvinter = 1,\ espx = 2,\ fraction = False,\ root = '$\\Omega$',\ stylebranche = '',\ stylenoeud = '',\ styleproba = 'midway,fill=white,scale=.5', filename = 'arbre'): # Stéphane Pasquet # mathweb.fr # 2022/07/02 # https://www.mathweb.fr/euclide/2022/07/02/latex-et-python-creer-un-arbre-de-bernoulli-automatiquement/ if fraction: proba_num = Fraction(str(proba)).numerator proba_denom = Fraction(str(proba)).denominator if isinstance(proba,float): proba_echec_num = Fraction(str(1-proba)).numerator proba_echec_denom = Fraction(str(1-proba)).denominator else: proba_echec_num = Fraction(str(1-Fraction(proba))).numerator proba_echec_denom = Fraction(str(1-Fraction(proba))).denominator proba = '$\\frac{'+str(proba_num)+'}{'+str(proba_denom)+'}$' probaechec = '$\\frac{'+str(proba_echec_num)+'}{'+str(proba_echec_denom)+'}$' else: probaechec = str(1-proba).replace(".",",") proba = str(proba).replace(".",",") tex = '\\documentclass{standalone}\n' tex += '\\usepackage{tikz}\n' tex += '\\usetikzlibrary{calc}\n' tex += '\\setlength{\\parindent}{0pt}\n' tex += '\\begin{document}\n' tex += '\\begin{tikzpicture}\n' tex += '\\tikzstyle{branche} = [ '+stylebranche+' ]\n' tex += '\\tikzstyle{noeud} = [ '+stylenoeud+' ]\n' tex += '\\tikzstyle{proba} = [ '+styleproba+' ]\n' level = niveau echec = '\\overline{' + succes + '}' # placement des noeuds while level != 0: if level == niveau: y = 0 for i in range(2**level): if i%2 == 0: tex += '\\node[noeud] (N' + str(level) + '-' + str(i) + ') at ({'+str(espx)+'*'+str(level)+'},'+str(y)+') {$'+succes+'$};\n' y -= espv else: tex += '\\node[noeud] (N' + str(level) + '-' + str(i) + ') at ({'+str(espx)+'*'+str(level)+'},'+str(y)+') {$'+echec+'$};\n' y -= espvinter else: for i in range(2**level): if i%2 == 0: tex += '\\node[noeud] (N' + str(level) + '-' + str(i) + ') at ($0.5*(N'+str(level+1)+'-'+str(2*i)+')+0.5*(N'+str(level+1)+'-'+str(2*i+1)+')+(-'+str(espx)+',0)$) \ {$'+succes+'$};\n' else: tex += '\\node[noeud] (N' + str(level) + '-' + str(i) + ') at ($0.5*(N'+str(level+1)+'-'+str(2*i)+')+0.5*(N'+str(level+1)+'-'+str(2*i+1)+')+(-'+str(espx)+',0)$) \ {$'+echec+'$};\n' level -= 1 # tracé des branches tex += '\\node[left,noeud] at ($0.5*(N1-0)+0.5*(N1-1)+(-'+str(espx)+',0)$) {'+root+'};\n' tex += '\\draw[branche] ($0.5*(N1-0)+0.5*(N1-1)+(-'+str(espx)+',0)$) -- (N1-0) node[proba] {'+proba+'};\n' tex += '\\draw[branche] ($0.5*(N1-0)+0.5*(N1-1)+(-'+str(espx)+',0)$) -- (N1-1) node[proba] {'+probaechec+'};\n' for lev in range(1,niveau): for i in range(2**lev): tex += '\\draw[branche] (N'+str(lev)+'-'+str(i)+'.east) -- (N'+str(lev+1)+'-'+str(2*i)+') node[proba] {'+proba+'};\n' tex += '\\draw[branche] (N'+str(lev)+'-'+str(i)+'.east) -- (N'+str(lev+1)+'-'+str(2*i+1)+') node[proba] {'+probaechec+'};\n' tex += '\\end{tikzpicture}\n' tex += '\\end{document}' # sauvegarde du fichier LaTeX from os.path import isfile from os import remove, system if isfile(filename+".tex"): remove(filename+".tex") fichier = open(filename+".tex","x") fichier.write(tex) fichier.close() # compilation PdfLaTeX dans le répertoire courant cmd = "pdflatex --shell-escape -synctex=1 -interaction=nonstopmode "+filename+".tex" system(cmd) cmd = "START "+filename+".pdf" system(cmd)