Rename Oscopy/ to oscopy/
[oscopy.git] / oscopy / Oscopy.py
blob74c061063a6997e2d7cf22369f51da10f64435d1
1 """ Interface between signals and figures
3 Class Oscopy: Commands callables from oscopy commandline
5 Methods:
6 __init__()
7 Create empty lists of figures, readers and signals
9 create(sns)
10 Create a new figure, and assign signals if provided
12 destroy(num)
13 Delete a figure
15 select(num, gn = 0)
16 Select the figure and the graph to become the current ones
18 layout(l)
19 set_ the layout of the current figure
21 figlist()
22 Print a list of figures
24 plot()
25 plot all the figure
27 read(fn)
28 Read signals from file fn
30 write(fn, fmt, sns, opts)
31 Write signals sns to file fn using format sns and options opts
33 update()
34 Reread all signals from files
36 add(sns)
37 Add a graph to the current figure
39 delete(gn)
40 Delete a graph from the current figure
42 mode(mode)
43 Set the mode of the current graph
45 scale(sc)
46 Set the axis scale of the current graph e.g. log or lin
48 range(a1, a2, a3, a4)
49 Set the axis range of the current graph
51 unit(xu, yu)
52 Set the unit of current graph from current figure
54 insert(sns)
55 Add signals to the current graph of the current figure
57 remove(sns)
58 Remove signals from the current graph of the current figure
60 freeze(sns)
61 Set the freeze flag of signals
63 unfreeze(sns)
64 Unset_ the freeze flag of signals
66 siglist()
67 List all the signals
69 math(expr)
70 Create a signal from a mathematical expression
72 signames_to_sigs(sns)
73 Return a list of the signal names from the arguments provided by the user
74 Should not be called from the command line
76 Abbreviations:
77 sigs: dict of sigs
78 sns : signal names
79 opts: options
80 fn : filename
81 gn : graph number
82 """
84 import sys
85 import re
86 import matplotlib.pyplot as plt
87 from Readers.DetectReader import DetectReader
88 from Writers.DetectWriter import DetectWriter
89 from Readers.Reader import ReadError
90 from Writers.Writer import WriteError
91 from Figure import Figure
93 class Oscopy(object):
94 """ Class Oscopy -- Interface between signals and figures
96 This object is the interface between the signals and the figures,
97 e.g. it handle operations on figures, signals, readers and writers.
98 It maintain a list of figures, a dict of reader and a dict of signals.
100 The keys for the signal dict are the signal name, as presented to the user
101 The keys for the reader dict are the file name.
104 def __init__(self):
105 """ Create the instance variables
107 self.curfig = None
108 self.readers = {}
109 self.figs = []
110 self.sigs = {}
111 self.upn = -1
112 self.sn_to_r = {}
114 def create(self, sigs):
115 """ Create a new figure and set_ it as current
116 Can be either called from commandline or a function.
117 When called from commandline, call signames_to_sigs to retrieve
118 the signal list
119 When called from a function, if the argument is not a list
120 then return.
121 After those tests, the figure is created with the signal list.
123 if isinstance(sigs, list):
124 # Called from commandline,
125 # Get the signal list from args
126 if not sigs == "":
127 sigs = self.signames_to_sigs(sigs)
128 else:
129 # No signal list provided
130 sigs = {}
131 elif not isinstance(sigs, dict):
132 return
133 # toplot is now a list
134 f = Figure(sigs)
135 self.figs.append(f)
136 self.curfig = f
138 def destroy(self, num):
139 """ Delete a figure
140 User must provide the figure number.
141 If the number is out of range, then return
142 Act as a "pop" with self.curfig
144 if num > len(self.figs) or num < 1:
145 return
146 if self.curfig == self.figs[num - 1]:
147 if len(self.figs) == 1:
148 # Only one element remaining in the list
149 self.curfig = None
150 elif num == len(self.figs):
151 # Last element, go to the previous
152 self.curfig = self.figs[num - 2]
153 else:
154 # Go to next element
155 self.curfig = self.figs[num]
156 del self.figs[num - 1]
157 if self.curfig is not None:
158 print "Curfig : ", self.figs.index(self.curfig) + 1
159 else:
160 print "No figures"
162 def select(self, num, gn = 0):
163 """ Select the current figure
165 if num > len(self.figs) or num < 1:
166 return
167 self.curfig = self.figs[num - 1]
168 if gn > 0:
169 self.curfig.select(gn)
171 def layout(self, l):
172 """ Define the layout of the current figure
174 if self.curfig is not None:
175 self.curfig.set_layout(l)
177 def figlist(self):
178 """ Print the list of figures
180 for i, f in enumerate(self.figs):
181 if f == self.curfig:
182 print "*",
183 else:
184 print " ",
185 print "Figure", i + 1, ":", f.layout
186 f.list()
188 def plot(self):
189 """ Plot the figures, and enter in the matplotlib main loop
191 if not self.figs:
192 return
193 for i, f in enumerate(self.figs):
194 fig = plt.figure(i + 1)
195 f.plot(fig)
196 plt.show()
198 def read(self, fn):
199 """ Read signals from file.
200 Duplicate signal names overwrite the previous one.
201 For new only gnucap files are supported.
202 Do not load the same file twice.
204 # File already loaded ?
205 if fn in self.readers.keys():
206 print "File already loaded"
207 return
209 r = DetectReader(fn)
210 if r is None:
211 print "File format unknown"
212 return
213 sigs = r.read(fn)
215 # Insert signals into the dict
216 for sn in sigs.keys():
217 self.sigs[sn] = sigs[sn]
218 self.sn_to_r[sn] = r
219 print fn, ":"
220 for s in sigs.itervalues():
221 print s
222 self.readers[fn] = r
224 def write(self, fn, fmt, sns, opts):
225 """ Write signals to file
227 # Create the object
228 sigs = self.signames_to_sigs(sns)
229 if len(sigs) < 1:
230 return
231 try:
232 w = DetectWriter(fmt, fn, True)
233 except WriteError, e:
234 print "Write error:", e
235 return
236 if w is not None:
237 try:
238 w.write(fn, sigs, opts)
239 except WriteError, e:
240 print "Write error:", e
242 def update(self, r=None, upn=-1):
243 """ Reread signal from files.
244 For each file, reread it, and for updated, new and deleted signal,
245 update the signal dict accordingly.
247 n = {} # New signals
248 if r is None:
249 # Normal call create the new list etc etc
250 self.upn += 1
251 for reader in self.readers.itervalues():
252 print "Updating signals from", reader
253 n.update(self.update(reader, self.upn))
254 else:
255 # First look at its dependencies
256 if hasattr(r, "get_depends") and callable(r.get_depends):
257 for sn in r.get_depends():
258 print " Updating signals from", self.sn_to_r[sn]
259 n.update(self.update(self.sn_to_r[sn], self.upn))
260 # TODO: Update depencies: what happens to vo when
261 # vout is deleted ? It seems it is not deleted: it should!
262 # Update the reader
263 n.update(r.update(self.upn, keep=False))
264 return n
266 # Find deleted signals
267 d = []
268 for sn, s in self.sigs.iteritems():
269 #n.update(s.update(self.upn, False))
270 if s.data is None:
271 d.append(sn)
272 # Insert new signals
273 self.sigs.update(n)
274 # Delete signals: first from figure and after from dict
275 for sn in d:
276 for f in self.figs:
277 f.remove({sn:self.sigs[sn]}, "all")
278 del self.sigs[sn]
280 def add(self, sns):
281 """ Add a graph to the current figure
282 The signal list is a coma separated list of signal names
283 If no figure exist, create a new one.
285 if not self.figs:
286 self.create(sns)
287 else:
288 sigs = self.signames_to_sigs(sns)
289 self.curfig.add(sigs)
291 def delete(self, gn):
292 """ Delete a graph from the current figure
294 if self.curfig is not None:
295 self.curfig.delete(gn)
297 def mode(self, mode):
298 """ Set the mode of the current graph of the current figure
300 if self.curfig is not None:
301 self.curfig.set_mode(mode)
303 def scale(self, sc):
304 """ Set the axis scale of the current graph of the current figure
306 if self.curfig is not None:
307 self.curfig.set_scale(sc)
309 def range(self, a1 = "reset", a2 = None, a3 = None, a4 = None):
310 """ Set the axis range of the current graph of the current figure
312 if self.curfig is not None:
313 self.curfig.set_range(a1, a2, a3, a4)
315 def unit(self, xu, yu = ""):
316 """ Set the units of current graph of current figure
318 if self.curfig is not None:
319 self.curfig.set_unit(xu, yu)
321 def insert(self, sns):
322 """ Insert a list of signals into the current graph
323 of the current figure
325 if not self.figs:
326 return
328 if self.curfig is not None:
329 sigs = self.signames_to_sigs(sns)
330 self.curfig.insert(sigs)
332 def remove(self, sns):
333 """ Remove a list of signals from the current graph
334 of the current figure
336 if not self.figs:
337 return
339 if self.curfig is not None:
340 sigs = self.signames_to_sigs(sns)
341 self.curfig.remove(sigs)
343 def freeze(self, sns):
344 """ Set the freeze flag of signals
346 sigs = self.signames_to_sigs(sns)
347 for s in sigs.itervalues():
348 s.freeze = True
350 def unfreeze(self, sns):
351 """ Unset the freeze flag of signals
353 sigs = self.signames_to_sigs(sns)
354 for s in sigs.itervalues():
355 s.freeze = False
357 def siglist(self):
358 """ List loaded signals
360 for s in self.sigs.itervalues():
361 print s
363 def math(self, inp):
364 """ Create a signal from mathematical expression
366 sigs = {}
368 # Create the expression
369 r = DetectReader(inp)
370 ss = r.read(inp)
371 if not ss:
372 # Failed to read file
373 # If reader provide a missing() and set_origsigs() functions
374 # and if signal names are found pass them to reader
375 if hasattr(r, "missing") and callable(r.missing):
376 sns = r.missing()
377 if hasattr(r, "set_origsigs") and callable(r.set_origsigs):
378 for sn in sns:
379 if self.sigs.has_key(sn):
380 sigs[sn] = self.sigs[sn]
381 else:
382 print "What is", sn
383 r.set_origsigs(sigs)
384 ss = r.read(inp)
385 if not ss:
386 print "Signal not generated"
387 for sn, s in ss.iteritems():
388 self.sigs[sn] = s
389 self.sn_to_r[sn] = inp
390 self.readers[inp] = r
392 def signames_to_sigs(self, sns):
393 """ Return a signal dict from the signal names list provided
394 If no signals are found, return {}
396 if not sns:
397 return {}
398 sigs = {}
399 # Are there signals ?
400 if not self.sigs:
401 print "No signal loaded"
402 return {}
404 # Prepare the signal list
405 for sn in sns:
406 if sn in self.sigs.keys():
407 sigs[sn] = self.sigs[sn]
408 else:
409 print sn + ": Not here"
411 # No signals found
412 if not sigs:
413 print "No signals found"
414 return {}
415 return sigs