IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Calcul scientifique Python Discussion :

Gestion des events matplotlib


Sujet :

Calcul scientifique Python

  1. #1
    Membre émérite

    Homme Profil pro
    Ingénieur
    Inscrit en
    Août 2010
    Messages
    662
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2010
    Messages : 662
    Par défaut Gestion des events matplotlib
    Salut,

    J'ai du mal à comprendre comment sont gérés les événements dans matplotlib. Je cherche à animer un graph après appuis sur un bouton "play". Mon graph contient un "silder" qui me permet de mettre à jour le contenu à la volée. J'ai défini mon bouton "play" de sorte à mettre à jour mon "slider" dans une boucle. Cette boucle parcours un ensemble de données. Or cet ensemble peut être assez conséquent et donc donner lieu à une longue animation. Je souhaite pouvoir la stopper à n'importe quel moment par l'appui sur un bouton "stop".

    Voici le code en question :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
     
    import matplotlib.pyplot as plt
    from matplotlib.widgets import Button
     
    def display():
     
        fig, ax = plt.subplots()
        plt.subplots_adjust(bottom=0.2)
     
        # Création d'un bouton permettant de jouer automatiquement la cinématique
        ax_play = plt.axes([0.69, 0.025, 0.1, 0.04])
        ax_stop = plt.axes([0.80, 0.025, 0.1, 0.04])
        play_button = Button(ax_play, 'Play', hovercolor='0.975')
        stop_button = Button(ax_stop, 'Stop', hovercolor='0.975')
     
        playing = False
        stopping = False
     
        def play(event):
            global playing
            global stopping
            if not playing:
                playing = True
                for i in range(10):
                    if not stopping:
                        #slider.set_val(i)
                        print(i)
                        plt.draw()
                        plt.pause(0.01)
                    else:
                        continue
                playing, stopping = False, False
     
        def stop(event):
            global stopping
            stopping = True
     
        play_button.on_clicked(play)
        stop_button.on_clicked(stop)
     
        plt.show()    
     
    display()
    Lorsque je clique sur "play", la fonction du même nom est lancée avec en argument event. Les booléens playing et stopping sont inconnus de la fonction, même avec l'emploi de global :
    NameError: name 'playing' is not defined
    Quel serait la bonne approche à adopter ici ?

    J

  2. #2
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 699
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 699
    Par défaut
    Salut,

    Avec Python3, les variables d'une fonction accédées par une sous-fonction ne sont plus "global" (au sens module) mais "nonlocal" (à chercher dans le scope englobant).

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  3. #3
    Membre émérite

    Homme Profil pro
    Ingénieur
    Inscrit en
    Août 2010
    Messages
    662
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2010
    Messages : 662
    Par défaut
    Cette notion ne me dit rien. Sauf erreur de ma part, je pense faire ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    def dummy():
        a = 1
        def func():
            print(a)
        func()
     
    dummy()
    >>> 1
    J'appelle une variable dans func défini un niveau plus haut. Et cela marche. D'ailleurs, ma fonction play, le callback appelé à l'appui du bouton "play" fonctionne sans ces booléens :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    def play(event):
        for i in range(10):
            slider.set_val(i)
            plt.draw()
            plt.pause(1)
    Le code complet et fonctionnant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    import numpy as np
    import matplotlib.pyplot as plt
    from matplotlib.widgets import Button, Slider
     
    def display():
     
        # Data
        x = np.arange(10)
        y = x**2
     
        fig, ax = plt.subplots()
        plt.subplots_adjust(bottom=0.2)
     
        line, = ax.plot([], [])
     
        # Création d'un slider permettant de rafraichir la figure tracée
        ax_slider = plt.axes([0.25, 0.1, 0.65, 0.03])
        slider = Slider(
            ax=ax_slider,
            label='',
            valmin=0,
            valmax=9,
            valinit=0,
            valstep=1,
        )
     
        # Fonction appelée à chaque changement de la variable derrière le slider
        def update(i):
            line.set_xdata(x[:int(i)])
            line.set_ydata(y[:int(i)])
     
        slider.on_changed(update)
     
        # Création d'un bouton permettant de jouer automatiquement la cinématique
        ax_play = plt.axes([0.69, 0.025, 0.1, 0.04])
        ax_stop = plt.axes([0.80, 0.025, 0.1, 0.04])
        play_button = Button(ax_play, 'Play', hovercolor='0.975')
        stop_button = Button(ax_stop, 'Stop', hovercolor='0.975')
     
        playing = False
        stopping = False
     
        def play(event):
            for i in range(10):
                slider.set_val(i)
                plt.draw()
                plt.pause(1)
     
        def stop(event):
            stopping = True
     
        play_button.on_clicked(play)
        stop_button.on_clicked(stop)
     
        ax.set_xlim((0, 10))
        ax.set_ylim((0, 100))
     
        plt.show()
     
     
    display()
    Donc slider, défini à un niveau "haut dessus" est bien trouvé sans soucis, comme pour l'exemple avec dummy. Par contre, si je fais ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
        def play(event):
            print(playing)
            if not playing:
                playing = True
            for i in range(10):
                slider.set_val(i)
                plt.draw()
                plt.pause(1)
    J'ai un message d'erreur me disant que playing n'a pas été référencé et le print ne se fait pas, alors que ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
        def play(event):
            print(playing)
            # if not playing:
            #     playing = True
            for i in range(10):
                slider.set_val(i)
                plt.draw()
                plt.pause(1)
    M'affiche False dans la console.

    J

  4. #4
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 699
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 699
    Par défaut
    Citation Envoyé par Julien N Voir le message
    Cette notion ne me dit rien. Sauf erreur de ma part, je pense faire ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    def dummy():
        a = 1
        def func():
            print(a)
        func()
     
    dummy()
    >>> 1
    Si ce code faisait quelque chose de ressemblant, il reproduirait la même erreur...
    Ce qui est impossible puisque qu'il n’essaie pas de mettre à jour la variable!
    Votre code ressemble plutôt à:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    >>> def f():
    ...    a = 1
    ...    def g():
    ...        global a
    ...        a += 1
    ...    g()
    ...
    Ce qui reproduit l'erreur:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    >>> f()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 6, in f
      File "<stdin>", line 5, in g
    NameError: name 'a' is not defined
    >>>
    Et si je remplace global par nonlocal:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    >>> def f():
    ...    a = 1
    ...    def g():
    ...        nonlocal a
    ...        a += 1
    ...    g()
    ...
    >>> f()
    >>>
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  5. #5
    Membre émérite

    Homme Profil pro
    Ingénieur
    Inscrit en
    Août 2010
    Messages
    662
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2010
    Messages : 662
    Par défaut
    Merci !

    Maintenant que j'ai lu la doc sur nonlocal il me semble évident de l'employer. Cependant, j'avoue ne jamais avoir rencontré ce mot clé auparavant... Et pourtant j'ai déjà à maintes reprises employé des fonctions imbriquées. Il y a quand même quelque chose qui m'interroge :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    def f():
        a = 1
        def g():
            print(a)
            #a += 1
        g()
        print(a)
    f()
    >>>1
    >>>1
    Mais ceci plante au print :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    def f():
        a = 1
        def g():
            print(a)
            a += 1
        g()
        print(a)
    f()
    Bref, maintenant je saurais quoi rechercher si je reproduis cette erreur.

    J

  6. #6
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 699
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 699
    Par défaut
    Salut,

    Citation Envoyé par Julien N Voir le message
    Il y a quand même quelque chose qui m'interroge :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    def f():
        a = 1
        def g():
            print(a)
            a += 1
        g()
        print(a)
    f()
    Si la fonction g n'était pas imbriquée, on aurait le même problème a += 1 a besoin de récupérer a avant de pouvoir lui assigner une nouvelle valeur/objet.
    Comme "a" n'a pas été créé dans la fonction, ce n'est pas une variable locale... et on cherche à modifier quelque chose "en dehors".

    Avec Python2, "global" faisait l'affaire...
    Avec Python3, global ne s'applique plus que pour les variables globales (du module) et nonlocal s'appliquera pour le scope englobant (des fonctions imbriquées). Ce qui lève pas mal d’ambiguïtés.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [débutant]gestion des Events
    Par sacoum dans le forum C++/CLI
    Réponses: 8
    Dernier message: 26/06/2008, 11h04
  2. Gestion des events
    Par BruceBoc dans le forum SDL
    Réponses: 7
    Dernier message: 28/04/2007, 14h30
  3. [Conception] classes internes ou gestion des events
    Par TTKiBosse dans le forum Général Java
    Réponses: 2
    Dernier message: 06/12/2006, 18h25
  4. Gestion des event avec un objet ole MsExcel
    Par rdemont dans le forum Delphi
    Réponses: 3
    Dernier message: 03/07/2006, 16h08
  5. [C#] Gestion des Events d'un control Composite
    Par lord_paco dans le forum ASP.NET
    Réponses: 3
    Dernier message: 07/10/2005, 09h10

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo