Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 25/06/2008, à 19:47

Pistolero

[Python] Barre de progression ASCII pour shell

Salut,

ca fait un petit moment que j'ai ecrit un petit bon de code pour avoir une barre de progression dans le shell, qui ressemble a ca:

Title   [============                                                ]  21 %

je l'utilise pratiquement tous les jours, car des que je fais tourner un prog en python je rajoute ma barre, car c'est bien sympa d'avoir l'etat d'avancement dans le shell surtout quand certain algo sont un peu long.

Bref, le truc c'est que j'avais ecrit ca a la va-vite, et cette barre n'est pas parfaite. On voit apparaitre le curseur clignoter a differents endroits de la barre a cause de la mise a jour du texte.

Comment ameliorer son esthetisme, je sais mettre des couleurs pour les sorties shell mais par rapport aussi a la structure et a la methode de la mise a jours.

class ProgressBar:
    '''
    Progress bar
    '''
    def __init__ (self, valmax, maxbar, title):
        if valmax == 0:  valmax = 1
        if maxbar > 200: maxbar = 200
        self.valmax = valmax
        self.maxbar = maxbar
        self.title  = title
    
    def update(self, val):
        import sys
        # format
        if val > self.valmax: val = self.valmax
        
        # process
        perc  = round((float(val) / float(self.valmax)) * 100)
        scale = 100.0 / float(self.maxbar)
        bar   = int(perc / scale)
  
        # render 
        out = '\r %20s [%s%s] %3d %%' % (self.title, '=' * bar, ' ' * (self.maxbar - bar), perc)
        sys.stdout.write(out)

avec valmax la valeur maxi de la variable qu'on observe, maxbar la valeur maxi de la taille de la bar en nombre de caracteres et title bah... le titre. Elle s'utilise comme cela:

Bar = ProgressBar(100, 60, 'MonTitre')
for i in xrange(100):
       Bar.update(i)

Voila, des idees, des suggestions, tout en restant simple, de telle sorte a eviter les 1000 lignes de code pour une barre de progession big_smile.

A+

Dernière modification par Pistolero (Le 25/06/2008, à 19:48)


Desole pour les accents, je suis esclave d'un qwerty.

Hors ligne

#2 Le 21/04/2009, à 16:15

s@mson

Re : [Python] Barre de progression ASCII pour shell

Bonjour,

http://pypi.python.org/pypi/progressbar/2.2

Elle est pas belle la vie?  :-)

Dernière modification par s@mson (Le 21/04/2009, à 16:15)

Hors ligne

#3 Le 21/04/2009, à 17:47

HP

Re : [Python] Barre de progression ASCII pour shell

Je vais, peut-être, suivre ce topic… ou pas roll


cat /dev/urandom >/dev/null 2>&1 #github

Hors ligne

#4 Le 03/02/2010, à 17:58

Narann

Re : [Python] Barre de progression ASCII pour shell

Merci beaucoup Pistolero pour ce script! Ça parait bête mais c'est impossible à trouver ce genre de truc! Merci Merci Merci! big_smile

Hors ligne

#5 Le 28/10/2010, à 09:43

elendil

Re : [Python] Barre de progression ASCII pour shell

Génial ça fait longtemps que je cherchais quelque chose du genre !

J'ai modifié ton code comme il suit :

class ProgressBar:
    '''
    Progress bar
    '''
    def __init__ (self, valmax, maxbar, title):
        if valmax == 0:  valmax = 1
        if maxbar > 200: maxbar = 200
        self.valmax = valmax
        self.maxbar = maxbar
        self.title  = title
    
    def update(self, val):
        import sys
        # process
        perc  = round((float(val) / float(self.valmax)) * 100)
        scale = 100.0 / float(self.maxbar)
        bar   = int(perc / scale)
  
        # render 
        out = '\r %20s [%s%s] %3d %%' % (self.title, '=' * bar, ' ' * (self.maxbar - bar), perc)
        sys.stdout.write(out)
        sys.stdout.flush()

J'ai rajouté sys.stdout.flush() ce qui permet de vider le buffer car chez moi je n'avait la barre de progression qu'une fois la boucle finie smile (source : topic)

J'ai supprimé la ligne :

if val > self.valmax: val = self.valmax

Car je trouve intéressant de savoir si ma boucle plante et dépasse la valeur maximale !
En effet si j'entre une valeur max égale à 100 et que dans mon code ma boucle dépasse cette valeur, la barre de progression affiche 100% 100% 100% . . . etc Je préfère avoir 110%, 120% . . . Du coup je comprend où est l'erreur !
Une autre solution serait de mettre :

if val > self.valmax: raise ValueError("'val' dépasse 'valmax')

Dernière modification par elendil (Le 28/10/2010, à 09:53)

Hors ligne

#6 Le 28/10/2010, à 20:36

kidanger

Re : [Python] Barre de progression ASCII pour shell

Bonjour,

Je trouve le "import sys" un peu mal placé, ne serait il pas mieux en dehors de la classe ?

De plus, je remplacerais

if valmax == 0:  valmax = 1
        if maxbar > 200: maxbar = 200
        self.valmax = valmax
        self.maxbar = maxbar

par  EDIT: ce qui suit est faux... roll

self.valmax = min(1, valmax)
self.maxbar = max(maxbar, 200)

C'est du chipotage, ça doit pas changer grand chose en performance wink

En tout cas, merci pour cette classe, bien légère mais qui peut être utile.

Dernière modification par kidanger (Le 29/10/2010, à 16:54)

Hors ligne

#7 Le 29/10/2010, à 15:42

elendil

Re : [Python] Barre de progression ASCII pour shell

Je suppose que tu veux dire :

self.valmax = max(1, valmax)
self.maxbar = min(maxbar, 200)

Et encore dans ce cas ton code n'est pas équivalent à celui donné par Pistolero car 'self.valmax = max(1, valmax)' va renvoyer 1 pour toute valeur inférieure à 1. Or Pistolero veut avoir 1 uniquement lorsque valmax = 0.

Je me trompe ?

Dernière modification par elendil (Le 29/10/2010, à 15:47)

Hors ligne

#8 Le 29/10/2010, à 16:51

kidanger

Re : [Python] Barre de progression ASCII pour shell

elendil a écrit :

Je suppose que tu veux dire :

self.valmax = max(1, valmax)
self.maxbar = min(maxbar, 200)

Et encore dans ce cas ton code n'est pas équivalent à celui donné par Pistolero car 'self.valmax = max(1, valmax)' va renvoyer 1 pour toute valeur inférieure à 1. Or Pistolero veut avoir 1 uniquement lorsque valmax = 0.

Je me trompe ?

lol J'ai encore écrit trop vite...
Par contre, j'ai pas testé le script, mais si valmax est inférieur à 0, ça marche encore ? (Ah, le 0 ça doit être pour éviter la division...)

La prochaine fois je réfléchirais à 3 fois avant de poster...

Hors ligne

#9 Le 29/10/2010, à 17:07

elendil

Re : [Python] Barre de progression ASCII pour shell

Ça m'arrive tellement souvent (d'écrire lus vite que je réfléchis . . . smile )

J'ai testé le code et j'ai apporté d'autres modifications mais je ne les aies pas sous la main. Je les poste prochainement !

Hors ligne

#10 Le 03/03/2015, à 17:12

pythonTim

Re : [Python] Barre de progression ASCII pour shell

Hello
je l'ai un peu amélioré

Fonctionne sous Debian.Linux

#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
import os
import time



class ProgressBar:
    '''
    Progress bar
    '''
    def __init__ (self, valmax, maxbar, title):
        if valmax == 0:  valmax = 1
        if maxbar > 200: maxbar = 200
        self.valmax = valmax
        self.maxbar = maxbar
        self.title  = title
    
    def update(self, val):
        
        # format
        if val > self.valmax: val = self.valmax
        
        # process
        perc  = round((float(val) / float(self.valmax)) * 100)
        scale = 100.0 / float(self.maxbar)
        bar   = int(perc / scale)
  
        # render 
        out = '\r%20s [%s%s] %3d %% ' % (self.title, '=' * bar, ' ' * (self.maxbar - bar), perc)
        sys.stdout.write(out)
        #Extinction du curseur
        os.system('setterm -cursor off')
        #Rafraichissement de la barre
        sys.stdout.flush()

## Test =
i = 1  #Variable surveillée
#Objet barre de progression
barre = ProgressBar(60,42, "chargement")
print'\n'
for x in range(60):
     barre.update(i) 
     time.sleep(0.30)
     i = i+1
#Redemarrage du curseur
os.system('setterm -cursor on')
print'\n' 
 

Dernière modification par pythonTim (Le 05/03/2015, à 19:40)

Hors ligne

#11 Le 25/06/2015, à 07:15

texom512

Re : [Python] Barre de progression ASCII pour shell

Je l'ai encore amélioré ! big_smile

__author__ = 'texom512'

import sys
import time

from math import *


class ProgressBar:
    """
    This class allows you to make easily a progress bar.
    """

    def __init__(self, steps, maxbar=100, title='Chargement'):
        if steps <= 0 or maxbar <= 0 or maxbar > 200:
            raise ValueError

        self.steps = steps
        self.maxbar = maxbar
        self.title = title

        self.perc = 0
        self._completed_steps = 0

        self.update(False)

    def update(self, increase=True):
        if increase:
            self._completed_steps += 1

        self.perc = floor(self._completed_steps / self.steps * 100)

        if self._completed_steps > self.steps:
            self._completed_steps = self.steps

        steps_bar = floor(self.perc / 100 * self.maxbar)

        if steps_bar == 0:
            visual_bar = self.maxbar * ' '
        else:
            visual_bar = (steps_bar - 1) * '=' + '>' + (self.maxbar - steps_bar) * ' '

        sys.stdout.write('\r' + self.title + ' [' + visual_bar + '] ' + str(self.perc) + '%')
        sys.stdout.flush()


if __name__ == '__main__':
    bar = ProgressBar(50)

    i = 0
    while bar.perc != 100:
        bar.update()
        time.sleep(0.5)

        i += 1

Cette nouvelle version présente de nombreux avantages par rapport à l'ancienne :
- Fonctionne avec Python 3.
- La bar s'affiche dès l'instant où on déclare notre variable.
- La bar est affiché vide au tout début.
- La bar se termine à 100% et pas à 99%
- La bar n'affiche qu'une fois les 100%
- Plus besoin de paramètre pour la méthode update.
- Il y a une flèche pour le chargement, pas juste des signes "=".
- Le pourcentage est un attribut, il est donc accessible depuis l'extérieur de la classe.
- Le code est plus propre qu'avant.

Dernière modification par texom512 (Le 16/01/2016, à 12:35)

Hors ligne