Category ArchivePython

Créer un GIF avec \(\LaTeX\), Python et ImageMagick

Le résultat à obtenir

Dans un article précédent, je vous expliquais comment créer un GIF avec \(\LaTeX\), et avec une manipulation Gimp. Trouvant la dernière étape un peu… (comment dire pour rester poli ?) … pénible, je vous propose un combi \(\LaTeX\) + Python + ImageMagick.

Une enveloppe astroïdale obtenue en Python avec Turtle

L’enveloppe de cette famille de cercles est une astroïde

L’objectif de cet article est de construire cette suite de cercles rouges à l’aide de Python et de son module Turtle.

Approche mathématique

Avant toute chose, il est nécessaire de comprendre comment sont obtenus tous les cercles rouges.

Si on regarde et analyse bien la figure, les tracés suggèrent que pour un angle \(\alpha\) donné, exprimé en degré, on trace un segment d’origine O (si on se place dans un repère, c’est l’origine) et d’angle \(\alpha\), qui coupe l’un des côté du carré inscrit dans le cercle principal.

Prenons le côté en haut à droite (donc dans le cadran x > 0 et y > 0 si on se ramène à un repère). Il a pour équation \(y=-x+R\) si on considère que le cercle principal a pour rayon \(R\). Notons I le point d’intersection de la droite d’équation \(y = x\tan(\alpha)\), qui forme un angle de \(\alpha\) avec l’horizontale, avec le segment d’équation \(y=-x+R\). Alors, ses coordonnées vérifient:$$\begin{cases}y_I=-x_I+R\\y_I=x_I\tan(\alpha)\end{cases} $$Donc:$$x_I\tan(\alpha)=-x_I+R$$d’où:$$x_I=\frac{R}{\tan(\alpha)+R}.$$

Une fois les coordonnées de I connues, on calcule la longueur IM, où M est le point du cercle principal de coordonnées \(R\cos\alpha;R\sin\alpha)\), à l’aide de la formule vue en classe de Seconde:$$IM = \sqrt{(x_I-x_M)^2 + (y_I-y_M)^2}.$$On peut alors tracer le cercle de centre I et de rayon IM : c’est un des cercles rouges.

Avec Turtle

Il faut faire appel à quelques méthodes du module Turtle; inutile donc d’écrire:

from turtle import *

En effet, le mieux est de n’importer que les méthodes qui nous intéressent. Il en est de même pour le module math, où seules les méthodes sin, cos, tan et pi sont nécessaires (pour la racine carrée, on élève à la puissance 0.5).

On commence donc par tracer un cercle (avec Turtle, c’est un peu… comment dire poliment ? … je trouve pas ! Désolé !) en se déplaçant d’abord en bas de la fenêtre puis en traçant le cercle. Ensuite, on en profite pour tracer le carré inscrit dans le cercle (avec “goto”, comme le stylo est déjà baissé, ça trace les segments).

Maintenant, on fait une boucle itérative sur l’angle variant de 0 à 359. Si vous observez bien, je ne me suis pas embêté avec les cas où l’angle est égal à 90°, 180° et 270° car ça n’a que peu d’importance au final du point de vue visuel). En fait 180° ne pose pas de problème pour la tangente, mais peu importe… Ouais, je suis une grosse feignasse !…

Remarquez aussi que j’ai pris \(R=300\) car la fenêtre par défaut fait 800×800. “300” me semblait un bon compromis. Voilà donc le programme:

Alors là, les plus observateurs.trices. d’entre vous me diront : “t’es qu’un charlatant ! Le GIF n’est pas exactement ce que fait ce programme…” et c’est vrai ! C’est en fait un ancien GIF qui traînait sur mon disque dur… quand je vous disais que j’étais une grosse feignasse !

En attendant, si vous souhaitez télécharger le programme directement plutôt que de vous embêter à le réécrire à la main, c’est sur cette page.

Saut, parabole et physique

Cet article est principalement destiné aux élèves de 1ère Math Spécialité.

Parlons dans cet article de mathématiques, et plus précisément du second degré. Alors, vous allez me dire : “oui, mais bon ! C’est super simple, il suffit de connaître les formules et on sait tout faire.” Ce n’est pas totalement faux… mais ce n’est pas suffisant ! Il y a beaucoup de situations qui font intervenir le second degré, notamment ce problème…

Les classes en Python

Dans le programme de Terminale NSI, la notion de classes apparaît. En 1ère, on ne doit pas en parler car la Première est une classe d’initiation avancée. Comment se présente une classe ? Et en quoi peut-elle aider ? Voici quelques éléments de réponse.

Etude d’une suite définie par \(u_{n+1} = f(u_n)\)

C’est un classique dans l’étude des suites : on considère une fonction f et on définit une suite par son premier terme \(u_0\) et par la relation \(u_{n+1}=f(u_n)\) pour tout entier naturel n.

Voyons cela avec l’exemple où \(f(x)=\frac{ax+b}{x^2-3x+2}\)…

Introduction aux matrices de rotation

Considérons la configuration suivante :

Dans le repère orthonormé d’origine O, A(x;y) est un point quelconque et A'(x’;y’) est son image par la rotation de centre O et d’angle \(\theta\). On cherche à exprimer x’ et y’ en fonction de x, y et \(\theta\)…

Reconnaître une chaîne de caractères palindrome avec Python

Dans cet article, nous allons manipuler les chaînes de caractères ainsi que les dictionnaires en Python.

Décomposition en produit de facteurs premiers sous \(\LaTeX\) avec Python

Cette tâche semble simple, mais pas tant que ça en définitive… Je voulais en effet créer une commande \(\LaTeX\) acceptant un paramètre (un nombre entier) qui décompose ce dernier en produit de facteurs premiers, et ce à l’aide de Python.

Il est donc naturel de penser à Pythontex. ça, c’est bon… Le problème est que quand on utilise Pythontex, on ne peut pas facilement passer un argument. Je m’explique… avec un code FAUX :

\documentclass[12pt,a4paper]{article}
\usepackage[utf8]{inputenc}
\usepackage[french]{babel}
\usepackage[T1]{fontenc}
\usepackage{pas-math}
\usepackage{pythontex}

\newcommand{\decomp}[1]{
\py{decompose(#1)}
}
\begin{document}
\decomp{120}
\end{document}

Ce script suppose connue la fonction Python decompose (préalablement définie). Le problème ici est que l’argument #1 ne passe pas… Ce code ne donne donc rien d’autre qu’une erreur.

Il faut donc utiliser une astuce… que voici:

\newcommand{\ifactors}[1]{
\begingroup\edef\x{\endgroup
    \noexpand\py{decompose(#1)}}\x}

Ensuite, j’ai voulu enrichir la macro \ifactors de sorte à ce qu’elle puisse afficher en ligne ou en colonne la décomposition comme ceci :

Cette idée m’est venue suite à un échange avec un abonné qui avait des difficultés à faire appel à Xcas pour cette même décomposition (outil inclus dans mon package pas-cours.sty). Il est vrai que faire tourner Xcas dans un document\(\LaTeX\) n’est pas chose simple et mon package pas-cours fait appel à Xcas pour ce genre de calculs. Il fallait donc que je trouve un moyen de contourner ceci.

Pour les abonné.e.s de mathweb.fr, vous trouverez le script \(\LaTeX\) qui inclus bien sûr le script Python de la décomposition. Il y a aussi en en-tête la chaîne de compilation à respecter pour faire tourner Pythontex. Ça se passe sur cette page.

Les k plus proches voisins

Dans le programme de NSI, on abord l’algorithme des k plus proches voisins. Je vais tenter de vous expliquer avec un schéma ce que cela signifie que de trouver de tels voisins.

Prenons l’exemple de points dans un repère orthonormé dans le carré [0;10]x[0;10] : ils sont soit bleus, soit rouges. On dit que “bleu” et “rouge” sont les classes des points.

Si on met au hasard un point dans ce même carré, on peur se demander de quels points est-il le plus proche, ce qui donnera sa classe éventuelle.

J’ai fait un programme en Python qui:

  • choisit au hasard 10 points rouges et 10 points bleus et qui les affichent;
  • choisit un point vert au hasard;
  • qui détermine la distance entre le point vert et chacun des autres points;
  • qui détermine enfin la classe éventuelle du point vert et qui affiche les distances prises en compte.

On obtient par exemple :

Pour télécharger le programme Python, rendez-vous sur cette page.

Lemniscate et parabole

Le but est de créer le GIF suivant:

Code Python

tikz = open("tikz.tex", "w")
text = ''
      
x = -5
while x < 5:
    y = 1/x
    r = (x**2+y**2)**0.5
    if r<10 and abs(y)<10:
        text = text + '\\begin{tikzpicture}[>=latex]\\labase'
        k = -5
        while k <= x:
            p = 1/k
            rr = (k**2+p**2)**0.5
            if rr<10 and abs(p)<10:
                text = text+'\\draw[red] ('+str(k)+','+str(p)+') circle ('+str(rr)+' cm);\n'
            k += 0.1
        text = text + '\\end{tikzpicture}\n'
    x += 0.1

tikz.write(text)
tikz.close()

Ce script génère un fichier tikz.tex dans lequel les dessins sont faits.

Le fichier \(LaTeX\)

\documentclass{article}
\usepackage{tikz}
\usepackage[paperwidth=10cm,paperheight=10cm,margin=0cm]{geometry}
\setlength{\parindent}{0pt}
\newcommand{\labase}{%
\clip (-5,-5) rectangle (5,5);
\draw[->] (-5,0) -- (5,0);
\draw[->] (0,-5) -- (0,5);
\draw plot[domain=-5:-0.1,samples=100] (\x,{1/\x});
\draw plot[domain=0.1:5,samples=100] (\x,{1/\x});
\node[below left] at (0,0) {$O$};
}
\begin{document}
\include{tikz}
\end{document}

En compilant via PdfLaTeX (par exemple), on génère un PDF de 49 pages.

Construction du GIF

J’ai pour habitude d’utiliser GIMP en ouvrant le PDF, puis en inversant l’ordre des calques, puis en sauvegardant en tant qu’animation dans un fichier .gif. Et voilà !

Avec Pythontex

On peut bien entendu créer un tel GIF directement avec pythontex:

% en utilisant Pythontex
\documentclass{article}
\usepackage{tikz}
\usepackage{pythontex}
\usepackage[paperwidth=10cm,paperheight=10cm,margin=0cm]{geometry}
\setlength{\parindent}{0pt}
\newcommand{\labase}{%
\clip (-5,-5) rectangle (5,5);
\draw[->] (-5,0) -- (5,0);
\draw[->] (0,-5) -- (0,5);
\draw plot[domain=-5:-0.1,samples=100] (\x,{1/\x});
\draw plot[domain=0.1:5,samples=100] (\x,{1/\x});
\node[below left] at (0,0) {$O$};
}
\begin{document}
\begin{pycode}
x = -5
while x < 5:
    y = 1/x
    r = (x**2+y**2)**0.5
    if r<10 and abs(y)<10:
        print('\\begin{tikzpicture}[>=latex]\\labase')
        k = -5
        while k <= x:
            p = 1/k
            rr = (k**2+p**2)**0.5
            if rr<10 and abs(p)<10:
                print('\\draw[red] ('+str(k)+','+str(p)+') circle ('+str(rr)+' cm);')
            k += 0.1
        print('\\end{tikzpicture}')
    x += 0.1
\end{pycode}
\end{document}