4 # Copyright (C) 2002 Jörg Lehmann <joergl@users.sourceforge.net>
5 # Copyright (C) 2002 André Wobst <wobsta@users.sourceforge.net>
7 # This file is part of PyX (http://pyx.sourceforge.net/).
9 # PyX is free software; you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation; either version 2 of the License, or
12 # (at your option) any later version.
14 # PyX is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
19 # You should have received a copy of the GNU General Public License
20 # along with PyX; if not, write to the Free Software
21 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 import re
, ConfigParser
25 from mathtree
import *
28 class ColumnError(Exception): pass
31 ColPattern
= re
.compile(r
"\$-?[0-9]+")
33 class MathTreeValCol(MathTreeValVar
):
35 def InitByParser(self
, arg
):
36 Match
= arg
.MatchPattern(ColPattern
)
42 MathTreeValsWithCol
= (MathTreeValConst
, MathTreeValVar
, MathTreeValCol
)
47 def __init__(self
, titles
, data
, parser
=parser(MathTreeVals
=MathTreeValsWithCol
), extern
=None):
53 def getcolumnno(self
, column
):
54 if self
.titles
.count(column
) == 1:
55 return self
.titles
.index(column
)
58 except (TypeError, IndexError, ValueError):
62 def getcolumn(self
, column
):
63 columnno
= self
.getcolumnno(column
)
64 return [x
[columnno
] for x
in self
.data
]
66 def _addcolumn(self
, expression
, **columns
):
68 split
= expression
.rindex("=")
70 self
.titles
.append(None)
72 self
.titles
.append(expression
[:split
])
73 expression
= expression
[split
+1:]
74 tree
= self
.parser
.parse(expression
)
76 for key
in tree
.VarList():
83 columnlist
[key
] = column
86 columnlist
[key
] = self
.getcolumnno(columns
[key
])
89 columnlist
[key
] = self
.getcolumnno(key
)
90 except ColumnError
, e
:
91 if self
.extern
is None or key
not in self
.extern
.keys():
95 for data
in self
.data
:
97 for key
in columnlist
.keys():
98 varlist
[key
] = float(data
[columnlist
[key
]])
99 except (TypeError, ValueError):
102 data
.append(tree
.Calc(varlist
, self
.extern
))
103 return columnlist
.keys()
105 def addcolumn(self
, expression
, **columns
):
106 usedkeys
= self
._addcolumn
(expression
, **columns
)
107 unusedkeys
= [key
for key
in columns
.keys() if key
not in usedkeys
]
109 raise KeyError("unused keys %s" % unusedkeys
)
114 class datafile(data
):
116 defaultcommentpattern
= re
.compile(r
"(#+|!+|%+)\s*")
117 defaultstringpattern
= re
.compile(r
"\"(.*?
)\"(\s
+|$
)")
118 defaultcolumnpattern = re.compile(r"(.*?
)(\s
+|$
)")
120 def splitline(self, line, stringpattern, columnpattern, tofloat=1):
122 if line.find('"')!=-1 or \
123 stringpattern is not self.defaultstringpattern or \
124 columnpattern is not self.defaultcolumnpattern:
126 match = stringpattern.match(line)
128 result.append(match.groups()[0])
129 line = line[match.end():]
131 match = columnpattern.match(line)
134 result.append(float(match.groups()[0]))
135 except (TypeError, ValueError):
136 result.append(match.groups()[0])
138 result.append(match.groups()[0])
139 line = line[match.end():]
143 return map(float, line.split())
144 except (TypeError, ValueError):
146 for r in line.split():
148 result.append(float(r))
149 except (TypeError, ValueError):
156 def __init__(self, file, commentpattern=defaultcommentpattern,
157 stringpattern=defaultstringpattern,
158 columnpattern=defaultcolumnpattern, **args):
164 file = open(file, "r")
169 for line in file.readlines():
171 match = commentpattern.match(line)
174 newtitles = self.splitline(line[match.end():], stringpattern, columnpattern, tofloat=0)
176 usetitles = newtitles
179 for value in self.splitline(line, stringpattern, columnpattern, tofloat=1):
180 linedata.append(value)
183 linedata = [linenumber] + linedata
184 if len(linedata) > maxcolumns:
185 maxcolumns = len(linedata)
186 usedata.append(linedata)
188 usetitles = [None] + usetitles[:maxcolumns-1]
189 usetitles += [None] * (maxcolumns - len(usetitles))
191 line += [None] * (maxcolumns - len(line))
194 data.__init__(self, usetitles, usedata, **args)
198 class sectionfile(data):
200 def __init__(self, file, sectionstr = "section", **args):
201 config = ConfigParser.ConfigParser()
202 config.optionxform = str
208 config.readfp(open(file, "r"))
210 usetitles = [sectionstr]
211 sections = config.sections()
213 for section in sections:
214 usedata.append([section] + [None for x in range(len(usetitles) - 1)])
215 for option in config.options(section):
216 if option == sectionstr:
217 raise ValueError("'%s' is already used as the section identifier" % sectionstr)
219 index = usetitles.index(option)
221 index = len(usetitles)
222 usetitles.append(option)
225 value = config.get(section, option)
227 usedata[-1][index] = float(value)
228 except (TypeError, ValueError):
229 usedata[-1][index] = value
230 data.__init__(self, usetitles, usedata, **args)