]> SALOME platform Git repositories - tools/eficas.git/blob - Aster/Cata/Utilitai/Table.py
Salome HOME
*** empty log message ***
[tools/eficas.git] / Aster / Cata / Utilitai / Table.py
1 #@ MODIF Table Utilitai  DATE 17/05/2005   AUTEUR DURAND C.DURAND 
2 # -*- coding: iso-8859-1 -*-
3 #            CONFIGURATION MANAGEMENT OF EDF VERSION
4 # ======================================================================
5 # COPYRIGHT (C) 1991 - 2004  EDF R&D                  WWW.CODE-ASTER.ORG
6 # THIS PROGRAM IS FREE SOFTWARE; YOU CAN REDISTRIBUTE IT AND/OR MODIFY  
7 # IT UNDER THE TERMS OF THE GNU GENERAL PUBLIC LICENSE AS PUBLISHED BY  
8 # THE FREE SOFTWARE FOUNDATION; EITHER VERSION 2 OF THE LICENSE, OR     
9 # (AT YOUR OPTION) ANY LATER VERSION.                                                  
10 #                                                                       
11 # THIS PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT   
12 # WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF            
13 # MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU      
14 # GENERAL PUBLIC LICENSE FOR MORE DETAILS.                              
15 #                                                                       
16 # YOU SHOULD HAVE RECEIVED A COPY OF THE GNU GENERAL PUBLIC LICENSE     
17 # ALONG WITH THIS PROGRAM; IF NOT, WRITE TO EDF R&D CODE_ASTER,         
18 #    1 AVENUE DU GENERAL DE GAULLE, 92141 CLAMART CEDEX, FRANCE.        
19 # ======================================================================
20
21 # RESPONSABLE MCOURTOI M.COURTOIS
22
23 import sys
24 import string
25 import re
26
27 from types import *
28 EnumTypes=(ListType, TupleType)
29 NumberTypes=(IntType, LongType, FloatType, ComplexType)
30
31 # try/except pour utiliser hors aster
32 try:
33    from Utilitai.Utmess import UTMESS
34 except ImportError:
35    def UTMESS(code,sprg,texte):
36       fmt='\n <%s> <%s> %s\n\n'
37       print fmt % (code,sprg,texte)
38
39 if not sys.modules.has_key('Graph'):
40    try:
41       from Utilitai import Graph
42    except ImportError:
43       import Graph
44
45 # formats de base (identiques à ceux du module Graph)
46 DicForm={
47    'csep'  : ' ',       # séparateur
48    'ccom'  : '#',       # commentaire
49    'cdeb'  : '',        # début de ligne
50    'cfin'  : '\n',      # fin de ligne
51    'formK' : '%-8s',    # chaines
52    'formR' : '%12.5E',  # réels
53    'formI' : '%8d'      # entiers
54 }
55
56 # ------------------------------------------------------------------------------
57 # ------------------------------------------------------------------------------
58 # ------------------------------------------------------------------------------
59 class TableBase(object):
60    """Classe pour partager les méthodes d'impression entre Table et Colonne
61    (c'est surtout utile pour vérifier que l'extraction et les filtres sur les
62    colonnes sont corrects).
63    """
64    def __repr__(self):
65       return self.ReprTable()
66    def Croise(self,**kargs):
67       raise StandardError, 'Must be defined in a derived class'
68
69 # ------------------------------------------------------------------------------
70    def Impr(self,FICHIER=None,FORMAT='TABLEAU',dform=None,**opts):
71       """Impresssion de la Table selon le format spécifié.
72          FICHIER : nom du(des) fichier(s). Si None, on dirige vers stdout
73          dform : dictionnaire de formats d'impression (format des réels,
74             commentaires, saut de ligne...)
75          opts  : selon FORMAT.
76       """
77       para={
78          'TABLEAU'         : { 'mode' : 'a', 'driver' : self.ImprTableau,   },
79          'ASTER'           : { 'mode' : 'a', 'driver' : self.ImprTableau,   },
80          'XMGRACE'         : { 'mode' : 'a', 'driver' : self.ImprGraph,     },
81          'AGRAF'           : { 'mode' : 'a', 'driver' : self.ImprTableau,   },
82          'TABLEAU_CROISE'  : { 'mode' : 'a', 'driver' : self.ImprTabCroise, },
83       }
84       kargs={
85          'FICHIER'   : FICHIER,
86          'FORMAT'    : FORMAT,
87          'dform'     : DicForm.copy(),
88          'mode'      : para[FORMAT]['mode'],
89       }
90       if dform<>None and type(dform)==DictType:
91          kargs['dform'].update(dform)
92       # ajout des options
93       kargs.update(opts)
94       
95       if not kargs.get('PAGINATION'):
96          # call the associated driver
97          para[FORMAT]['driver'](**kargs)
98
99       else:
100          if not type(kargs['PAGINATION']) in EnumTypes:
101             ppag=[kargs['PAGINATION'],]
102          else:
103             ppag=list(kargs['PAGINATION'])
104          del kargs['PAGINATION']
105          npag=len(ppag)
106          # paramètres hors ceux de la pagination
107          lkeep=[p for p in self.para if ppag.count(p)==0]
108          # création des listes des valeurs distinctes
109          lvd=[]
110          for p in ppag:
111             lvp=getattr(self,p).values()
112             lvn=[]
113             for it in lvp:
114                if it<>None and lvn.count(it)==0:
115                   lvn.append(it)
116             lvn.sort()
117             lvd.append(lvn)
118          # création des n-uplets
119          s = '[['+','.join(['x'+str(i) for i in range(npag)])+'] '
120          s+= ' '.join(['for x'+str(i)+' in lvd['+str(i)+']' for i in range(npag)])+']'
121          try:
122             lnup=eval(s)
123          except SyntaxError, s:
124             UTMESS('F','Table','Erreur lors de la construction des n-uplets')
125          # pour chaque n-uplet, on imprime la sous-table
126          for nup in lnup:
127             tab=self
128             for i in range(npag):
129                tab = tab & (getattr(tab,ppag[i]) == nup[i])
130                sl=''
131                if tab.titr: sl='\n'
132                tab.titr += sl+ppag[i]+': '+str(nup[i])
133             tab[lkeep].Impr(**kargs)
134
135 # ------------------------------------------------------------------------------
136    def ImprTableau(self,**kargs):
137       """Impression au format TABLEAU ou ASTER
138       """
139       # fichier ou stdout
140       if kargs.get('FICHIER')<>None:
141          f=open(kargs['FICHIER'],kargs['mode'])
142       else:
143          f=sys.stdout
144       # ecriture
145       f.write(self.ReprTable(**kargs) + '\n')
146       # fermeture
147       if kargs.get('FICHIER')<>None:
148          f.close()
149
150    def ReprTable(self,FORMAT='TABLEAU',dform=DicForm,**ignore):
151       """Représentation d'une Table ou d'une Colonne sous forme d'un tableau.
152       """
153       rows=self.rows
154       para=self.para
155       typ =self.type
156       if not type(para) in EnumTypes:
157          para=[self.para,]
158          typ =[self.type,]
159       # est-ce que l'attribut .type est renseigné ?
160       typdef=typ<>[None]*len(typ)
161       txt=[]
162       # ['']+ pour ajouter un séparateur en début de ligne
163       lspa=['',]
164       # lmax : largeur max des colonnes = max(form{K,R,I},len(parametre))
165       lmax=[]
166       for p in para:
167          t=typ[para.index(p)]
168          larg_max=max([len(str(p))] + \
169                [len(FMT(dform,k,t) % 0) for k in ('formK','formR','formI')])
170          lspa.append(FMT(dform,'formK',t,larg_max,str(p)) % p)
171          lmax.append(larg_max)
172       if typdef:
173          stype=dform['csep'].join([''] + \
174           [FMT(dform,'formK',typ[i],lmax[i]) % typ[i] for i in range(len(para))])
175       txt.append('')
176       txt.append('-'*80)
177       txt.append('')
178       ASTER=(FORMAT=='ASTER')
179       if ASTER:
180          txt.append('#DEBUT_TABLE')
181       if self.titr:
182          if ASTER:
183             txt.extend(['#TITRE '+lig for lig in self.titr.split('\n')])
184          else:
185             txt.append(self.titr)
186       txt.append(dform['csep'].join(lspa))
187       if ASTER and typdef:
188          txt.append(stype)
189       for r in rows:
190          lig=['']
191          empty=True
192          for v in para:
193             i=para.index(v)
194             t=typ[i]
195             rep=r.get(v,None)
196             if type(rep) is FloatType:
197                lig.append(FMT(dform,'formR',t,lmax[i]) % rep)
198                empty=False
199             elif type(rep) is IntType:
200                lig.append(FMT(dform,'formI',t,lmax[i]) % rep)
201                empty=False
202             else:
203                if rep==None:
204                   rep='-'
205                else:
206                   empty=False
207                s=FMT(dform,'formK',t,lmax[i],rep) % str(rep)
208                # format AGRAF = TABLEAU + '\' devant les chaines de caractères !
209                if FORMAT=='AGRAF':
210                   s='\\'+s
211                lig.append(s)
212          if not empty:
213             txt.append(dform['csep'].join(lig))
214       if ASTER:
215          txt.append('#FIN_TABLE')
216       return dform['cfin'].join(txt)
217 # ------------------------------------------------------------------------------
218    def ImprTabCroise(self,**kargs):
219       """Impression au format TABLEAU_CROISE d'une table ayant 3 paramètres.
220       """
221       # création du tableau croisé et impression au format TABLEAU
222       tabc=self.Croise()
223       kargs['FORMAT']='TABLEAU'
224       tabc.Impr(**kargs)
225 # ------------------------------------------------------------------------------
226    def ImprGraph(self,**kargs):
227       """Impression au format XMGRACE : via le module Graph
228       """
229       args=kargs.copy()
230       if len(self.para)<>2:
231          UTMESS('A','Table','La table doit avoir exactement deux paramètres.')
232          return
233       lx, ly = [[v for v in getattr(self,p).values() if v<>None] for p in self.para]
234       # objet Graph
235       graph=Graph.Graph()
236       dicC={
237          'Val' : [lx, ly],
238          'Lab' : self.para,
239       }
240       if args['LEGENDE']==None: del args['LEGENDE']
241       Graph.AjoutParaCourbe(dicC, args)
242       graph.AjoutCourbe(**dicC)
243       
244       # Surcharge des propriétés du graphique et des axes
245       # (bloc quasiment identique dans impr_fonction_ops)
246       if args.get('TITRE'):            graph.Titre=args['TITRE']
247       if args.get('BORNE_X'):
248                                        graph.Min_X=args['BORNE_X'][0]
249                                        graph.Max_X=args['BORNE_X'][1]
250       if args.get('BORNE_Y'):
251                                        graph.Min_Y=args['BORNE_Y'][0]
252                                        graph.Max_Y=args['BORNE_Y'][1]
253       if args.get('LEGENDE_X'):        graph.Legende_X=args['LEGENDE_X']
254       if args.get('LEGENDE_Y'):        graph.Legende_Y=args['LEGENDE_Y']
255       if args.get('ECHELLE_X'):        graph.Echelle_X=args['ECHELLE_X']
256       if args.get('ECHELLE_Y'):        graph.Echelle_Y=args['ECHELLE_Y']
257       if args.get('GRILLE_X'):         graph.Grille_X=args['GRILLE_X']
258       if args.get('GRILLE_Y'):         graph.Grille_Y=args['GRILLE_Y']
259       
260       try:
261          graph.Trace(**args)
262       except TypeError:
263          UTMESS('A','Table','Les cellules ne doivent contenir que des nombres réels')
264
265 # ------------------------------------------------------------------------------
266 # ------------------------------------------------------------------------------
267 # ------------------------------------------------------------------------------
268 class Table(TableBase):
269    """Une table est construite comme une liste de lignes, chaque ligne est
270    un dictionnaire.
271    On crée puis on ajoute les lignes avec la méthode append :
272       t=Table()
273       t.append(dict(a=1,b=2))
274       t.append(dict(a=3,b=4))
275    La méthode __iter__ définit un itérateur sur les lignes de la table,
276    __repr__ retourne une représentation de la table, utilisée par "print t".
277    Grace à la classe Colonne et à sa méthode _extract, il est possible
278    de construire une sous-table qui satisfait un critère donné.
279    Le critère est donné par une fonction Python qui retourne vrai
280    ou faux si la valeur d'une colonne respecte le critère ou non.
281    Exemple:
282      def critere(valeur):
283          return valeur < 10
284      soustable = t.a._extract(critere)
285    t.a retourne un objet intermédiaire de la classe Colonne qui mémorise
286    le nom de la colonne demandée (a, ici).
287    """
288    def __init__(self, rows=[], para=[], typ=[], titr=''):
289       """Constructeur de la Table :
290          rows : liste des lignes (dict)
291          para : liste des paramètres
292          type : liste des types des paramètres
293          titr : titre de la table
294       """
295       self.rows=[r for r in rows if r.values()<>[None]*len(r.values())]
296       self.para=list(para)
297       if len(typ)==len(self.para):
298          self.type=list(typ)
299       else:
300          self.type=[None]*len(self.para)
301       self.titr=titr
302
303    def append(self, obj):
304       """Ajoute une ligne (type dict) à la Table"""
305       self.rows.append(obj)
306
307    def __iter__(self):
308       """Itère sur les lignes de la Table"""
309       return iter(self.rows)
310
311    def __getattr__(self, column):
312       """Construit un objet intermediaire (couple table, colonne)"""
313       typ=None
314       if not column in self.para:
315          column=''
316       else:
317          typ=self.type[self.para.index(column)]
318       return Colonne(self, column, typ)
319
320    def sort(self, CLES=None, ORDRE='CROISSANT'):
321       """Tri de la table.
322          CLES  : liste des clés de tri
323          ORDRE : CROISSANT ou DECROISSANT (de longueur 1 ou len(keys))
324       """
325       # par défaut, on prend tous les paramètres
326       if CLES==None:
327          CLES=self.para[:]
328       if not type(CLES) in EnumTypes:
329          CLES=[CLES,]
330       else:
331          CLES=list(CLES)
332       self.rows=sort_table(self.rows, self.para, CLES, (ORDRE=='DECROISSANT'))
333 #       if not type(order) in EnumTypes:
334 #          order=[order,]
335 #       print 'TRI clés=%s, order=%s' % (keys,order)
336 #       # on ne garde que le premier si les longueurs sont différentes
337 #       if len(order)<>len(keys):
338 #          order=[order[0],]
339 #       else:
340 #          # si toutes les valeurs sont identiques, on peut ne garder que la 1ère
341 #          d={}
342 #          for o in order: d[o]=None
343 #          if len(order)<>len(keys) or len(d.keys())==1:
344 #             order=[order[0],]
345 #       if len(order)==1:
346 #          self.rows=sort_table(self.rows, self.para, keys, (order[0]=='DECROISSANT'))
347 #       else:
348 #          # de la dernière clé à la première
349 #          for k,o in [(keys[i],order[i]) for i in range(len(keys)-1,-1,-1)]:
350 #             print 'TRI : clé=%s, order=%s' % (k,o)
351 #             self.rows=sort_table(self.rows, self.para, [k], (o=='DECROISSANT'))
352
353    def __delitem__(self, args):
354       """Supprime les colonnes correspondantes aux éléments de args """
355       if not type(args) in EnumTypes:
356          args=[args,]
357       new_rows=self.rows
358       new_para=self.para
359       new_type=self.type
360       for item in args:
361          del new_type[new_para.index(item)]
362          new_para.remove(item)
363          for line in new_rows : del line[item] 
364       return Table(new_rows, new_para, new_type, self.titr)
365
366    def __getitem__(self, args):
367       """Extrait la sous table composée des colonnes dont les paramètres sont dans args """
368       if not type(args) in EnumTypes:
369          args=[args,]
370       else:
371          args=list(args)
372       #print '<getitem> args=',args
373       new_rows=[]
374       new_para=args
375       new_type=[]
376       for item in new_para:
377          if not item in self.para:
378             return Table()
379          new_type.append(self.type[self.para.index(item)])
380       for line in self:
381          new_line={}
382          for item in new_para:
383             new_line[item]=line.get(item)
384          new_rows.append(new_line)
385       return Table(new_rows, new_para, new_type, self.titr)
386
387    def __and__(self, other):
388       """Intersection de deux tables (opérateur &)"""
389       if other.para<>self.para:
390          UTMESS('A','Table','Les paramètres sont différents')
391          return Table()
392       else:
393          tmp = [ r for r in self if r in other.rows ]
394          return Table(tmp, self.para, self.type, self.titr)
395
396    def __or__(self, other):
397       """Union de deux tables (opérateur |)"""
398       if other.para<>self.para:
399          UTMESS('A','Table','Les paramètres sont différents')
400          return Table()
401       else:
402          tmp = self.rows[:]
403          tmp.extend([ r for r in other if r not in self ])
404          return Table(tmp, self.para, self.type[:], self.titr)
405
406    def values(self):
407       """Renvoie la table sous la forme d'un dictionnaire de listes dont les
408       clés sont les paramètres.
409       """
410       dico={}
411       for column in self.para:
412          dico[column]=Colonne(self, column).values()
413       return dico
414
415    def Array(self,Para,Champ):
416       """Renvoie sous forme de NumArray le résultat d'une extraction dans une table
417       méthode utile à macr_recal
418       """
419       import Numeric
420       __Rep = self[Para,Champ].values()
421       F=Numeric.zeros((len(__Rep[Para]),2),Numeric.Float)
422       for i in range(len(__Rep[Para])):
423        F[i][0] = __Rep[Para][i]
424        F[i][1] = __Rep[Champ][i]
425       del(__Rep)
426       return F
427
428    def Croise(self):
429       """Retourne un tableau croisé P3(P1,P2) à partir d'une table ayant
430       trois paramètres (P1, P2, P3).
431       """
432       if len(self.para)<>3:
433          UTMESS('A','Table','La table doit avoir exactement trois paramètres.')
434          return Table()
435       py, px, pz = self.para
436       ly, lx, lz = [getattr(self,p).values() for p in self.para]
437       new_rows=[]
438       #lpz='%s=f(%s,%s)' % (pz,px,py)
439       lpz='%s/%s' % (px,py)
440       new_para=[lpz,]
441       # attention aux doublons dans lx et ly
442       for it in ly:
443          if it<>None and new_para.count(it)==0:
444             new_para.append(it)
445       newx=[]
446       for it in lx:
447          if it<>None and newx.count(it)==0:
448             newx.append(it)
449       for x in newx:
450          if x<>None:
451             d={ lpz : x, }
452             taux = (getattr(self,px)==x)
453             for dz in taux.rows:
454                d[dz[py]]=dz[pz]
455             new_rows.append(d)
456       new_type=[self.type[0],] + [self.type[2]]*len(ly)
457       new_titr=self.titr
458       if new_titr<>'': new_titr+='\n'
459       new_titr+=pz + ' FONCTION DE ' + px + ' ET ' + py
460       return Table(new_rows, new_para, new_type, new_titr)
461
462 # ------------------------------------------------------------------------------
463 # ------------------------------------------------------------------------------
464 # ------------------------------------------------------------------------------
465 class Colonne(TableBase):
466    """Classe intermédiaire pour mémoriser un couple (table, nom de colonne)
467    et exprimer les critères d'extraction sous une forme naturelle en python
468    en surchargeant les operateurs <, >, <> et =.
469    Alors on peut écrire la requete simple :
470      soustable=t.a<10
471    Ainsi que des requetes plus complexes :
472      soustable=t.a<10 & t.b <4
473    ou
474      soustable=t.a<10 | t.b <4
475    Les "alias" EQ, NE, LE, LT, GE, GT permettent à la macro IMPR_TABLE
476    d'utiliser directement le mot-clé utilisateur CRIT_COMP défini dans le
477    catalogue : getattr(Table,CRIT_COMP).
478    """
479    def __init__(self, table, column, typ=None):
480       """Constructeur (objet Table associé, paramètre de la colonne, type du
481       paramètre).
482       """
483       self.Table=table
484       self.rows=self.Table.rows
485       self.para=column
486       self.type=typ
487       self.titr=''
488
489    def _extract(self, fun):
490       """Construit une table avec les lignes de self.Table 
491          dont l'élément de nom self.para satisfait le critère fun,
492          fun est une fonction qui retourne vrai ou faux
493       """
494       return Table([row for row in self.Table if fun(row.get(self.para))], self.Table.para, self.Table.type, self.Table.titr)
495
496    def __le__(self, VALE):
497       return self._extract(lambda v: v<>None and v<=VALE)
498
499    def __lt__(self, VALE):
500       return self._extract(lambda v: v<>None and v<VALE)
501
502    def __ge__(self, VALE):
503       return self._extract(lambda v: v<>None and v>=VALE)
504
505    def __gt__(self, VALE):
506       return self._extract(lambda v: v<>None and v>VALE)
507
508    def __eq__(self, VALE, CRITERE='RELATIF', PRECISION=0.):
509       if type(VALE) in EnumTypes :
510          return self._extract(lambda v: v in VALE)
511       if PRECISION==0. or not type(VALE) in NumberTypes:
512          if type(VALE) in StringTypes:
513             return self._extract(lambda v: v<>None and str(v).strip()==VALE.strip())
514          else:
515             return self._extract(lambda v: v==VALE)
516       else:
517          if CRITERE=='ABSOLU':
518             vmin=VALE-PRECISION
519             vmax=VALE+PRECISION
520          else:
521             vmin=(1.-PRECISION)*VALE
522             vmax=(1.+PRECISION)*VALE
523          return self._extract(lambda v: v<>None and vmin<v<vmax)
524
525    def __ne__(self, VALE, CRITERE='RELATIF', PRECISION=0.):
526       if type(VALE) in EnumTypes :
527          return self._extract(lambda v: v not in VALE)
528       if PRECISION==0. or not type(VALE) in NumberTypes:
529          if type(VALE) in StringTypes:
530             return self._extract(lambda v: v<>None and str(v).strip()<>VALE.strip())
531          else:
532             return self._extract(lambda v: v<>VALE)
533       else:
534          if CRITERE=='ABSOLU':
535             vmin=VALE-PRECISION
536             vmax=VALE+PRECISION
537          else:
538             vmin=(1.-PRECISION)*VALE
539             vmax=(1.+PRECISION)*VALE
540          return self._extract(lambda v: v<>None and (v<vmin or vmax<v))
541
542    def MAXI(self):
543       # important pour les performances de récupérer le max une fois pour toutes
544       maxi=max(self)
545       return self._extract(lambda v: v==maxi)
546
547    def MINI(self):
548       # important pour les performances de récupérer le min une fois pour toutes
549       mini=min(self)
550       return self._extract(lambda v: v==mini)
551
552    def ABS_MAXI(self):
553       # important pour les performances de récupérer le max une fois pour toutes
554       abs_maxi=max([abs(v) for v in self.values() if type(v) in NumberTypes])
555       return self._extract(lambda v: v==abs_maxi or v==-abs_maxi)
556
557    def ABS_MINI(self):
558       # important pour les performances de récupérer le min une fois pour toutes
559       abs_mini=min([abs(v) for v in self.values() if type(v) in NumberTypes])
560       # tester le type de v est trop long donc pas de abs(v)
561       return self._extract(lambda v: v==abs_mini or v==-abs_mini)
562
563    def __iter__(self):
564       """Itère sur les éléments de la colonne"""
565       for row in self.Table:
566          # si l'élément n'est pas présent on retourne None
567          yield row.get(self.para)
568          #yield row[self.para]
569
570    def __getitem__(self, i):
571       """Retourne la ième valeur d'une colonne"""
572       return self.values()[i]
573
574    def values(self):
575       """Renvoie la liste des valeurs"""
576       return [r[self.para] for r in self.Table]
577
578    # équivalences avec les opérateurs dans Aster
579    LE=__le__
580    LT=__lt__
581    GE=__ge__
582    GT=__gt__
583    EQ=__eq__
584    NE=__ne__
585    def VIDE(self)    : return self.__eq__(None)
586    def NON_VIDE(self): return self.__ne__(None)
587
588 # ------------------------------------------------------------------------------
589 # ------------------------------------------------------------------------------
590 # ------------------------------------------------------------------------------
591 def sort_table(rows,l_para,w_para,reverse=False):
592    """Sort list of dict.
593       rows     : list of dict
594       l_para   : list of the keys of dict
595       w_para   : keys of the sort
596    """
597    c_para=[i for i in l_para if i not in w_para]
598    new_rows=rows
599    for i in w_para :
600       new_key= '__'+str(w_para.index(i))+i
601       for row in new_rows :
602          row[new_key]=row[i]
603          del row[i]
604    for i in c_para :
605       new_key= '___'+i
606       for row in new_rows :
607          row[new_key]=row[i]
608          del row[i]
609    new_rows.sort()
610    if reverse:
611       new_rows.reverse()
612    for i in w_para :
613       old_key= '__'+str(w_para.index(i))+i
614       for row in new_rows :
615          row[i]=row[old_key]
616          del row[old_key]
617    for i in c_para :
618       old_key= '___'+i
619       for row in new_rows :
620          row[i]=row[old_key]
621          del row[old_key]
622    return new_rows
623
624 # ------------------------------------------------------------------------------
625 def FMT(dform, nform, typAster=None, larg=0, val=''):
626    """Retourne un format d'impression Python à partir d'un type Aster ('R','I',
627    'K8', 'K16'...). Si typAster==None, retourne dform[nform].
628       larg : largeur minimale du format (val permet de ne pas ajouter des blancs
629       si la chaine à afficher est plus longue que le format, on prend le partie
630       de ne pas tronquer les chaines)
631    """
632    if typAster==None:
633       fmt=dform[nform]
634    elif typAster in ('I', 'R'):
635       if nform=='formK':
636          # convertit %12.5E en %-12s
637          fmt=re.sub('([0-9]+)[\.0-9]*[diueEfFgG]+','-\g<1>s',dform['form'+typAster])
638          #print nform, typAster, fmt
639       else:
640          fmt=dform[nform]
641    else:
642       # typAster = Kn
643       fmt='%-'+typAster[1:]+'s'
644    # on ajoute éventuellement des blancs pour atteindre la largeur demandée
645    if larg<>0:
646       fmt=' '*max(min(larg-len(val),larg-len(fmt % 0)),0) + fmt
647    return fmt
648
649 # ------------------------------------------------------------------------------
650 # ------------------------------------------------------------------------------
651 # ------------------------------------------------------------------------------
652 if __name__ == "__main__":
653    listdic = [
654    {'NOEUD': 'N1' ,'NUME_ORDRE': 1 ,'INST': 0.5, 'DX': -0.00233, 'COOR_Y': 0.53033,},
655    {'NOEUD': 'N1' ,'NUME_ORDRE': 2 ,'INST': 1.0, 'DX': -0.00467, 'COOR_Y': 0.53033,},
656    {'NOEUD': 'N1' ,'NUME_ORDRE': 3 ,'INST': 1.5, 'DX': -0.00701, 'COOR_Y': 0.53033,},
657    {'NOEUD': 'N1' ,'NUME_ORDRE': 4 ,'INST': 2.0, 'DX': -0.00934, 'COOR_Y': 0.53033,},
658    {'NOEUD': 'N1' ,'NUME_ORDRE': 5 ,'INST': 2.5, 'DX': -0.01168, 'COOR_Y': 0.53033,},
659    {'NOEUD': 'N2' ,'NUME_ORDRE': 11,'INST': 5.5, 'DX': -0.00233, 'COOR_Y': 0.53033,},
660    {'NOEUD': 'N2' ,'NUME_ORDRE': 12,'INST': 6.0, 'DX': -0.00467, 'COOR_Y': 0.53033,},
661    {'NOEUD': 'N2' ,'NUME_ORDRE': 13,'INST': 6.5, 'DX': -0.00701, 'COOR_Y': 0.53033,},
662    {'NOEUD': 'N2' ,'NUME_ORDRE': 14,'INST': 7.0, 'DX': -0.00934, 'COOR_Y': 0.53033,},
663    {'NOEUD': 'N2' ,'NUME_ORDRE': 15,'INST': 7.5, 'DX': -0.01168, 'COOR_Y': 0.53033,},
664    ]
665    import random
666    random.shuffle(listdic)
667    listpara=['NOEUD','NUME_ORDRE','INST','COOR_Y','DX']
668    listtype=['K8','I','R','R','R']
669    t=Table(listdic,listpara,listtype)
670    
671    tb=t[('NOEUD','DX')]
672    print tb.para
673    print tb.type
674    
675    print
676    print "------Table initiale----"
677    print t
678    print
679    print "--------- CRIT --------"
680    print t.NUME_ORDRE <=5
681    print
682    print "------- CRIT & CRIT -----"
683    print (t.NUME_ORDRE < 10) & (t.INST >=1.5)
684    print
685    print "----- EQ maxi / min(col), max(col) ------"
686    print t.DX == max(t.DX)
687    print min(t.DX)
688    print max(t.DX)
689    print "------ getitem sur 2 paramètres ------"
690    print t.NUME_ORDRE
691    print t.DX
692    print t['DX','NUME_ORDRE']
693    print "------ sort sur INST ------"
694    t.sort('INST')
695    print t
696
697    print "------- TABLEAU_CROISE ------"
698    tabc=t['NOEUD','INST','DX'] 
699    tabc.Impr(FORMAT='TABLEAU_CROISE')
700
701    N=5
702    ldic=[]
703    for i in range(N):
704       ldic.append({'IND':float(i), 'VAL' : random.random()*i})
705    para=['IND','VAL']
706    t3=Table(ldic, para, titr='Table aléatoire')
707    col=t3.VAL.ABS_MAXI()
708    col=t3.VAL.MINI()
709    
710    t3.sort('VAL','IND')
711    
712    tg=tabc['INST','DX'].DX.NON_VIDE()
713    #tg.Impr(FORMAT='XMGRACE')
714    
715    g=Graph.Graph()
716    g.Titre="Tracé d'une fonction au format TABLEAU"
717    g.AjoutCourbe(Val=[tg.INST.values(), tg.DX.values()], Lab=['INST','DX'])
718    g.Trace(FORMAT='TABLEAU')
719    
720 #   t.Impr(PAGINATION='NOEUD')
721    t.Impr(PAGINATION=('NOEUD','INST'))
722