Growing daisies (Geogebra) — Les-mathematiques.net The most powerful custom community solution in the world

Growing daisies (Geogebra)

Bonjour à tous et à toutes.
Comment faites-vous pour définir des fonctions complexes d'une variable complexe avec Geogebra ?
La motivation (et l'explication du titre à deux balles) est en en pièce jointe.
Merci d'avance.
e.v.

[Image contenue dans le pdf joint. AD]115218
Personne n'a raison contre un enfant qui pleure.


Réponses

  • Bonsoir ev,

    Je sais que ce n'est pas ce que tu as demandé, mais ce graphe est tellement beau que j'ai décidé de le tracer avec SageMath. Je ne suis pas très fort là-dedans, donc il y a sûrement des maladresses, mais ça marche. On peut mettre le code dans un fichier appelé machin.sage (l'extension compte) et le lancer avec la commande 'sage machin.sage'. Voici le code :
    #! /usr/bin/env sage
    
    import os
    import matplotlib.pyplot as plt
    from sage.plot.colors import get_cmap
    
    plt.style.use('seaborn-white')
    
    x,y = var('x,y')
    R(z) = z^3 + (-0.2 + 0.11*i)/z^3
    f(z) = R(R(R(z))).real_part(hold=True)
    fxy(x,y) = R(R(R(x+i*y))).real_part(hold=True)
    
    npoints = 800
    graphe = contour_plot(
        fxy(x,y).simplify(), (x, -1.2, 1.2), (y, -1.2, 1.2), contours=[-2, 0, 2],
        fill=False, cmap=get_cmap([(0.4,0.4,0.4)]), linewidths=0.4,
        plot_points=npoints)
    
    outputDir = "/tmp/screenshots"
    os.makedirs(outputDir, exist_ok=True)
    # graphe.save(os.path.join(outputDir, "graphe.pdf"))
    graphe.save(os.path.join(outputDir, "graphe.png"), dpi=600)
    # graphe.save(os.path.join(outputDir, "graphe low dpi.png"), dpi=200)
    
    115212
  • C'est cré-cré beau.

    J'ai essayé avec Geogebra coordonnée par coordonnée. Je me suis fait jeter. Mon idée était de faire des animations.

    Merci beaucoup Brian.

    e.v.
    Personne n'a raison contre un enfant qui pleure.


  • Je l'ai fait avec Geogebra avec mais c'est assez laid avec les équations implicites. Je vais voir si on peut faire mieux.
    J'ai juste tapé ceci :
    R(z)=z^3+(-.2+.11i)/z^3
    f(z)=real(R(R(R(z))))
    f(x+yi)=0
    f(x+yi)=2
    f(x+yi)=-2
    

    Cela marche mieux quand on met trois équations implicites au lieu d'une.
    On obtient des résultats différents selon la fenêtre choisie. D'ailleurs il vaut mieux régler la fenêtre avant parce que ça rame beaucoup (du moins sur mon vieux Mac).
  • Merci Philippe.

    Je vais essayer ta syntaxe.

    Un Mac ? Grapher ne fait pas mieux ?

    amicalement,

    e.v.
    Personne n'a raison contre un enfant qui pleure.


  • Sans trop de surprise, je me suis fait lourder par Geogebra.
    Probablement trop vieux et ronchon.

    amicalement,

    e.v.
    Personne n'a raison contre un enfant qui pleure.


  • Tiens, ça n'a rien à voir mais en cherchant un peu sur le net des jolies figures du même style, je suis tombé sur le site https://complex-analysis.com que je ne connaissais pas.
    En faisant défiler les pages, on peut voir de jolies courbes de niveau ou des fractales.
  • Je ne sais pas si vous connaissez.
    C’est moins joli mais très intrigant à plusieurs points de vue :
    Le graphe contient la formule... https://fr.m.wikipedia.org/wiki/Formule_autoréférente_de_Tupper

    [Correction du lien. AD]
  • Excellent, Dom, je ne connaissais pas ! Ça me fait penser aux quines.

    P. S. : ton lien est cassé ; c'est sans doute vers cette page que tu voulais pointer.
  • @ Dom & Brian.

    Merci pour vos liens. Un poil hors-sujet, mais passionnants. Je connaissais le truc de Tupper grâce à ce Phôrüm.

    @ Philippe.

    Plus joli qu'efficace, mais bouderons-nous notre plaisir ?
    ça donne des idées de fonctions à essayer.
    Ta syntaxe passe sur Geogebra classic et c'est pas très beau effectivement.

    Bon dimanche,

    e.v.
    Personne n'a raison contre un enfant qui pleure.


  • J'ai modifié le code pour n'utiliser que Matplotlib (SageMath n'est plus nécessaire) et produire des animations. Le code produisant juste des images fixes est également là ; il y a juste quelques trucs à décommenter comme indiqué et la ligne prepareAnimation(...) à commenter pour le réactiver — j'ai un peu la flemme d'unifier la syntaxe d'entrée pour gérer les deux cas et documenter ça.

    On peut produire des animations en plein de formats grâce à matplotlib.animation.FFMpegWriter (j'ai testé MKV et MP4 en codec H264, ainsi que GIF animé). Exemple d'appel :
    machin.py 400 250 dark_background /tmp/fleurs.mkv
    
    Argument 1 : nombre de lignes et de colonnes de la « grille » sur laquelle on évalue la fonction.
    Argument 2 : nombre d'images de l'animation.
    Argument 3 : nom de la feuille de style Matplotlib choisie.
    Argument 4 : fichier de sortie. Passer un argument vide ("") pour une visualisation interactive (vitesse alors réglable avec 'interval' en ligne 77).

    La liste des feuilles de style Matplotlib disponibles peut être obtenue avec :
    import matplotlib.pyplot as plt
    print(" ".join(plt.style.available))
    
    Le code :
    #! /usr/bin/env python3
    
    import matplotlib.pyplot as plt
    import matplotlib.animation as mpl_anim
    import numpy as np
    import sys
    
    # Code pour une image fixe
    def prepareData(xmin, xmax, nPointsX, ymin, ymax, nPointsY):
        x = np.linspace(xmin, xmax, nPointsX)
        y = np.linspace(ymin, ymax, nPointsY)
        xMat, yMat = np.meshgrid(x, y)
        zMat = xMat + 1j*yMat
    
        def R(z):
            return z**3 + (-0.2 + 0.11j)/(z**3)
    
        vals = R(R(R(zMat))).real
        return x, y, vals
    
    
    def preparePlot(x, y, z, outFile=None, style=None):
        if style:
            plt.style.use(style)
        fig, ax = plt.subplots()
        ax.contour(x, y, z, (-2, 0, 2))
        ax.set_aspect('equal', adjustable='datalim') # repère orthonormé
        fig.set_size_inches(12, 10)
    
        if outFile:
            plt.savefig(outFile, dpi=600, bbox_inches="tight")
        else:
            plt.show() # affichage en direct
    
    
    # Code pour les animations
    def transition(i, Nt):
        x = i/Nt
        return 8*x*(1-x) - 1.0
    
    def transition2(i, Nt):
        x = 2*i/Nt
        tmp = x**2 if 2*i <= Nt else (2.0-x)**2
        return 2*tmp - 1
    
    
    def dataForFrame(i, Nt, zMat):
        def R(z):
            a = 1 + 1.0*transition2(i, Nt)
            b = 1 + 0.8*transition(i, Nt)
            c = 1 + 10*transition2(i, Nt)
            d = 1 + 0.8*transition(i, Nt)
            return a*z**3 + (-0.2*b + c*0.11j) / (d*z**3)
    
        return R(R(R(zMat))).real
    
    
    def prepareAnimation(x, y, nFrames, outFile=None, style=None):
        Nt = nFrames - 1
        xMat, yMat = np.meshgrid(x, y)
        zMat = xMat + 1j*yMat
    
        if style:
            plt.style.use(style)
        fig, ax = plt.subplots()
    
        if outFile:
            # Les deux paramètres suivants déterminent la taille de chaque image de
            # la vidéo produite :
            fig.set_dpi(225)
            # fig.set_size_inches(13, 11)
        else:
             # Taille de la figure à l'écran (je garde le nombre de dpi par défaut :
             # pourrait dépendre de l'écran / la config utilisateur).
            fig.set_size_inches(9, 8)
    
        cont = ax.contour(x, y, dataForFrame(0, Nt, zMat), (0,))
    
        def update(i):
            nonlocal cont
            for artist in cont.collections:
                artist.remove()  # https://stackoverflow.com/a/42398244
            cont = ax.contour(x, y, dataForFrame(i, Nt, zMat), (-2, 0, 2))
            return cont.collections
    
        # 'interval' influence plt.show() mais pas le FFMpegWriter
        anim = mpl_anim.FuncAnimation(
            fig, update, frames=nFrames, interval=50, repeat=True, blit=True)
    
        if outFile:
            # Testé outFile avec les extensions .mp4, .mkv, .gif ; toutes trois
            # produisent bien une vidéo. Beau résultat avec 1200 points
            # (sys.argv[1]) et 500 images.
            anim.save(outFile, writer=mpl_anim.FFMpegWriter(fps=25, bitrate=-1))
        else:
            # Pour une animation interactive fluide, ne pas passer un trop grand
            # nombre de points (sys.argv[1]). Sur mon ordi, le résultat est sympa
            # avec 300 points et 500 images.
            plt.show()
    
    
    def main():
        # Code pour les images fixes (désactivé pour le moment)
        # nPoints = int(sys.argv[1])
        # style = sys.argv[2]
        # if style:
        #     print(f"Using style '{style}'")
        # outFile = sys.argv[3] if len(sys.argv) > 3 else ""
        nPoints = int(sys.argv[1])
        nFrames = int(sys.argv[2])
        style = sys.argv[3]
        if style:
            print(f"Using style '{style}'")
        outFile = sys.argv[4] if len(sys.argv) > 4 else ""
    
        x, y, z = prepareData(-1.2, 1.2, nPoints, -1.2, 1.2, nPoints)
        # Ligne pour les images fixes commentée :
        # preparePlot(x, y, z, outFile=outFile, style=style)
        prepareAnimation(x, y, nFrames, outFile=outFile, style=style)
    
        sys.exit(0)
    
    
    if __name__ == "__main__": main()
    
    Vidéo et images en meilleure qualité sur imgur.com.115284
    115286
  • Magique !

    Prévoir un message d'avertissement pour les épileptiques, toutefois.

    amicalement,

    e.v.
    Personne n'a raison contre un enfant qui pleure.


  • La taille du GIF animé attaché à mon message précédent est limitée à 4,77 Mo. Difficile de faire une vidéo satisfaisante qui tient là-dedans... mais celle que j'ai mise sur imgur.com prend un peu plus son temps.

    J'ai légèrement mis à jour le script posté ci-dessus pour mettre en évidence la façon dont on peut régler la résolution de la vidéo obtenue (ou la taille de la fenêtre en mode interactif).

    Sur mon ordi un peu ancien (2008 ou 2009), j'obtiens une visualisation interactive satisfaisante avec :
    machin.py 300 500 dark_background ""
    
    Pour avoir une belle vidéo, fluide et en bonne résolution (1440×1080, 25 images/s, codec H.264, taille fichier résultant 8,8 Mo), on peut faire :
    machin.py 1200 500 dark_background sortie.mkv
    
    Mon code utilise (matplotlib et) FFmpeg, mais comme indiqué ici, matplotlib.animation.FFMpegWriter peut aussi utiliser AVConv ou ImageMagick pour fabriquer les vidéos.
  • Finalement, pour que les choses restent simples, j'ai préféré faire deux scripts séparés : un pour produire des images fixes et l'autre pour les vidéos. Le second doit être compatible avec ce que j'ai écrit ci-dessus au niveau de l'utilisation. Pour le premier, j'ai ajouté le module 'argparse' qui permet de passer les options de manière standard et d'obtenir toute l'aide en lançant le script avec l'option --help (il y a un petit mélange de français et d'anglais mais personne n'en mourra, j'espère).

    Le script qui génère des images fixes ne nécessite que Matplotlib. Celui pour les vidéos requiert également FFmpeg, mais pourrait aisément utiliser AVConv ou ImageMagick à la place de FFmpeg comme indiqué précédemment (mais ImageMagick ne sait pas faire tout ce que font les deux autres).

    L'image ci-dessous est obtenue en lançant le script pour images fixes ainsi :
    python3 image-fixe.py -s classic --no-axes -o fleurs_classic.png
    
    (l'option -s est un alias pour --stylesheet, -o pour --output-file : tout ceci est expliqué dans la sortie de 'python3 image-fixe.py --help').

    L'extension .tex a été ajoutée aux deux scripts pour pouvoir les joindre en attachement à ce message. Il faut évidemment la retirer dans les deux cas.

    Edit : suppression d'une fonction non utilisée dans animation.py et ajustement d'un commentaire.115346
  • Bonsoir,
    J'ai poussé la limite des pièces jointes au maximum accepté, à savoir 9,6 MB.
  • Merci Philippe ! Si ça intéresse les gens, je peux donc ajouter la vidéo au format MKV, fluide et avec une bonne résolution, obtenue avec :
    python3 animation.py 1200 500 dark_background /tmp/fleurs_dark_background.mkv
    
    (commande qui prend 6 minutes sur mon ordi ; le fichier résultant pèse 8.8 Mo).
Connectez-vous ou Inscrivez-vous pour répondre.
Success message!