Logiciel libre de géométrie, d'analyse et de simulation multiplateforme par Yves Biton

Accueil Tutoriels l’API de MathGraph32

Programming a figure in Python : The jungler (advanced use)

modification vendredi 22 avril 2024.

Toutes les versions de cet article : [English] [français]



This articled is inspirer by this article of Vincent Pantaloni on APMEP website (in french) : https://afdm.apmep.fr/rubriques/ouvertures/mathematiques-du-jonglage/

Since version 7.9.1, MathGraph32 allows you to create objects in a figure using ¨Python language.

We will here generate an animated figure : the jungler.

This example uses advanced features of MathGraph32, including complex numbers.

Once the figure has appeared, click on button Start - Stop to launch the animation and click on the same button to stop it.

The animation can be very fast : replace in line 22 : addTimerButton(draw, 1/60) 1/60 by 1/120 (it is the animation frequency in seconds), click on button Execute the on button Start - Stop.

You can also change the balls numer (that has to be an odd numer) changing the line : n_balls = addCalc(’nballs’, ’5’) and for instance replacing 5 by 7.

More explanations here



Line 7 : ph = addCalc(’ph’, ’0’) creates in the MathGraph32 figure a eal calculation named ph with formula 0. This calculation object is returnes in Python variable ph (we could use another nmae but using the same name is better for code comprehension).

This figure creates a Start - Stop button on the top left corner of the figure with the following line :
addTimerButton(draw, 1/60)
When this button is clicked upon to launch the animation, function draw is called every 1/60 second.
Let’s have a look at function draw :

def draw():
        global valph
        valph += 0.0075
        giveFormulaTo('ph', str(valph))
        updateDependantDisplay(ph)

This function increases the global Python variable valph of 0.0075, gives this value to MathGrap32 calculation ph in the form of a formula contained in a string using MathGraph32 API function giveFormulaTo, the line updateDependantDisplay(ph) asks MathGraph32 to recalculate all the objects depending on calculation ph and to update their display (for the graphical ones). In particular in function make_ball all the balls are recalculated.

All the objecst created in function make_ball(i) (called for i in range 1 to n_balls) must be MathGraph32 objects. So imossible here to use a Python if else.

MathGraph32 Dooes not allow to add in a figure a calculation with a name already used for a former calculation.

That is the reason why all the objects used in this function are suffixed with i value.

An example :
At the first call of this function with i = 1, the following lines :

        stri = str(i)
        j = 'j' + stri # Nom du calcul qui repésente la valeur actuelle de i dans les calculs MathGraph32 suivants
        addCalc(j, stri)
<code>
will create a MathGraph32 calculation names nommé {j1} with formula '1'.
During the second call of this function with i = 2, a new calulation named {j2} will be created with formula '2'.

Llet's have a look at the following lines of function {make_ball} :
<code>
        ballph = 'ballph' + stri # Nom de calcul dans mtg32
        ball_ph = addCalc(ballph, f"mod(2.0 * (ph * nballs + {j}),nballs * 2)")

The first line creates a Python calculation named ballph (local to function make_ball).
Durng the first call to function make_ball, variable Python ballph contains the string ’ballph1’ that will fe used in the next line as name for the created MathGraph32 calculation(and will be returned in ball_ph Python
variable). :

ball_ph = addCalc(ballph, f"mod(2.0 * (ph * nballs + {j}),nballs * 2)")

Function addCalc of the l’API adds to the MathGraph32 figure a real calculation whose name is the first argument and second argument is the formula used to create this calculation. The Python object returned by this function is the created MathGraph32 object. (futher we use function addCalcComp in the same maner to create a complex MathGraph32 calculation).
Let us look at the formula used do create this calculation : f"mod(2.0 * (ph * nballs + j),nballs * 2)"
The f caracter preceeding the string indicates that the content of brackets {} has to be replaced by the content of the Python variable name of which is inside the brackets. Thus, during the creation of the calculation when i is equal to 1, the string used to define the formula will be : mod(2.0 * (ph * nballs + j1),nballs * 2). MathGraph32 knows calculations ph, nballs et j1 (defined before in make_ball) so this formula is valid for a MathGraph32 calculation.

MathGraph32 function mod (a, b) returns the rest of the euclidian division of a by b (the equivalent of a%b in Python).

Further the following line :

forcalc = f"si({ballph} <= nballs - 1, {airltor}, si({ballph} <= nballs ,rhand, si({ballph} <= 2*nballs - 1,{airrtol}, lhand)))"

defines a Python variable forcalc containing string representing a valid formula for a complex MathGraph32 calculation.

For instance, in this string, rhand refers to a complex MathGraph32 calculation created in line 82 containing the complex affix of the right hand depending on ph.

We could proceed differently without using MathGraph32 calculations and dynamical objects and recalculate and redisplay all the objects of the figure at each update of ph value of the figure but this would be slower. Imossible the to egt a frequency of 1/120 second.

MathGraph32 function if(testvalue, returnif1, returnelse) returns returnif1 if testvalue value is1 and returnelse f testvalue is not equal to 1. You can use it in a real or complex calculation.

The following line :

point = addPointZ(f"{forcalc}", '')

creates a point whose affix is given by the formula conained in Python variable forcalc. the second argument of this function is the name of the created point (here an empty string) and may be omitted : point = addPointZ(f"forcalc") will give the same result.