Index de l'article

Objectif

Réaliser avec python et la bibliothèque turtle sous Thonny des graphiques du style du dessous. L'idée est de s'amuser, de tester puis de comprendre le fonctionnement du script final. Les principes de programmation utilisés sont:

  • l'affectation des variables
  • quelques commandes de la bibliothèque turtle
  • l'utilisation d'un dictionnaire
  • la boucle for
  • la division entière (modulo)

Pour le principe de fonctionnement de cette table de multiplication d'un nouveau genre partant de turtle et pointant vers Mandelbrot
voir cette vidéo (de Burkard Polster)

Documentation

Tous les scripts suivants utilisent essentiellement la bibliothèque turtle nativement présente dans python donc tous les scripts commenceront par "from turtle import*".
En dessous quelques liens vers une documentation de Laurent Pointal mise à disposition sur son site https://perso.limsi.fr/pointal/python:abrege.

Les étapes constructivistes du script ultime


Création d'un cercle avec Turtle

Objectif

Tracer un cercle centré dans la fenêtre turtle. Nécessite au début du script un décalage verticalement vers le bas de la longueur du rayon.

Script

from turtle import *

penup()
goto(0,-100)
pendown()

circle(100,270)
penup()
home()

Analyse

  • penup() => lève le crayon (pas de trace)
  • goto(x,y) => se déplace vers x,y
  • pendown() => baisse le crayon (trace) 
  • circle(rayon, angle) => dessine un cercle
  • home() => Retour au point 0,0 de la tortue

Ici je descends de 100 pt sur l'axe des y vers le bas sans tracer de ligne puis je trace un cercle de rayon 100 et d'angle 270°. J'en conclue que je pourrai faire des fragments d'arc de cercle de n parties sur 360°.

 


Découpage du cercle en x arcs de cercle

Objectif

Découper un cercle en x parties égales. npt représente le nombre de points, ici je prends 11 parties. Comme la logique de découpe est reproductible j'ai l'idée d'utiliser la boucle bornée for ;)!

Script

from turtle import *

npt=11

penup()
goto(0,-100)
pendown()

for i in range(npt):
    dot()
    print(position())
    circle(100,360/npt)

penup()
home()

Analyse

  • ntp => nombre de points = nombre de fragments d'arc = 11 dans cet exemple
  • for i in range (npt) => création de npt entier allant de 0 à 10 (npt-1=11-1=10)
  • dot() => crée un point à la position de la tortue
  • position() => relève les coordonnées (x,y) de la position de la tortue
  • print() => affiche dans shell => utile pour voir ce que donne la commande position()
  • circle(100,360/npt) => crée un arc de cercle de rayon 100 et de longueur d'arc 360/11 ième dans cet exemple
    (si vous utilisez le mode débug de Thonny, vous noterez que circle crée des arcs de 32.72° en partant du dernier point placé - ce qui est cool)

Je dispose de la base qui me permettra de construire la suite du script car je visualise les segments d'arc et j'ai les coordonnées des points. Je veux maintenant afficher les n° des points de 0 à 11 sur le cercle et surtout je veux enregistrer les coordonnées quelque part. Pour l'enregistrement je pense soit à une liste, soit à un dictionnaire (je pense que les deux fonctionneront!) 

A ce niveau de maîtrise, si je vous êtes curieux vous pouvez aller voir:

et retourner un peu en enfance ;)

 


Affichage des n° des points sur le cercle et ajout de la liste dans un dictionnaire

Objectif

Afficher près de chaque point son label (son n°  de 0 à npt-1) et enregistrer les coodonnées des points dans un dictionnaire. L'intérêt du dictionnaire est de pouvoir par la suite appelé les coordonnées d'un point en utilisant son nom ou label ;).

Je veux aussi pouvoir jouer avec le rayon du cercle pour modifier si besoin sa taille afin de mieux voir les noms des points si besoin.

Script

from turtle import *
rayon=200 #rayon du cercle
npt=11 #nbre de points
pos={} #dictionnaire

penup()
goto(0,-rayon)
pendown()

for i in range(npt):
    dot()
    write(i)
    pos[i]=position()
    print("coord=",position(),"val dans dictionnaire=",pos[i])# pour comprendre
    circle(rayon,360/npt)

print(pos)# pour visualiser le dictionnaire label:(valeurs)
penup()
home()

Analyse

  • # symbole me permettant d'ajouter dans mon script des commentaires
  • variable rayon=200 => pour pouvoir modifier le rayon de mon cercle => donc je dois remplacer la valeur 100 dans mon goto et dans circle par la variable rayon
    (vous noterez le commentaire)
  • pos={} => création d'un dictionnaire se nommant "pos". Comme entre les accolades il n'y a rien, mon dictionnaire est vide
  • goto(0,-rayon) => remplace maintenant le goto(0,-100) car le décalage vers le bas doit rester cohérent avec ma valeur de rayon
  • write(i) => commande qui écrit la valeur de i dans turtle à l'endroit où se trouve la tortue - ce qui tombe bien après le dot()
  • pos[i]=position() => affectation des coordonnées (position()) dans le dictionnaire
    pos[0] = (0.00,-200.00) 
    pos[1] = (108.13,-168.25)
    ...
  • print("coord=",position(),"val dans dictionnaire=",pos[i]) => donne l'affichage suivant dans le shell
    coord= (0.00,-200.00) val dans dictionnaire= (0.00,-200.00)
    ...
    coord= (-108.13,-168.25) val dans dictionnaire= (-108.13,-168.25)
    Je comprends donc que le dictionnaire pos contient les entrées i=0, i=1... et que je peux appeler chaque coordonnées avec pos[i]
  • print(pos) => n'est plus dans la boucle for donc affichage final du dictionnaire 
    {0: (0.00,-200.00), 1: (108.13,-168.25), 2: (181.93,-83.08), 3: (197.96,28.46), 4: (151.15,130.97), 5: (56.35,191.90), 6: (-56.35,191.90), 7: (-151.15,130.97), 8: (-197.96,28.46), 9: (-181.93,-83.08), 10: (-108.13,-168.25)}
    soit { label 0 : valeur associée au label 0 , label 1 : valeur associée au label 1 , ... , label final : valeur associée au label final }

Le plus dur me semble fait, je dispose des coordonnées, je peux appeler les coordonnées, et à l'aide d'un pendown() et de goto(x,y) je dois bien pouvoir faire un trait entre deux points.

 


Création d'un trait entre deux coordonnées arbitrairement choisies i et j

Objectif

Tout est dans le titre... Et je constate que le monde est bien fait ;)))

Script

from turtle import *
rayon=200 #rayon du cercle
npt=11 #nbre de points
pos={} #dictionnaire

penup()
goto(0,-rayon)
pendown()

for i in range(npt):
 
    dot()
    write(i)
    pos[i]=position()
    circle(rayon,360/npt)

penup()
home()

# tracer des traits
goto(pos[2])
pendown()
goto(pos[4])

Analyse

  • notez le penup () après la boucle
  • goto(pos[2]) => goto((181.93,-83.08)) = goto (181.93,-83.08) = goto ( x , y) dans l'exemple du dessus
    puisque penup() avant le commentaire #tracer la tortue va se déplacer à la position 2
    puis
  • pendown() => le stylo trace 
  • goto(pos[4]) => je trace donc un trait de la position 2 à la position 4

L'idée maintenant est d'insérer dans la boucle ce principe de traçage de traits. Je dois relier le point i au point  j qui est le double de i si je travaille avec la table de 2. Si vous ne comprenez pas, je vous conseille de revoir la vidéo suivante: https://youtu.be/qhbuKbxJsk8

 


En approche de le script ultime - boucle et tracer des traits

Objectif

Insérer dans une boucle le tracé des traits en appliquant le principe pour la table de 2. Mais je veux faire tous les jolis dessins de Burkard Polster - Je pense alors variable ;)

Script

from turtle import *
rayon=200 #rayon du cercle
npt=10 #nbre de points
table=2 #variable pour la table de multiplication
pos={} #dictionnaire

penup()
goto(0,-rayon)
pendown()

for i in range(npt):
    dot()
    write(i)
    pos[i]=position()
    circle(rayon,360/npt)

penup()
home()
print(pos) #pour comprendre

# tracer des traits
for i in range (npt):
    penup()
    j=i*table
    goto(pos[i])
    pendown()
    goto(pos[j]) # ceci est la ligne 27

Analyse

  •  table=2 => valeur de la table arbitrairement choisie, je déclare une variable car vous vous doutez bien que je veux faire des dessins avec 2, 25, 51...

En fin de script

  • # tracer des traits => commentaire début du tracé
  • for i in ... => je boucle de 0 à 10 dans le cas présent => donc j'envisage 10 traits
  • j=i*table => calcul la valeur de mon point d'arrivé pour la table de 2 dans le cas présent
    et je me doute que je ne traite pas les valeurs finales du genre si i=10 alors j=10*2=20 et je n'ai pas dans mon dictionnaire l'entrée 20:

Je comprends le message d'erreur dans le shell... je n'ai que 10 entrées dans mon dictionnaire pour des i allant de 0 à 9 donc évidement que cela coince pour j quand i=5. Je dis i=5 car ma tortue est bloquée dans mon dessin sur cette valeur ;)

 


Script ultime - le graal

Objectif

Pouvoir dormir ce soir ;) et vous proposer, j'en suis assez fier, un script qui fonctionne dans tous les cas de figure...

Pour vous impressionner avec un joli dessin, vous noterez les valeurs utilisées dans la fenêtre Python Turtle Graphics:

  • rayon=200 #rayon du cercle
  • npt=100 #nbre de points
  • table=35 #Saisir ici des valeurs entières

Script

from turtle import *
# jouer avec les valeurs npt et table
# si dessin pas à la bonne taille jouer alors avec rayon

rayon=200 #rayon du cercle
npt=100 #nbre de points
table=35 #Saisir ici des valeurs entières

# la suite n'est pas à modifier!!

pos={} #dictionnaire

penup()
goto(0,-rayon)
pendown()

for i in range(npt):

    dot()
    write(i)
    pos[i]=position()
    circle(rayon,360/npt)


penup()
home()

# tracer des traits

for i in range (npt):
    penup()
    j=i*table
   
    goto(pos[i])
    pendown()
    goto(pos[j%npt]) # voir l'analyse pour comprendre ce modulo

Analyse

En vidéo avec Thonny et le mode débug. L'idée est de résoudre le problème de l'étape précédente pour des j supérieurs au nombre de points de mon cercle. La discussion tourne donc autour de la dernière ligne:
    goto(pos[j%npt]) # voir l'analyse pour comprendre ce modulo