1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 """This module defines the classes used to generate interferometer
20 summary screens from data.
21
22 """
23
24
25
26
27
28 from __future__ import division
29
30 import re
31 import calendar
32 import datetime
33 import os
34 import sys
35 import numpy
36 import copy
37 import StringIO
38 import lal
39 import warnings
40
41 from dateutil.relativedelta import relativedelta
42 from matplotlib import use
43
44
45 use("Agg")
46
47 from pylal import git_version
48 from pylal import htmlutils
49 from pylal import plotdata
50 from pylal import plotsegments
51 from pylal import plottriggers
52 from pylal import seriesutils
53 from pylal.dq import dqTriggerUtils
54 from pylal.plotutils import display_name as latex
55
56 from glue import markup
57 from glue import segments
58 from glue import segmentsUtils
59 from glue.ligolw import table, lsctables
60
61 LIGOTimeGPS = float
62
63
64 __author__ = "Duncan M. Macleod <duncan.macleod@ligo.org>"
65 __version__ = git_version.id
66 __date__ = git_version.date
67
68
69 _r_cchar = re.compile("[\W_]+")
70 rindex = re.compile("index.html\Z")
71
72
73 SUMMARY_MODE_GPS = 0
74 SUMMARY_MODE_DAY = 1
75 SUMMARY_MODE_WEEK = 2
76 SUMMARY_MODE_MONTH = 3
77 SUMMARY_MODE_YEAR = 5
78 MODE_NAME = {SUMMARY_MODE_GPS: "GPS",\
79 SUMMARY_MODE_DAY: "DAY",\
80 SUMMARY_MODE_WEEK: "WEEK",\
81 SUMMARY_MODE_MONTH: "MONTH",\
82 SUMMARY_MODE_YEAR: "YEAR"}
83
84
85 TOGGLE = "toggleVisible();"
92 """
93 The default meta-class for the summary tabs. It provides the basics so
94 developers should subclass SummaryTab to generate something useful.
95 """
96 mode = SUMMARY_MODE_GPS
97 ifo = None
99 """
100 Initialise a SummaryTab object. At least a name must be given.
101
102 @param name: a name string for the tab
103 @type name: C{str}
104 """
105
106 self.name = name
107
108
109 kwargs.setdefault("plots", list())
110 kwargs.setdefault("subplots", list())
111 kwargs.setdefault("children", list())
112 kwargs.setdefault("parent", None)
113 kwargs.setdefault("state", None)
114 kwargs.setdefault("information", None)
115 kwargs.setdefault("skip_summary", False)
116
117
118 for key,val in kwargs.iteritems():
119 setattr(self, key, val)
120
121
122
123
124 @property
126 """Descriptive string for this Tab."""
127 if not hasattr(self, "_name"):
128 self.name = ""
129 return self._name
130 @name.setter
131 - def name(self, value):
132 self._name = str(value)
133 @name.deleter
136
137 @property
139 """path to the directory for this Tab."""
140 if not hasattr(self, "_directory"):
141 n = _r_cchar.sub("_", self.name.lower())
142 if hasattr(self, "parent") and self.parent is not None:
143 self.directory = os.path.join(self.parent.directory, n)
144 else:
145 self.directory = os.path.join(os.path.curdir, n)
146 return self._directory
147 @directory.setter
149 self._directory = os.path.normpath(d)
150 @directory.deleter
153
154 @property
156 """GPS start time for this Tab."""
157 return self._start_time
158 @start_time.setter
161 @start_time.deleter
164
165 @property
167 """GPS end time for this Tab."""
168 return self._end_time
169 @end_time.setter
172 @end_time.deleter
175
176 @property
180 @span.setter
181 - def span(self, seg):
184 @span.deleter
187
188 @property
190 """glue.segments.segmentlist describing the analysis segments for
191 this Tab.
192 """
193 return self._segments
194 @segments.setter
199 @segments.deleter
202
203
204
205
206 @property
208 """list of plots for this Tab."""
209 return self._plotlist
210 @plots.setter
211 - def plots(self, plotlist):
212 self._plotlist = list(map(os.path.normpath, plotlist))
213 @plots.deleter
216
217 @property
219 """list of subplots for this Tab."""
220 return self._subplotlist
221 @subplots.setter
223 self._subplotlist = list(map(os.path.normpath, subplotlist))
224 return self._subplotlist
225 @subplots.deleter
227 del self._subplotlist
228
229
230
231
232 @property
234 """path str to the frame for this Tab."""
235 if not hasattr(self, "_href"):
236 basename = "%s.html" % _r_cchar.sub("_", self.state.name).lower()
237 self.href = os.path.join(self.directory, basename)
238 return self._href
239 @href.setter
240 - def href(self, url):
241 self._href = os.path.normpath(url)
242 @href.deleter
245
246 @property
248 """URL to the index for this Tab."""
249 return os.path.join(os.path.normpath(self.directory), "")
250
251
252
253
254
258
260 names = [c.name for c in self.children]
261 try:
262 idx = names.index(name)
263 except ValueError,e:
264 raise RuntimeError("Parent tab has no child named \"%s\". Valid "
265 "children are: %s." % (name, ", ".join(names)))
266 else:
267 return self.children[idx]
268
270 """
271 Write the HTML menu for this tab.
272
273 @param jobdir: output directory of this job
274 @type jobdir: C{str}
275 @param startdate: date at which to start the menubar calendar
276 @type startdate: C{datetime.datetime}
277 @param weekday: day on which to start week in calendar (0=monday)
278 @type weekday: C{int}
279 """
280 self.menu = markup.page()
281 self.menu.div(id_="menubar")
282
283
284 if self.mode == SUMMARY_MODE_DAY:
285 sections = ["Today", "Previous day", "Next day", "Calendar"]
286 marker = "today"
287 strf = "%Y%m%d"
288 delta = datetime.timedelta(days=1)
289 elif self.mode == SUMMARY_MODE_WEEK:
290 sections = ["This week", "Previous week", "Next week",\
291 "Calendar"]
292 marker = "thisweek"
293 strf = "%Y%m%d"
294 delta = datetime.timedelta(days=7)
295 elif self.mode == SUMMARY_MODE_MONTH:
296 sections = ["This month", "Previous month", "Next month",\
297 "Calendar"]
298 marker = "thismonth"
299 strf = "%Y%m"
300 delta = relativedelta(months=1)
301 elif self.mode == SUMMARY_MODE_YEAR:
302 sections = ["This year", "Previous year", "Next year",\
303 "Calendar"]
304 marker = "thisyear"
305 strf = "%Y"
306 delta = relativedelta(years=1)
307 else:
308 sections = ["Full data"]
309 sections.extend(["About", "Glossary"])
310
311
312 if self.name == "Online" and len(self.states):
313 self.menu.div(class_="statetoggle")
314 self.menu.ul(id_="id_statetoggle")
315 for i,s in enumerate(self.states):
316 s2 = _r_cchar.sub("-", s.name.lower())
317 setcls = """$("#li_%s").attr("class","%s");$("#div_%s").%s()"""
318 onclick = []
319 for j,tag in enumerate(self.states):
320 tag = _r_cchar.sub("-", tag.name.lower())
321 class_ = j==i and "open" or "closed"
322 show = j==i and "show" or "hide"
323 onclick.append(setcls % (tag, class_, tag, show))
324 class_ = i==0 and "open" or "closed"
325 id_ = "li_%s" % s2
326 href = "#%s" % s2
327 self.menu.li(s.name, class_=class_, id_=id_, href=href,\
328 onclick=";".join(onclick))
329 self.menu.ul.close()
330 self.menu.div.close()
331 else:
332 run_states = [child.state for child in self.children\
333 if child.state is not None]
334 if len(run_states):
335 self.menu.div(class_="statetoggle")
336 self.menu.ul(id_="statetoggle")
337 for i,state in enumerate(run_states):
338 title = "%s time" % state.name.title()
339 class_ = i==0 and "open" or "closed"
340 id_ = "li_%s" % _r_cchar.sub("-", state.name.lower())
341 onclick = "$(this).loadrunstate(\"%s\");"\
342 % self.children[i].href
343 self.menu.li(title, class_=class_, id_=id_,\
344 onclick=onclick)
345 self.menu.ul.close()
346 self.menu.div.close()
347
348
349 if self.mode != SUMMARY_MODE_GPS:
350 cday = datetime.datetime(*lal.GPSToUTC(int(self.start_time))[:6])
351 cstrf = cday.strftime(strf)
352 for i,sec in enumerate(sections):
353 if re.match("(Today|This )", sec):
354 if re.search(cstrf, self.index):
355 link =\
356 re.sub("%s%s%s" % (os.path.sep, cstrf, os.path.sep),\
357 "%s%s%s" % (os.path.sep, marker, os.path.sep),\
358 self.index)
359 else:
360 link = os.path.join(jobdir, os.pardir, marker, "")
361 if link.endswith("about%s" % os.path.sep):
362 link = link[:-6]
363 elif sec.startswith("Previous "):
364 previous = (cday-delta).strftime(strf)
365 if re.search(cstrf, self.index):
366 link = self.index
367 else:
368 link = jobdir
369 link = link.replace(cstrf, previous)
370 elif sec.startswith("Next "):
371 next_ = (cday+delta).strftime(strf)
372 if re.search(cstrf, self.index):
373 link = self.index
374 else:
375 link = jobdir
376 link = link.replace(cstrf, next_)
377 elif sec == "About" and self.mode != SUMMARY_MODE_GPS:
378 link = os.path.join(jobdir, sec.lower())
379 else:
380 link = sec.lower()
381 link = "%s%s"\
382 % (os.path.normpath(rindex.sub("", link)), os.path.sep)
383 self.menu.a(sec, id_="link_%d" % i, class_="menulink", href=link)
384
385
386 if self.mode == SUMMARY_MODE_GPS or self.name == "Calendar":
387 self.menu.div.close()
388 else:
389 now = int(lal.GPSTimeNow())
390 enddate = datetime.datetime(*lal.GPSToUTC(now)[:6])
391 if self.name in ["Summary", "Glossary", "Calendar"]:
392 menucal = calendar_page(startdate, enddate, weekday=weekday,\
393 path=None, ncol=1, reverse=True)
394 menupath = os.path.join("html", "menucal.html")
395 else:
396 menucal = calendar_page(startdate, enddate, weekday=weekday,\
397 path=self.directory, ncol=1,\
398 reverse=True)
399 menupath = os.path.join("html", "%s_menucal.html"\
400 % _r_cchar.sub("_", re.split("\d\d\d\d%s"\
401 % os.path.sep,\
402 self.directory)[-1]))
403 with open(menupath, "w") as menuf:
404 menuf.write(re.sub(" class=\"\"", "", str(menucal)))
405 self.menu.div("",id_="menucalendar")
406 self.menu.script("$(\"div#menucalendar\").load(\"%s\");"\
407 % menupath, type="text/javascript")
408 self.menu.div.close()
409
411 """
412 Write the links to summary pages for other interferometers.
413
414 @param baselist: list of (ifo, url) pairs defining the base for each
415 IFO.
416 @type baselist: list of tuples
417 @param thisifo: IFO prefix for this Tab.
418 @type thisifo: C{str}
419 @param tablink: relative URL of this Tab to append to all IFO base
420 URLs.
421 @type tablink: C{str}
422 """
423 if re.search("None", str(tablink)):
424 tablink = ""
425 else:
426 tablink = rindex.sub("", tablink)
427 self.ifobar = markup.page()
428 baselist.sort(key=lambda (a,b): a)
429 for ifo,base in baselist:
430 if ifo.upper() == thisifo.upper():
431 self.ifobar.h1(markup.oneliner.a(ifo, href=tablink))
432 else:
433 self.ifobar.h3(markup.oneliner.a(ifo.upper(),\
434 href=os.path.join(base, tablink)))
435
437 """
438 Write this Tab's frame to file as HTML. This allows it to be jquery
439 loaded into a parent page.
440 """
441 with open(self.href, "w") as framef:
442 framef.write(re.sub(" class=\"\"", "", str(self.frame)))
443
444 - def build(self, **initargs):
445 """
446 Write this Tab's full HTML to the index file.
447
448 @keyword **initargs: keyword arguments to pass to markup.page.init.
449 """
450
451 if isinstance(self, OnlineSummaryTab):
452 banner = markup.oneliner.h1("Online data")
453 else:
454 date = datetime.date(*lal.GPSToUTC(int(self.start_time))[:3])
455 if self.mode == SUMMARY_MODE_DAY:
456 banner = "%s: %d-%d" % (date.strftime("%B %d %Y"),\
457 self.start_time, self.end_time)
458 elif self.mode == SUMMARY_MODE_WEEK:
459 banner = "Week of %s: %d-%d" % (date.strftime("%B %d %Y"),\
460 self.start_time, self.end_time)
461 elif self.mode == SUMMARY_MODE_MONTH:
462 banner = "%s: %d-%d" % (date.strftime("%B %Y"),\
463 self.start_time, self.end_time)
464 elif self.mode == SUMMARY_MODE_YEAR:
465 banner = "%s: %d-%d" % (date.strftime("%Y"),\
466 self.start_time, self.end_time)
467 else:
468 banner = "%d-%d" % (self.start_time, self.end_time)
469 banner = markup.oneliner.h1(banner)
470
471
472 if self.mode != SUMMARY_MODE_GPS:
473 homebutton = markup.page()
474 homebutton.ul(class_="buttons")
475 homebutton.li(id_="online")
476 homebutton.a("Online", href="")
477 homebutton.li.close()
478 homebutton.ul.close()
479 else:
480 homebutton = False
481
482
483 initargs.setdefault("title", "Summary: %s" % self.name)
484
485 page = htmlutils.build_page(icon=self.ifobar, banner=banner,\
486 homebutton=homebutton, tabs=self.tabs,\
487 menu=self.menu, frame=self.frame,\
488 **initargs)
489 with open(os.path.join(self.index, "index.html"), "w") as indexf:
490 indexf.write(re.sub(" class=\"\"", "", str(page)))
491
507
510 """
511 SummaryTab representing an overview Tab for a set of child Tabs.
512 """
514 """
515 Write the tabbar for this Tab.
516
517 @param sectiontabs: list of SummaryTab objects to include in tabbar
518 @type sectiontabs: C{list}
519 """
520 self.tabs = markup.page()
521
522
523 sectiontabs.sort(key=lambda t: t.name == "Summary" and 1 or\
524 "Misc." and 3 or 2)
525
526
527 alltabs = []
528 for tab in sectiontabs:
529 tab.children.sort(key=lambda t:
530 re.search('odc(.*)(overview|summary)',
531 t.name, re.I) and 3 or
532 re.search('odc', t.name, re.I) and 4 or
533 re.search('(overview|summary)', t.name, re.I)
534 and 2 or 1)
535 alltabs.append(tab)
536 if tab.name != "Summary":
537 alltabs.extend(tab.children)
538 allnames = [t.name for t in alltabs]
539 if self.name in allnames:
540 current = allnames.index(self.name)
541 else:
542 current = None
543
544
545 self.tabs.div(class_="right")
546 self.tabs.ul(class_="tabs", id_="arrows")
547 if current is not None:
548 self.tabs.li(title="Previous", class_="arrow")
549 href = rindex.sub("", alltabs[(current-1)%len(alltabs)].index)
550 self.tabs.a("←",href=href)
551 self.tabs.li.close()
552 self.tabs.li(title="Next", class_="arrow")
553 href = rindex.sub("", alltabs[(current+1)%len(alltabs)].index)
554 self.tabs.a("→",href=href)
555 self.tabs.li.close()
556 self.tabs.ul.close()
557 self.tabs.div.close()
558
559
560 self.tabs.ul(class_="tabs")
561
562
563 subtabs = None
564 for i,tab in enumerate(sectiontabs):
565 if self.name == tab.name\
566 or (self.parent and self.parent.name == tab.name):
567 class_ = "open"
568 subtabs = tab.children
569 parent = tab
570 else:
571 class_ = "closed"
572 self.tabs.li(id_=_r_cchar.sub("_", tab.name.lower()),\
573 class_=class_, title=self.name)
574 self.tabs.a(tab.name, href=rindex.sub("", tab.index))
575 if class_=="closed" and tab.name == "Summary":
576 self.tabs.ul("",class_="dropdown")
577 elif class_=="closed":
578 self.tabs.ul(class_="dropdown")
579 for subtab in tab.children:
580 self.tabs.li(id_=_r_cchar.sub("_", subtab.name.lower()),\
581 class_="closed", title="Open %s" % subtab.name)
582 self.tabs.a(subtab.name, href=rindex.sub("", subtab.index))
583 self.tabs.li.close()
584 self.tabs.ul.close()
585 self.tabs.li.close()
586 self.tabs.ul.close()
587
588 self.tabs.div(class_="clear")
589 self.tabs.div.close()
590
591 if self.name != "Summary" and subtabs:
592 self.tabs.ul(class_="subtabs",\
593 id_=_r_cchar.sub("_", parent.name.lower()))
594 for tab in subtabs:
595 if self.name == tab.name:
596 class_="open"
597 else:
598 class_="closed"
599 self.tabs.li(id_=_r_cchar.sub("_", tab.name.lower()),\
600 class_=class_, title="Open %s" % tab.name)
601 self.tabs.a(tab.name, href=rindex.sub("", tab.index))
602 self.tabs.li.close()
603 else:
604 self.tabs.ul(class_="subtabs")
605 self.tabs.ul.close()
606
607
608 self.tabs.div("", class_="clear")
609
611 """
612 Write the HTML frame for this SectionSummary.
613 """
614 self.frame = markup.page()
615 div(self.frame, 0, self.name)
616 if self.name == "Summary":
617 order = ["Sensitivity", "Triggers", "Segments"]
618 self.children.sort(key=lambda x: x.parent.name in order\
619 and order.index(x.parent.name)+1 or 1000)
620 children = []
621 for tab in self.children:
622 children.append(tab)
623 else:
624 children = self.children
625 n = len(children) > 1 and 2 or 1
626
627 self.frame.table(style="table-layout: fixed; width: 100%;")
628 for i,tab in enumerate(children):
629 if self.name == "Summary" and tab.skip_summary:
630 continue
631 if i % n == 0:
632 self.frame.tr()
633 self.frame.td()
634 if (self.name == "Summary"):
635 parent = tab.parent
636 self.frame.a(markup.oneliner.h2(parent.name, class_='summary'),
637 href=parent.index, title=parent.name)
638 self.frame.a(href=parent.index, title=parent.name)
639 else:
640 self.frame.a(href=tab.index, title=tab.name)
641 self.frame.h2(tab.name, class_="summary")
642 self.frame.img(src=tab.plots[0][0], alt=tab.name, class_="full")
643 self.frame.a.close()
644 self.frame.td.close()
645 if i % n == (n-1):
646 self.frame.tr.close()
647 self.frame.table.close()
648 self.frame.div.close()
649
651 raise AttributeError("The frametohtml function should not be used"+\
652 " for SegmentSummaryTabs.")
653
673
676 """
677 Object representing a summary of segments.
678 """
684
685
686
687
688 @property
690 """glue.segments.segmentlistdict containing glue.segments.segmentlists
691 for each flag used in this SegmentSummaryTab."""
692 return self._segdict
693 @segdict.setter
700 @segdict.deleter
703
704
705
706
707
709 """
710 Add a glue.segments.segmentlist for a given flag to this object
711
712 @param flag: name of flag to record
713 @type flag: C{str}
714 @param seglist: list of segments to record
715 @type seglist: C{glue.segments.segmentlist}
716
717 """
718 if self.segdict.has_key(flag):
719 self.segdict[flag] += segments.segmentlist(seglist)
720 else:
721 self.flags.append(flag)
722 self.segdict[flag] = segments.segmentlist(seglist)
723
725 """
726 Write the segments know for the given flag to a segwizard format file.
727 If an output filename is not given, one is generated.
728
729 @param flag: name of flag whose segments are to be written
730 @type flag: C{str}
731 @param filename: path string of file to be written
732 @type filename: C{str}
733 """
734 if not filename:
735 name = _r_cchar.sub("-", _r_cchar.sub("_", flag.upper()), 1)
736 filename = os.path.join(self.directory, "%s-%d-%d.txt"\
737 % (name, self.start_time, abs(self.span)))
738 with open(filename, "w") as segf:
739 segmentsUtils.tosegwizard(segf, self.segdict[flag])
740 self.segment_files[flag] = filename
741
743 """
744 Plot the segments associated with this SegmentSummaryTab.
745
746 @param outfile: filename for plot
747 @type outfile: C{str}
748 @param subplot: record plot as a subplot, default: False
749 @type subplot: C{bool}
750 @keyword **kwargs: other arguments to pass to
751 plotsegments.plotsegmentlistdict
752 """
753 if not subplot:
754 kwargs.setdefault("xlim", [self.start_time, self.end_time])
755 kwargs.setdefault("keys", list(self.flags))
756 if re.search("segments\Z", self.name, re.I):
757 kwargs.setdefault("title", self.name)
758 else:
759 kwargs.setdefault("title", "%s segments" % self.name)
760 kwargs.setdefault("subtitle", "%d-%d" % (self.start_time,self.end_time))
761 desc = kwargs.pop("description", None)
762 plotsegments.plotsegmentlistdict(self.segdict, outfile, **kwargs)
763 if subplot:
764 self.subplots.append((outfile, desc))
765 else:
766 self.plots.append((outfile, desc))
767
768 - def plotduration(self, outfile, flag, subplot=False, **kwargs):
769 """
770 Plot the segment durations for the given flag.
771
772 @param outfile: filename for plot
773 @type outfile: C{str}
774 @param flag: name of flag whose segments are to be plotted
775 @type flag: C{str}
776 @param subplot: record plot as a subplot, default: False
777 @type subplot: C{bool}
778 @keyword **kwargs: other arguments to pass to
779 plotsegments.plotsegmentlistdict
780 """
781 desc = kwargs.pop("description", None)
782 if not subplot:
783 kwargs.setdefault("xlim", [self.start_time, self.end_time])
784 kwargs.setdefault("flag", flag)
785 if re.search("segments\Z", self.name, re.I):
786 kwargs.setdefault("title", self.name)
787 else:
788 kwargs.setdefault("title", "%s segments" % self.name)
789 plotsegments.plotduration(self.segdict[flag], outfile, **kwargs)
790 if subplot:
791 self.subplots.append((outfile, desc))
792 else:
793 self.plots.append((outfile, desc))
794
796 """
797 Plot a histogram of the segments associated with this SegmentSummaryTab.
798
799 @param outfile: filename for plot
800 @type outfile: C{str}
801 @param subplot: record plot as a subplot, default: False
802 @type subplot: C{bool}
803 @keyword **kwargs: other arguments to pass to
804 plotsegments.plotsegmentlistdict
805 """
806 desc = kwargs.pop("description", None)
807 kwargs.setdefault("keys", list(self.flags))
808 if re.search("segments\Z", self.name, re.I):
809 kwargs.setdefault("title", self.name)
810 else:
811 kwargs.setdefault("title", "%s segments" % self.name)
812 plotsegments.plothistogram(self.segdict, outfile, **kwargs)
813 if subplot:
814 self.subplots.append((outfile, desc))
815 else:
816 self.plots.append((outfile, desc))
817
819 """
820 Plot the duty cycle of segments associated with this SegmentSummaryTab.
821
822 @param outfile: filename for plot
823 @type outfile: C{str}
824 @param subplot: record plot as a subplot, default: False
825 @type subplot: C{bool}
826 @keyword **kwargs: other arguments to pass to
827 plotsegments.plotsegmentlistdict
828 """
829 desc = kwargs.pop("description", None)
830 kwargs.setdefault("keys", list(self.flags))
831 if not subplot:
832 kwargs.setdefault("xlim", [self.start_time, self.end_time])
833 if re.search("segments\Z", self.name, re.I):
834 kwargs.setdefault("title", self.name)
835 else:
836 kwargs.setdefault("title", "%s segments" % self.name)
837 if self.mode == SUMMARY_MODE_DAY:
838 kwargs.setdefault("binlength", 3600)
839 elif self.mode == SUMMARY_MODE_WEEK or self.mode == SUMMARY_MODE_MONTH:
840 kwargs.setdefault("binlength", 86400)
841 elif self.mode == SUMMARY_MODE_YEAR:
842 kwargs.setdefault("binlength", 365/12*86400)
843 plotsegments.plotdutycycle(self.segdict, outfile, **kwargs)
844 if subplot:
845 self.subplots.append((outfile, desc))
846 else:
847 self.plots.append((outfile, desc))
848
850 """
851 Generate a markup.page object representing the HTML summary of the
852 segments associated with this SegmentSummaryTab.
853 """
854
855 self.frame = markup.page()
856 div(self.frame, 0, self.name)
857 self.frame.p("This page summarises %s segments." % self.name,\
858 class_="line")
859
860
861 div(self.frame, (0, 1), "Summary")
862 self.frame.a(href=self.plots[0][0], title=self.plots[0][1],\
863 rel="full", class_="fancybox-button")
864 self.frame.img(src=self.plots[0][0], alt=self.plots[0][1],class_="full")
865 self.frame.a.close()
866
867
868
869 uptime = abs(self.span & segments.segment(self.span[0],float(lal.GPSTimeNow())))
870 headers = ["Flags", "Livetime (s)", "Duty cycle (\%)", "Relative duty cycle (\%)"]
871 data = []
872 for i,flag in enumerate(self.flags):
873 if i>0:
874 previousuptime = float(abs(self.segdict[self.flags[i-1]]))
875 if previousuptime == 0:
876 previousuptime = numpy.inf
877 data.append([flag, float(abs(self.segdict[flag])),\
878 100*float(abs(self.segdict[flag]))/float(uptime),\
879 100*float(abs(self.segdict[flag]))/previousuptime])
880 else:
881 data.append([flag, float(abs(self.segdict[flag])),\
882 100*float(abs(self.segdict[flag]))/float(uptime),\
883 100*float(abs(self.segdict[flag]))/float(uptime)])
884 self.frame.add(htmlutils.write_table(headers, data, {"table":"full"})())
885 self.frame.div.close()
886
887
888 div(self.frame, (0, 2), "Plots")
889 pclass = len(self.plots[1:]) == 1 and "full" or "half"
890 for plot,desc in self.plots[1:]:
891 self.frame.a(href=plot, title=desc, class_="fancybox-button",\
892 rel="full")
893 self.frame.img(src=plot, alt=desc, class_=pclass)
894 self.frame.a.close()
895 self.frame.div.close()
896
897
898 div(self.frame, (0, 3), "Segment lists")
899 for i,flag in enumerate(self.flags):
900 div(self.frame, (0, 3, i), flag, display=False)
901 segfile = self.segment_files.get(flag, None)
902 if segfile is not None:
903 self.frame.p("The full segment list can be downloaded from %s."\
904 % markup.oneliner.a("this file", href=segfile),\
905 class_="line")
906 segwizard = StringIO.StringIO()
907 segmentsUtils.tosegwizard(segwizard, self.segdict[flag])
908 self.frame.pre(segwizard.getvalue())
909 segwizard.close()
910 self.frame.div.close()
911 self.frame.div.close()
912
913
914 if len(self.subplots):
915 div(self.frame, (0, 4), "Subplots", display=True)
916 for plot,desc in self.subplots:
917 self.frame.a(href=plot, title=desc, class_="fancybox-button",\
918 rel="subplots")
919 self.frame.img(src=plot, alt=desc, class_="quarter")
920 self.frame.a.close()
921 self.frame.div.close()
922
923
924 if self.information:
925 div(self.frame, (0, 5), "Information", display=True)
926 self.frame.add(self.information)
927 self.frame.div.close()
928
929 self.frame.div.close()
930
931
932 for attr in ["segments", "segdict"]:
933 if hasattr(self, attr):
934 try:
935 delattr(self, attr)
936 except AttributeError:
937 raise
938
941 """
942 SummaryTab representing the summary of data extracted from frames.
943 """
945 SummaryTab.__init__(self, *args, **kwargs)
946 self.timeseries = dict()
947 self.sampling = dict()
948 self.spectrum = dict()
949 self.minspectrum = dict()
950 self.maxspectrum = dict()
951 self.designspectrum = dict()
952 self.referencespectrum = dict()
953 self.spectrogram = dict()
954 self.channels = []
955 self.framefiles = dict()
956
957
958
959
960
962 """
963 Add a glue.ligolw.table for a given channel to this object
964
965 @param channel: name of channel to store
966 @type channel: C{str}
967 @param series: TimeSeries data object to store
968 @type series: C{lal.XXXXTimeSeries}
969 """
970 self.timeseries[channel] = series
971 self.sampling[channel] = 1/series.deltaT
972 if channel not in self.channels:
973 self.channels.append(channel)
974
976 """
977 Add a list of REAL8VectorSequence objects as the spectrogram for this
978 channel.
979
980 @param channel: name of channel to store
981 @type channel: C{str}
982 @param sequencelist: spectrogram data object to store, or list of
983 spectrograms
984 """
985 if not self.spectrogram.has_key(channel):
986 self.spectrogram[channel] = []
987 if hasattr(sequencelist, "__contains__"):
988 self.spectrogram[channel].extend(sequencelist)
989 else:
990 self.spectrogram[channel].append(sequencelist)
991 if channel not in self.channels:
992 self.channels.append(channel)
993
1007
1009 """
1010 Add a FrequencySeries object as the minimum spectrum for this
1011 channel.
1012
1013 @param channel: name of channel to store
1014 @type channel: C{str}
1015 @param series: FrequencySeries data object to store
1016 @type series: C{lal.XXXXFrequencySeries}
1017 """
1018 if not series.name.endswith("min"):
1019 series.name = "%s_min" % series.name
1020 self.minspectrum[channel] = series
1021 if channel not in self.channels:
1022 self.channels.append(channel)
1023
1025 """
1026 Add a REAL8FrequencySeries object as the maximum spectrum for this
1027 channel.
1028
1029 @param channel: name of channel to store
1030 @type channel: C{str}
1031 @param series: FrequencySeries data object to store
1032 @type series: C{lal.XXXXFrequencySeries}
1033 """
1034 if not series.name.endswith("max"):
1035 series.name = "%s_max" % series.name
1036 self.maxspectrum[channel] = series
1037 if channel not in self.channels:
1038 self.channels.append(channel)
1039
1041 """
1042 Add a FrequencySeries object as the maximum spectrum for this
1043 channel.
1044
1045 @param channel: name of channel to store
1046 @type channel: C{str}
1047 @param series: FrequencySeries data object to store
1048 @type series: C{lal.XXXXFrequencySeries}
1049 """
1050 self.designspectrum[channel] = series
1051
1053 """
1054 Add a FrequencySeries object as the maximum spectrum for this
1055 channel.
1056
1057 @param channel: name of channel to store
1058 @type channel: C{str}
1059 @param series: FrequencySeries data object to store
1060 @type series: C{lal.XXXXFrequencySeries}
1061 """
1062 self.referencespectrum[channel] = series
1063
1064 - def plottimeseries(self, outfile, channels=None, subplot=False, **kwargs):
1065 """
1066 Plot the timeseries for this TriggerSummary, one column against another.
1067
1068 @param outfile: filename for plot
1069 @type outfile: C{str}
1070 @param channels: list of channels to plot, default: all of them
1071 @type channels: C{list}
1072 @param subplot: record plot as a subplot, default: False
1073 @type subplot: C{bool}
1074 @keyword **kwargs: other arguments to pass to
1075 plotdata.plottimeseries
1076 """
1077 if not channels:
1078 channels = self.channels
1079 desc = kwargs.pop("description", None)
1080 if not subplot:
1081 kwargs.setdefault("xlim", [self.start_time, self.end_time])
1082 data = [seriesutils.duplicate(self.timeseries[channel])\
1083 for channel in channels]
1084 for i,channel in enumerate(channels):
1085 data[i].name = channel
1086 try:
1087 plotdata.plottimeseries(data, outfile, **kwargs)
1088 except ValueError as err:
1089 warnings.warn("ValueError: %s" % err.message)
1090 if subplot:
1091 self.subplots.append((outfile, desc))
1092 else:
1093 self.plots.append((outfile, desc))
1094
1095 - def plothistogram(self, outfile, channels=None, subplot=False, **kwargs):
1096 """
1097 Plot the histogram of data contained with the timeseries' for this
1098 DataSummary.
1099
1100 @param outfile: filename for plot
1101 @type outfile: C{str}
1102 @param channels: list of channels to plot, default: all of them
1103 @type channels: C{list}
1104 @param subplot: record plot as a subplot, default: False
1105 @type subplot: C{bool}
1106 @keyword **kwargs: other arguments to pass to
1107 plotdata.plothistogram
1108 """
1109 if not channels:
1110 channels = self.channels
1111 desc = kwargs.pop("description", None)
1112 data = [self.timeseries[channel] for channel in channels]
1113 for i,channel in enumerate(channels):
1114 data[i].name = channel
1115 if len(channels) == 1:
1116 data[0].name = "_"
1117 plotdata.plothistogram(data, outfile, **kwargs)
1118 if subplot:
1119 self.subplots.append((outfile, desc))
1120 else:
1121 self.plots.append((outfile, desc))
1122
1123 - def plotspectrogram(self, outfile, channel=None, ratio=None, subplot=False,\
1124 **kwargs):
1125 """
1126 Plot the spectrogram of the given channel
1127
1128 @param outfile: filename for plot
1129 @type outfile: C{str}
1130 @param channels: list of channels to plot, default: all of them
1131 @type channels: C{list}
1132 @param ratio: description of ratio to calculate on-the-fly,
1133 e.g. "median", or "design"
1134 @type ratio: C{list}
1135 @param subplot: record plot as a subplot, default: False
1136 @type subplot: C{bool}
1137 @keyword **kwargs: other arguments to pass to
1138 plotdata.plotspectrogram
1139 """
1140 if not channel:
1141 channel = self.channels[0]
1142 desc = kwargs.pop("description", None)
1143 if not subplot:
1144 kwargs.setdefault("xlim", [self.start_time, self.end_time])
1145 kwargs.setdefault("title", latex(channel))
1146
1147
1148 if len(self.spectrogram[channel]):
1149 data = []
1150 epoch = []
1151 deltaT = []
1152 f0 = []
1153 deltaF = []
1154 f_array = self.spectrogram[channel][0]['f_array']
1155 for i in range(len(self.spectrogram[channel])):
1156 data.append(self.spectrogram[channel][i]['data'])
1157 epoch.append(self.spectrogram[channel][i]['epoch'])
1158 deltaT.append(self.spectrogram[channel][i]['deltaT'])
1159 f0.append(self.spectrogram[channel][i]['f0'])
1160 deltaF.append(self.spectrogram[channel][i]['deltaF'])
1161
1162 else:
1163 data = []
1164 epoch = LIGOTimeGPS(self.start_time)
1165 deltaT = 1
1166 f0 = 0
1167 deltaF = 1
1168 f_array = None
1169
1170
1171 if ratio:
1172 if ratio == "median":
1173 spectrum = self.spectrum[channel].data.data
1174 elif ratio == "max":
1175 spectrum = self.maxspectrum[channel].data.data
1176 elif ratio == "min":
1177 spectrum = self.minspectrum[channel].data.data
1178 elif ratio == "design":
1179 spectrum = self.designspectrum[channel].data.data
1180 elif ratio == "reference":
1181 spectrum = self.referencespectrum[channel].data.data
1182 else:
1183 raise ValueError("Unknown ratio mode \"%s\"" % ratio)
1184 for i,sequence in enumerate(data):
1185 data[i] =\
1186 lal.CreateREAL8VectorSequence(sequence.length,\
1187 sequence.vectorLength)
1188 data[i].data = sequence.data/spectrum
1189 numpy.putmask(data[i].data, numpy.isnan(data[i].data), 1e100)
1190
1191 plotdata.plotspectrogram(data, outfile, epoch=epoch, deltaT=deltaT,\
1192 f0=f0, deltaF=deltaF, ydata=f_array, **kwargs)
1193 if subplot:
1194 self.subplots.append((outfile, desc))
1195 else:
1196 self.plots.append((outfile, desc))
1197
1198 - def plotspectrum(self, outfile, channel=None, psd=False, subplot=False,\
1199 **kwargs):
1200 """
1201 Plot the spectrum of the given channel
1202
1203 @param outfile: filename for plot
1204 @type outfile: C{str}
1205 @param channels: list of channels to plot, default: all of them
1206 @type channels: C{list}
1207 @param psd: plot spectrum as a PSD, default False
1208 @type psd: C{bool}
1209 @param subplot: record plot as a subplot, default: False
1210 @type subplot: C{bool}
1211 @keyword **kwargs: other arguments to pass to
1212 plotdata.plotfrequencyseries
1213 """
1214 if channel:
1215 channels = [channel]
1216 else:
1217 channels = self.channels
1218 desc = kwargs.pop("description", None)
1219 serieslist = []
1220 for channel in channels:
1221 serieslist.extend([self.spectrum[channel],
1222 self.minspectrum[channel],\
1223 self.maxspectrum[channel]])
1224 if self.designspectrum.has_key(channel):
1225 serieslist.append(self.designspectrum[channel])
1226 if self.referencespectrum.has_key(channel):
1227 serieslist.append(self.referencespectrum[channel])
1228 if psd:
1229 for i,series in serieslist:
1230 serieslist[i] = seriesutils.fromarray(series.data.data**2,\
1231 name=series.name, epoch=series.epoch,\
1232 deltaT=series.deltaF, f0=series.f0,\
1233 sampleUnits=series.sampleUnits,\
1234 frequencyseries=True)
1235 plotdata.plotfrequencyseries(serieslist, outfile, **kwargs)
1236 if subplot:
1237 self.subplots.append((outfile, desc))
1238 else:
1239 self.plots.append((outfile, desc))
1240
1242 """
1243 Generate a markup.page object representing the HTML summary of the
1244 data associated with this DataSummaryTab.
1245 """
1246
1247 self.frame = markup.page()
1248 div(self.frame, 0, self.name)
1249 self.frame.p("This page summarises %s data." % self.name,\
1250 class_="line")
1251
1252
1253 div(self.frame, (0, 1), "Summary")
1254 if len(self.plots):
1255 self.frame.a(href=self.plots[0][0], title=self.plots[0][1],\
1256 rel="full", class_="fancybox-button")
1257 self.frame.img(src=self.plots[0][0], alt=self.plots[0][1],\
1258 class_="full")
1259 self.frame.a.close()
1260
1261
1262 headers = ["Channel", "Sampling rate"]
1263 data = [[channel, channel in self.sampling and self.sampling[channel] or 'N/A']\
1264 for channel in self.channels\
1265 if not re.search("[-._](min|max)\Z", channel)]
1266 self.frame.add(htmlutils.write_table(headers, data, {"table":"full"})())
1267 self.frame.div.close()
1268
1269
1270 div(self.frame, (0, 2), "Plots")
1271 pclass = len(self.plots[1:]) == 1 and "full" or "half"
1272 for plot,desc in self.plots[1:]:
1273 self.frame.a(href=plot, title=desc, class_="fancybox-button",\
1274 rel="full")
1275 self.frame.img(src=plot, alt=desc, class_=pclass)
1276 self.frame.a.close()
1277 self.frame.div.close()
1278
1279
1280 if len(self.subplots):
1281 div(self.frame, (0, 4), "Subplots", display=True)
1282 for plot,desc in self.subplots:
1283 self.frame.a(href=plot, title=desc, class_="fancybox-button",\
1284 rel="subplots")
1285 self.frame.img(src=plot, alt=desc, class_="quarter")
1286 self.frame.a.close()
1287 self.frame.div.close()
1288
1289
1290 if self.information:
1291 div(self.frame, (0, 5), "Information", display=True)
1292 self.frame.add(self.information)
1293 self.frame.div.close()
1294
1295 self.frame.div.close()
1296
1297
1298 for attr in ["timeseries", "spectrum", "minspectrum", "maxspectrum",\
1299 "spectrogram"]:
1300 if hasattr(self, attr):
1301 delattr(self, attr)
1302
1305 """
1306 SummaryTab representing a summary of detection range extracted from
1307 frames directly or calculated from h(t).
1308 """
1312
1314 self.sources.append(sourcedict)
1315 self.sources.sort(key=lambda s: (s["type"],s["name"]))
1316
1317 @property
1319 """glue.segments.segmentlist describing the veto segments for
1320 this Tab.
1321 """
1322 return self._trigsegments
1323 @trigsegments.setter
1325 self._trigsegments =\
1326 segments.segmentlist([segments.segment(map(float, s))\
1327 for s in vetolist])
1328 @trigsegments.deleter
1330 del self._trigsegments
1331
1333 """
1334 Generate a markup.page object representing the HTML summary of the
1335 data associated with this RangeSummaryTAb.
1336 """
1337
1338 self.frame = markup.page()
1339 div(self.frame, 0, self.name)
1340 self.frame.p("This page summarises %s range data." % self.name,\
1341 class_="line")
1342
1343
1344 div(self.frame, (0, 1), "Summary")
1345 if len(self.plots):
1346 self.frame.a(href=self.plots[0][0], title=self.plots[0][1],\
1347 rel="full", class_="fancybox-button")
1348 self.frame.img(src=self.plots[0][0], alt=self.plots[0][1],\
1349 class_="full")
1350 self.frame.a.close()
1351
1352
1353 headers = ["Source", "Type", "Mean range (Mpc)", "Min range (Mpc)",\
1354 "Max range (Mpc)"]
1355 td = []
1356 for s in self.sources:
1357 data = self.timeseries[s["name"]].data.data
1358 data = data[data!=0]
1359 if data.size:
1360 td.append([s["name"], s["type"], data.mean(), data.min(),\
1361 data.max()])
1362 else:
1363 td.append([s["name"], s["type"], "-", "-", "-"])
1364 self.frame.add(htmlutils.write_table(headers, td, {"table":"full"})())
1365 self.frame.div.close()
1366
1367
1368 div(self.frame, (0, 2), "Plots")
1369 pclass = len(self.plots[1:]) == 1 and "full" or "half"
1370 for plot,desc in self.plots[1:]:
1371 self.frame.a(href=plot, title=desc, class_="fancybox-button",\
1372 rel="full")
1373 self.frame.img(src=plot, alt=desc, class_=pclass)
1374 self.frame.a.close()
1375 self.frame.div.close()
1376
1377
1378 if len(self.subplots):
1379 div(self.frame, (0, 4), "Subplots", display=True)
1380 for plot,desc in self.subplots:
1381 self.frame.a(href=plot, title=desc, class_="fancybox-button",\
1382 rel="subplots")
1383 self.frame.img(src=plot, alt=desc, class_="quarter")
1384 self.frame.a.close()
1385 self.frame.div.close()
1386
1387
1388 if self.information:
1389 div(self.frame, (0, 5), "Information", display=True)
1390 self.frame.add(self.information)
1391 self.frame.div.close()
1392
1393 self.frame.div.close()
1394
1395
1396 for attr in ["timeseries"]:
1397 if hasattr(self, attr):
1398 delattr(self, attr)
1399
1402 """
1403 Object representing a summary of triggers.
1404 """
1406 SummaryTab.__init__(self, *args, **kwargs)
1407 self.triggers = dict()
1408 self.channels = []
1409 self.trigger_files = dict()
1410
1412 """
1413 Add a glue.ligolw.table for a given channel to this object
1414
1415 @param channel: name of channel to record
1416 @type channel: C{str}
1417 @param trigtable: LIGOLw table of triggers to record
1418 @type trigtable: C{glue.ligolw.table.Table}
1419 """
1420 if self.triggers.has_key(channel):
1421 self.triggers[channel].extend(trigtable)
1422 else:
1423 self.triggers[channel] = trigtable
1424 if channel not in self.channels:
1425 self.channels.append(channel)
1426
1427 - def toxml(self, channel, filename=None):
1428 """
1429 Write the trigtable for the given channel to an xml file.
1430
1431 @param channel: name of channel to record
1432 @type channel: C{str}
1433 @param filename: path of file to write, preferrably xml.gz extension
1434 @type filename: C{str}
1435 """
1436 if not filename:
1437 name = _r_cchar.sub("-", _r_cchar.sub("_", channel.upper()), 1)
1438 filename = os.path.join(self.directory, "%s-%d-%d.txt"\
1439 % (name, self.start_time, abs(self.span)))
1440 with open(filename, "w") as trigf:
1441 dqTriggerUtils.totrigxml(trigf, self.triggers[channel],\
1442 program=sys.argv[0])
1443
1444 - def plottable(self, outfile, channels=None, subplot=False,\
1445 **kwargs):
1446 """
1447 Plot the triggers for this TriggerSummary, one column against another.
1448
1449 @param outfile: filename for plot
1450 @type outfile: C{str}
1451 @param channels: list of channels to plot
1452 @type channels: C{list}
1453 @param subplot: record plot as a subplot, default: False
1454 @type subplot: C{bool}
1455 @keyword **kwargs: other arguments to pass to
1456 plottriggers.plottable
1457 """
1458 desc = kwargs.pop("description", None)
1459 if kwargs.get("xcolumn", None) == "time":
1460 kwargs.setdefault("xlim", [self.start_time, self.end_time])
1461 if channels and len(channels) == 1:
1462 kwargs.setdefault("title", "%s (%s)" % (latex(channels[0]),\
1463 latex(self.etg)))
1464 if channels is not None:
1465 trigs = dict((key,val) for (key,val) in self.triggers.iteritems()\
1466 if key in channels)
1467 plottriggers.plottable(trigs, outfile, **kwargs)
1468 if len(self.triggers.keys()) == 1:
1469 kwargs.setdefault("title","%s (%s)" % (latex(self.channels[0]),\
1470 latex(self.etg)))
1471 plottriggers.plottable({"_":self.triggers.values()[0]}, outfile,\
1472 **kwargs)
1473 else:
1474 plottriggers.plottable(self.triggers, outfile, **kwargs)
1475 if subplot:
1476 self.subplots.append((outfile, desc))
1477 else:
1478 self.plots.append((outfile, desc))
1479
1480 - def plothistogram(self, outfile, channels=None, subplot=False, **kwargs):
1481 """
1482 Plot a histogram of the triggers for this TriggerSummary.
1483
1484 @param outfile: filename for plot
1485 @type outfile: C{str}
1486 @param channels: list of channels to plot
1487 @type channels: C{list}
1488 @param subplot: record plot as a subplot, default: False
1489 @type subplot: C{bool}
1490 @keyword **kwargs: other arguments to pass to
1491 plottriggers.plothistogram
1492 """
1493 desc = kwargs.pop("description", None)
1494 if kwargs.get("cumulative", True) and not kwargs.has_key("normalize"):
1495 kwargs["normalize"] = float(abs(self.span))
1496 if channels and len(channels) == 1:
1497 kwargs.setdefault("title", "%s (%s)" % (latex(channels[0]),\
1498 latex(self.etg)))
1499 elif not channels:
1500 kwargs.setdefault("title", "%s (%s)"
1501 % (latex(self.triggers.keys()[0]),\
1502 latex(self.etg)))
1503 kwargs.setdefault("subtitle",
1504 "%d-%d" % (int(self.start_time), int(self.end_time)))
1505 if channels is not None:
1506 trigs = dict((key,val) for key in self.triggers.keys() if key\
1507 in channels)
1508 plottriggers.plothistogram(trigs, outfile, **kwargs)
1509 elif len(self.triggers.keys()) == 1:
1510 plottriggers.plothistogram({"_":self.triggers.values()[0]},\
1511 outfile, **kwargs)
1512 else:
1513 plottriggers.plothistogram(self.triggers, outfile, **kwargs)
1514 if subplot:
1515 self.subplots.append((outfile, desc))
1516 else:
1517 self.plots.append((outfile, desc))
1518
1519 - def plotrate(self, outfile, channels=None, subplot=False, **kwargs):
1520 """
1521 Plot the rate of triggers for this TriggerSummary.
1522
1523 @param outfile: filename for plot
1524 @type outfile: C{str}
1525 @param channels: list of channels to plot
1526 @type channels: C{list}
1527 @param subplot: record plot as a subplot, default: False
1528 @type subplot: C{bool}
1529 @keyword **kwargs: other arguments to pass to
1530 plottriggers.plotrate
1531 """
1532 desc = kwargs.pop("description", None)
1533 kwargs.setdefault("xlim", [self.start_time, self.end_time])
1534 kwargs.setdefault("title", "%s (%s) binned by %s"
1535 % (latex(self.triggers.keys()[0]),
1536 latex(self.etg), latex(kwargs["column"])))
1537 plottriggers.plotrate(self.triggers.values()[0], outfile, **kwargs)
1538 if subplot:
1539 self.subplots.append((outfile, desc))
1540 else:
1541 self.plots.append((outfile, desc))
1542
1545 """
1546 Plot the auto correlation function of the trigers for this
1547 TriggerSummary.
1548
1549 @param outfile: filename for plot
1550 @type outfile: C{str}
1551 @param channels: list of channels to plot
1552 @type channels: C{list}
1553 @param subplot: record plot as a subplot, default: False
1554 @type subplot: C{bool}
1555 @keyword **kwargs: other arguments to pass to
1556 plottriggers.plotautocorrelation
1557 """
1558 desc = kwargs.pop("description", None)
1559 if kwargs.get("xcolumn", None) == "time":
1560 kwargs.setdefault("xlim", [self.start_time, self.end_time])
1561 if channels:
1562 trigs = dict((key,val) for key in self.triggers.keys() if key\
1563 in channels)
1564 plottriggers.plotautocorrelation(trigs, outfile, **kwargs)
1565 elif len(self.triggers.keys()) == 1:
1566 plottriggers.plotautocorrleation({"_":self.triggers.values()[0]},\
1567 outfile, **kwargs)
1568 else:
1569 plottriggers.plotautocorrelation(self.triggers, outfile, **kwargs)
1570 if subplot:
1571 self.subplots.append((outfile, desc))
1572 else:
1573 self.plots.append((outfile, desc))
1574
1575 - def finalize(self, snrs=[5,8,10,20,50,100,500,1000]):
1576 """
1577 Generate a markup.page object summarising the triggers in this
1578 TriggerSummaryTab.
1579 """
1580
1581 self.frame = markup.page()
1582 div(self.frame, 0, self.name)
1583 self.frame.p("This page summarises %s triggers." % self.name,\
1584 class_="line")
1585
1586
1587 div(self.frame, (0, 1), "Summary")
1588 self.frame.a(href=self.plots[0][0], title=self.plots[0][1],\
1589 rel="full", class_="fancybox-button")
1590 self.frame.img(src=self.plots[0][0], alt=self.plots[0][1],class_="full")
1591 self.frame.a.close()
1592
1593
1594 th = ["Channel"]+["SNR >= %d" % s for s in snrs]
1595 td = []
1596 for chan in self.channels:
1597 snr = numpy.asarray(self.triggers[chan].getColumnByName("snr"))
1598 td.append([chan]+[(snr>s).sum() for s in snrs])
1599 self.frame.add(htmlutils.write_table(th, td, {"table":"full"})())
1600 self.frame.div.close()
1601
1602
1603 div(self.frame, (0, 2), "Plots")
1604 pclass = len(self.plots[1:]) == 1 and "full" or "half"
1605 for plot,desc in self.plots[1:]:
1606 self.frame.a(href=plot, title=desc, class_="fancybox-button",\
1607 rel="full")
1608 self.frame.img(src=plot, alt=desc, class_=pclass)
1609 self.frame.a.close()
1610 self.frame.div.close()
1611
1612
1613 div(self.frame, (0, 3), "Loudest events")
1614 for i,chan in enumerate(self.channels):
1615 div(self.frame, (0, 3, i), chan, display=False)
1616 trigfile = self.trigger_files.get(chan, None)
1617 if trigfile is not None:
1618 self.frame.p("The full segment list can be downloaded from %s."\
1619 % markup.oneliner.a("this file", href=trigfile),\
1620 class_="line")
1621 trigs = table.new_from_template(self.triggers[chan])
1622
1623 if re.search("sngl_inspiral", trigs.tableName, re.I):
1624 self.triggers[chan].sort(key=lambda t: t.get_new_snr(),
1625 reverse=True)
1626 else:
1627 self.triggers[chan].sort(key=lambda t: t.snr, reverse=True)
1628 trigs.extend(self.triggers[chan][:20])
1629 data = []
1630 data.append(plottriggers.get_column(trigs, "time"))
1631 head = ["Time"]
1632 if "central_freq" in trigs.validcolumns.keys():
1633 data.append(plottriggers.get_column(trigs, "duration"))
1634 data.append(plottriggers.get_column(trigs, "central_freq"))
1635 data.append(plottriggers.get_column(trigs, "bandwidth"))
1636 head.extend(["Duration", "Frequency", "Bandwidth"])
1637 else:
1638 data.append(plottriggers.get_column(trigs, "template_duration"))
1639 data.append(plottriggers.get_column(trigs, "mchirp"))
1640 head.extend(["Template duration", "Chirp mass"])
1641 data.append(plottriggers.get_column(trigs, "snr"))
1642 head.append("SNR")
1643 if re.search("sngl_inspiral", trigs.tableName, re.I):
1644 data.append(trigs.get_column("new_snr"))
1645 head.append("newSNR")
1646 data = map(list, zip(*data))
1647 self.frame.add(htmlutils.write_table(head,data,{"table":"full"})())
1648 self.frame.div.close()
1649 self.frame.div.close()
1650
1651
1652 if len(self.subplots):
1653 div(self.frame, (0, 4), "Subplots", display=True)
1654 for plot,desc in self.subplots:
1655 self.frame.a(href=plot, title=desc, class_="fancybox-button",\
1656 rel="subplots")
1657 self.frame.img(src=plot, alt=desc, class_="quarter")
1658 self.frame.a.close()
1659 self.frame.div.close()
1660
1661
1662 if self.information:
1663 div(self.frame, (0, 5), "Information", display=True)
1664 self.frame.add(self.information)
1665 self.frame.div.close()
1666
1667 self.frame.div.close()
1668
1669
1670 for attr in ["triggers"]:
1671 if hasattr(self, attr):
1672 delattr(self, attr)
1673
1676 """
1677 Object representing a summary of auxiliary channel triggers.
1678 """
1680 SummaryTab.__init__(self, *args, **kwargs)
1681 self.triggers = dict()
1682 self.channels = []
1683 self.mainchannel = []
1684 self.trigger_files = dict()
1685 self.coincs = dict()
1686 self.numcoincs = dict()
1687 self.sigma = dict()
1688 self.auxplots = dict()
1689
1690 - def get_coincs(self, channel1, channel2, dt=0.03):
1691 """
1692 Find triggers for channel1 within dt of a trigger for channel2.
1693 """
1694 self.coincs[(channel1, channel2)] =\
1695 dqTriggerUtils.get_coincs(self.triggers[channel1],\
1696 self.triggers[channel2], dt=dt)
1697 self.numcoincs[(channel1, channel2)] =\
1698 len(self.coincs[(channel1, channel2)])
1699
1701 """
1702 Calculate the statistical significance of the number of triggers in
1703 channel coincident with a trigger in the mainchannel.
1704 Give a list of numerical time shifts to calculate for multiple events.
1705 """
1706 trigs1 = self.triggers[channel]
1707 trigs2 = self.triggers[self.mainchannel]
1708 t = plottriggers.get_column(trigs1, "time")
1709
1710 _reburst = re.compile("burst", re.I)
1711 _rering = re.compile("ring", re.I)
1712 _recbc = re.compile("inspiral", re.I)
1713 shifts = numpy.asarray(shifts)
1714 ncoinc = numpy.zeros(len(shifts))
1715 for i,shift in enumerate(shifts):
1716 if shift==0 and self.numcoincs.has_key((self.mainchannel, channel)):
1717 ncoinc[i] = self.numcoincs[(self.mainchannel, channel)]
1718 else:
1719 ncoinc[i] = dqTriggerUtils.get_number_coincs(trigs2, trigs1,\
1720 dt=dt,\
1721 timeshift=shift)
1722
1723
1724 mean = ncoinc[shifts!=0].mean()
1725 std = ncoinc[shifts!=0].std()
1726 self.sigma[channel] = dict(zip(shifts, numpy.fabs(ncoinc-mean)/std))
1727
1728 - def plottable(self, outfile, channel, **kwargs):
1729 """
1730 Plot the triggers for the given channel.
1731 """
1732 desc = kwargs.pop("description", None)
1733 if kwargs.get("xcolumn", None) == "time":
1734 kwargs.setdefault("xlim", [self.start_time, self.end_time])
1735 kwargs.setdefault("title", "%s (%s)" % (latex(channel),\
1736 latex(self.etg)))
1737 plottriggers.plottable({"_":self.triggers[channel]}, outfile,\
1738 **kwargs)
1739 self.auxplots[channel].append((outfile, desc))
1740
1746
1747 - def plotrate(self, outfile, channel, **kwargs):
1753
1755 desc = kwargs.pop("description", None)
1756 if kwargs.get("xcolumn", None) == "time":
1757 kwargs.setdefault("xlim", [self.start_time, self.end_time])
1758 plottriggers.plotautocorrleation({"_":self.triggers[channel]},\
1759 outfile, **kwargs)
1760 self.auxplots[chan].append((outfile, desc))
1761
1762 - def plotcoincs(self, outfile, channel, **kwargs):
1763 """
1764 Plot the coincident triggers between the given channel and the
1765 mainchannel.
1766 """
1767 desc = kwargs.pop("description", None)
1768 if kwargs.get("xcolumn", None) == "time":
1769 kwargs.setdefault("xlim", [self.start_time, self.end_time])
1770 kwargs.setdefault("title", "Coincident %s and %s (%s)"\
1771 % (latex(channel), latex(self.mainchannel),\
1772 latex(self.etg)))
1773 trigs = {channel:self.coincs[(channel, self.mainchannel)],\
1774 self.mainchannel:self.coincs[(self.mainchannel, channel)]}
1775 plottriggers.plottable(trigs, outfile, **kwargs)
1776 self.auxplots[channel].append((outfile, desc))
1777
1778 - def plotsigma(self, outfile, channel=None, **kwargs):
1779 """
1780 Plot the statistical significance of the number of coincidences between
1781 the mainchannel and all auxiliary channels.
1782 """
1783 desc = kwargs.pop("description", None)
1784 xdata = []
1785 ydata = []
1786
1787
1788 if channel:
1789 xdata,ydata = zip(*sorted(self.sigma[channel].items(),\
1790 key=lambda (x,y): x))
1791
1792 else:
1793 for chan in self.channels:
1794 if chan == self.mainchannel:
1795 continue
1796 if self.sigma[chan].has_key(0.0):
1797 ydata.append(self.sigma[chan][0.0])
1798 xdata.append(chan)
1799
1800
1801 kwargs.pop("xlim", None)
1802 ylim = kwargs.pop("ylim", None)
1803 kwargs.pop("logx", False)
1804 logy = kwargs.pop("logy", False)
1805
1806
1807 if channel:
1808 xlabel = kwargs.pop("xlabel", "Time shift (s)")
1809 else:
1810 xlabel = kwargs.pop("xlabel", "")
1811 ylabel = kwargs.pop("ylabel", r"Coincidence significance "\
1812 "($\mathrm{\sigma}$)")
1813 if channel:
1814 title = kwargs.pop("title", "Coincident %s and %s (%s)"\
1815 % (latex(channel), latex(self.mainchannel),\
1816 latex(self.etg)))
1817 else:
1818 title = kwargs.pop("title",\
1819 "Significance of coincidences with %s (%s)"\
1820 % (latex(self.mainchannel), latex(self.etg)))
1821 subtitle = kwargs.pop("subtitle", "")
1822
1823
1824 bbox = kwargs.pop("bbox_inches", None)
1825 cbar = kwargs.pop("hidden_colorbar", None)
1826
1827
1828 if channel:
1829 plot = plotdata.plotutils.BarPlot(xlabel, ylabel, title, subtitle)
1830 else:
1831 plot = plotdata.plotutils.BarPlot(xlabel, ylabel, title, subtitle,\
1832 figsize=[24,6])
1833 plot.add_content(numpy.arange(len(xdata)), ydata, **kwargs)
1834 plot.finalize()
1835 if cbar:
1836 plotdata.plotutils.add_colorbar(plot.ax, visible=False)
1837
1838
1839 plot.ax.set_xlim(-1, len(xdata))
1840 plot.ax.set_xticks(numpy.arange(0,len(xdata)))
1841 if channel:
1842 plot.ax.set_xticklabels(map(lambda x: "$%s$"\
1843 % plotdata.plotutils.float_to_latex(x),\
1844 xdata))
1845 else:
1846 plot.ax.set_xticklabels(map(latex, xdata))
1847 for i,t in enumerate(plot.ax.get_xticklabels()):
1848 t.set_rotation(315)
1849 t.set_verticalalignment('top')
1850 t.set_horizontalalignment('left')
1851 t.set_fontsize("smaller")
1852 plot.fig.subplots_adjust(bottom=0.3)
1853
1854 if ylim:
1855 plot.ax.set_ylim(ylim)
1856
1857 plot.savefig(outfile, bbox_inches=bbox)
1858 plot.close()
1859 if channel:
1860 self.auxplots[channel].append((outfile, desc))
1861 else:
1862 self.plots.append((outfile, desc))
1863
1865 """
1866 Plot the number of coincidences between this channel and the
1867 mainchannel for all slides and zerolag.
1868 """
1869 desc = kwargs.pop("description", None)
1870 data = sorted(self.sigma[channel].items(), key=lambda x: x[0])
1871 shifts,sigma = map(numpy.asarray, zip(*data))
1872
1873
1874 kwargs.pop("xlim")
1875 xlim = [shifts.min() - abs(shifts.min())*0.01,\
1876 shifts.max() + abs(shifts.max())+0.01]
1877 ylim = kwargs.pop("ylim", None)
1878 kwargs.pop("logx")
1879 logy = kwargs.pop("logy")
1880
1881
1882 xlabel = kwargs.pop("xlabel", "Time shift (s)")
1883 ylabel = kwargs.pop("ylabel", "Number of coincidences")
1884 title = kwargs.pop("title", "")
1885 subtitle = kwargs.pop("subtitle", "")
1886
1887
1888 bbox = kwargs.pop("bbox_inches", None)
1889 cbar = kwargs.pop("hidden_colorbar", None)
1890
1891
1892 plot = plotdata.plotutils.SimplePlot(xlabel, ylabel, title, subtitle)
1893 plot.add_content(shift, sigma, **kwargs)
1894 plot.finalize()
1895 if logy:
1896 plot.ax.sey_yscale("log")
1897 plot.ax.set_xlim(xlim)
1898 if logy:
1899 plot.ax.set_ylim(ylim)
1900 if cbar:
1901 plotdata.plotutils.add_colorbar(plot.ax, visible=False)
1902
1903 plotdata.plotutils.set_ticks(plot.ax, x=False, y=True)
1904 plot.savefig(outfile, bbox_inches=bbox)
1905 plot.close()
1906 self.auxplots[chan].append((outfile, desc))
1907
1909 """
1910 Generate a glue.markup.page summarising the auxiliary channel triggers
1911 for this AuxTriggerSummaryTab.
1912 """
1913
1914 self.frame = markup.page()
1915 div(self.frame, 0, self.name)
1916 self.frame.p("This page summarises auxiliary channel %s triggers."\
1917 % self.name, class_="line")
1918
1919
1920 if self.mainchannel:
1921 div(self.frame, (0, 1), "Summary")
1922 if len(self.plots):
1923 self.frame.a(href=self.plots[0][0], title=self.plots[0][1],\
1924 class_="fancybox-button", rel="full")
1925 self.frame.img(src=self.plots[0][0], alt=self.plots[0][1],\
1926 class_="full")
1927 self.frame.a.close()
1928
1929
1930 if len(self.numcoincs.keys()) != 0:
1931 th = ["Channel", "Num. coinc. with<br>%s" % self.mainchannel,\
1932 "Num. %s<br>coinc. with aux." % self.mainchannel,\
1933 "Zero shift coinc. σ"]
1934 td = []
1935 cellclasses = {"table":"full"}
1936 for chan in self.channels:
1937 if chan == self.mainchannel:
1938 continue
1939 td.append([chan])
1940 if (chan, self.mainchannel) in self.numcoincs.keys():
1941 td[-1].extend([self.numcoincs[(chan, self.mainchannel)],
1942 self.numcoincs[(self.mainchannel,chan)]])
1943 else:
1944 td[-1].extend(["-", "-"])
1945 if (self.sigma.has_key(chan) and
1946 self.sigma[chan].has_key(0.0)):
1947 sigmaStr = "%.2f" % self.sigma[chan][0.0]
1948 td[-1].append(sigmaStr)
1949 if self.sigma[chan][0.0] > 5:
1950 cellclasses[sigmaStr] = "red"
1951 cellclasses[chan] = "red"
1952 else:
1953 td[-1].append("-")
1954 self.frame.add(htmlutils.write_table(th, td,
1955 cellclasses)())
1956
1957 self.frame.div.close()
1958
1959
1960 div(self.frame, (0, 2), "Auxiliary channels", display=True)
1961
1962 for i,chan in enumerate(self.channels):
1963 if chan == self.mainchannel:
1964 continue
1965 div(self.frame, (0, 2, i), chan, display=True)
1966 if (chan, self.mainchannel) in self.numcoincs:
1967 th = ["Num. coinc with<br>%s" % (self.mainchannel),\
1968 "Num %s<br>coinc with aux." % (self.mainchannel),\
1969 "Zero time-shift coincidence σ"]
1970 td = list()
1971 if (chan, self.mainchannel) in self.numcoincs.keys():
1972 td.extend([self.numcoincs[(chan, self.mainchannel)],\
1973 self.numcoincs[(self.mainchannel, chan)]])
1974 else:
1975 td.extend(["-", "-"])
1976 if self.sigma.has_key(chan) and self.sigma[chan].has_key(0.0):
1977 td.append("%.2f" % self.sigma[chan][0.0])
1978 else:
1979 td.append("-")
1980 self.frame.add(htmlutils.write_table(th,td,{"table":"full"})())
1981 class_ = plotclass(len(self.auxplots[chan]))
1982 for p,d in self.auxplots[chan]:
1983 self.frame.a(href=p, title=d, class_="fancybox-button", rel=class_)
1984 self.frame.img(src=p, alt=d, class_=class_)
1985 self.frame.a.close()
1986 self.frame.div.close()
1987 self.frame.div.close()
1988
1989
1990 if self.information:
1991 div(self.frame, (0, 3), "Information", display=True)
1992 self.frame.add(self.information)
1993 self.frame.div.close()
1994
1995 self.frame.div.close()
1996
1997
1998 for attr in ["triggers", "coincs"]:
1999 if hasattr(self, attr):
2000 delattr(self, attr)
2001
2003 """
2004 Object representing a summary of auxiliary channel triggers.
2005 """
2007 SummaryTab.__init__(self, *args, **kwargs)
2008 self.triggers = dict()
2009 self.channels = []
2010 self.winnerchannels = []
2011 self.mainchannel = []
2012 self.trigger_files = dict()
2013 self.coincs = dict()
2014 self.numcoincs = dict()
2015 self.sigma = dict()
2016 self.auxplots = dict()
2017 self.rounds = {}
2018
2020 """
2021 Kludge, rnd=0 is all the rounds combined
2022 """
2023
2024 desc = kwargs.pop("description", None)
2025 if kwargs.get("cumulative", True) and not kwargs.has_key("normalize"):
2026 kwargs["normalize"] = float(abs(self.span))
2027 trigs = {}
2028 segments_before = segments.segmentlist([])
2029 for i in range(1,rnd):
2030 segments_before |= self.rounds[i].veto_segments
2031 segments_after = segments.segmentlist([])
2032 if rnd:
2033 segments_after |= segments_before
2034 segments_after |= self.rounds[rnd].veto_segments
2035 else:
2036 for i in range(1,1+len(self.rounds)):
2037 segments_after |= self.rounds[i].veto_segments
2038
2039 trigs[" before"] = lsctables.New(lsctables.SnglBurstTable)
2040 trigs[" before"].extend([t for t in self.triggers[self.mainchannel] if t.peak_time not in segments_before])
2041 trigs["after"] = lsctables.New(lsctables.SnglBurstTable)
2042 trigs["after"].extend([t for t in self.triggers[self.mainchannel] if t.peak_time not in segments_after])
2043 plottriggers.plothistogram(trigs, outfile,\
2044 **kwargs)
2045 self.auxplots[rnd].append((outfile, desc))
2046
2048 """
2049 Plot the coincident triggers between the given round
2050 """
2051 desc = kwargs.pop("description", None)
2052 if kwargs.get("xcolumn", None) == "time":
2053 kwargs.setdefault("xlim", [self.start_time, self.end_time])
2054 if rnd:
2055 auxchannelname = latex(self.rounds[rnd].channel)
2056 else :
2057 auxchannelname = "auxiliary"
2058 kwargs.setdefault("title", "Coincident %s and %s (%s)"\
2059 % (auxchannelname, latex(self.mainchannel),\
2060 latex(self.etg)))
2061 trigs = {}
2062 if rnd:
2063 trigs[auxchannelname] = self.rounds[rnd].vetoing_aux_trigs
2064 trigs[self.mainchannel] = self.rounds[rnd].vetoed_h_trigs
2065 else:
2066 trigs[auxchannelname] = lsctables.New(lsctables.SnglBurstTable)
2067 trigs[self.mainchannel] = lsctables.New(lsctables.SnglBurstTable)
2068 for i in range(1,1+len(self.rounds)):
2069 trigs[auxchannelname].extend(self.rounds[i].vetoing_aux_trigs)
2070 trigs[self.mainchannel].extend(self.rounds[i].vetoed_h_trigs)
2071 plottriggers.plottable(trigs, outfile, **kwargs)
2072 self.auxplots[rnd].append((outfile, desc))
2073
2075 """
2076 Generate a glue.markup.page summarising the auxiliary channel triggers
2077 for this AuxTriggerSummaryTab.
2078 """
2079
2080 self.frame = markup.page()
2081 div(self.frame, 0, self.name)
2082 self.frame.p("This page summarise hveto with %s triggers."\
2083 % self.name, class_="line")
2084
2085
2086 if self.mainchannel:
2087 div(self.frame, (0, 1), "Summary")
2088 if len(self.plots):
2089 self.frame.a(href=self.plots[0][0], title=self.plots[0][1],\
2090 class_="fancybox-button", rel="full")
2091 self.frame.img(src=self.plots[0][0], alt=self.plots[0][1],\
2092 class_="full")
2093 self.frame.a.close()
2094
2095 th = ['Channel', 'Significance', 'T win.', 'SNR', 'Use %', 'Eff.', 'Deadtime',\
2096 'Eff./Deadtime', 'Cum. Eff.', 'Cum. Deadtime', 'Cum. Eff./Deadtime',\
2097 'Safety', 'Segments' ]
2098 td = []
2099 cellclasses = {"table":"full"}
2100
2101
2102 cumeff = 0
2103 cumdt = 0
2104 for i in sorted(self.rounds.keys()):
2105
2106 use = self.rounds[i].use_percentage
2107 eff = self.rounds[i].efficiency[0]
2108 dt = self.rounds[i].deadtime[0]
2109 edr = self.rounds[i].deadtime!=0\
2110 and round(eff/dt, 2) or 'N/A'
2111 cumeff += eff
2112 cumdt += dt
2113 cumedr = cumeff/cumdt
2114
2115 use = '%s%%' % round(use, 2)
2116 eff = '%s%%' % round(eff, 2)
2117 dt = '%s%%' % round(dt, 3)
2118 cumeffstr = '%s%%' % round(cumeff, 2)
2119 cumdtstr = '%s%%' % round(cumdt, 2)
2120 cumedrstr = '%s%%' % round(cumedr, 2)
2121
2122
2123 safe = 'N/A'
2124
2125
2126 td.append([self.rounds[i].channel, round(self.rounds[i].significance, 2), self.rounds[i].dt, self.rounds[i].snr,\
2127 use, eff, dt, edr, cumeffstr, cumdtstr, cumedrstr, safe,\
2128 '<a href="%s" rel="external">link</a>' % self.rounds[i].veto_file])
2129
2130 self.frame.add(htmlutils.write_table(th, td,
2131 cellclasses)())
2132
2133 self.frame.div.close()
2134
2135
2136 div(self.frame, (0, 2), "Auxiliary channels", display=True)
2137
2138 for i,chan in enumerate(self.winnerchannels):
2139 div(self.frame, (0, 2, i), chan, display=True)
2140 class_ = plotclass(len(self.auxplots[i+1]))
2141 for p,d in self.auxplots[i+1]:
2142 self.frame.a(href=p, title=d, class_="fancybox-button", rel=class_)
2143 self.frame.img(src=p, alt=d, class_=class_)
2144 self.frame.a.close()
2145 self.frame.div.close()
2146 self.frame.div.close()
2147
2148
2149 if self.information:
2150 div(self.frame, (0, 3), "Information", display=True)
2151 self.frame.add(self.information)
2152 self.frame.div.close()
2153
2154 self.frame.div.close()
2155
2156
2157 for attr in ["triggers", "coincs"]:
2158 if hasattr(self, attr):
2159 delattr(self, attr)
2160
2163 """
2164 Object representing the summary of a bitmasked channel.
2165 """
2170
2172 self.bitmask = dict(bitmask)
2173 self.bits = sorted(self.bitmask.keys())
2174
2176 self.derived_bitmask = dict(derived_bitmask)
2177 self.derived_bits = sorted(self.derived_bitmask.keys())
2178
2180 """
2181 Generate a markup.page object representing the HTML summary of the
2182 segments associated with this StateVectorSummaryTab.
2183 """
2184
2185 self.frame = markup.page()
2186 div(self.frame, 0, self.name)
2187 self.frame.p("This page summarises %s state vector." % self.name,\
2188 class_="line")
2189
2190
2191 div(self.frame, (0, 1), "Summary")
2192 self.frame.a(href=self.plots[0][0], title=self.plots[0][1],\
2193 class_="fancybox-button", rel="full")
2194 self.frame.img(src=self.plots[0][0], alt=self.plots[0][1],\
2195 class_="full")
2196 self.frame.a.close()
2197
2198
2199 uptime = float(abs(self.span))
2200 headers = ["Bit", "Flag", "Livetime (s)", "Duty cycle (%%)"]
2201 data = [[bit, self.bitmask[bit],\
2202 abs(self.segdict[self.bitmask[bit]]),\
2203 "%.2f" %\
2204 (100*(abs(self.segdict[self.bitmask[bit]])/uptime))]\
2205 for bit in self.bits]
2206 self.frame.add(htmlutils.write_table(headers, data, {"table":"full"})())
2207 self.frame.div.close()
2208
2209
2210 if len(self.plots) > 1:
2211 div(self.frame, (0, 2), "Plots")
2212 for plot,desc in self.plots[1:]:
2213 self.frame.a(href=plot, title=desc, class_="fancybox-button",\
2214 rel="half")
2215 self.frame.img(src=plot, alt=desc, class_="half")
2216 self.frame.a.close()
2217 self.frame.div.close()
2218
2219
2220 div(self.frame, (0, 3), "Segment lists")
2221 for i,bit in enumerate(self.bits):
2222 flag = self.bitmask[bit]
2223 div(self.frame, (0, 3, i), flag, display=False)
2224 segfile = self.segment_files.get(flag, None)
2225 if segfile is not None:
2226 self.frame.p("The full segment list can be downloaded from %s."\
2227 % markup.oneliner.a("this file", href=segfile),\
2228 class_="line")
2229 segwizard = StringIO.StringIO()
2230 segmentsUtils.tosegwizard(segwizard, self.segdict[flag])
2231 self.frame.pre(segwizard.getvalue())
2232 segwizard.close()
2233 self.frame.div.close()
2234 self.frame.div.close()
2235
2236
2237 if len(self.subplots):
2238 div(self.frame, (0, 4), "Subplots", display=True)
2239 for plot,desc in self.subplots:
2240 self.frame.a(href=plot, title=desc, class_="fancybox-button",\
2241 rel="subplots")
2242 self.frame.img(src=plot, alt=desc, class_="quarter")
2243 self.frame.a.close()
2244 self.frame.div.close()
2245
2246
2247 if self.information:
2248 div(self.frame, (0, 5), "Information", display=True)
2249 self.frame.add(self.information)
2250 self.frame.div.close()
2251
2252 self.frame.div.close()
2253
2254
2255 for attr in ["segdict"]:
2256 if hasattr(self, attr):
2257 delattr(self, attr)
2258
2261
2263 SummaryTab.__init__(self, *args, **kwargs)
2264 self.tabs = ""
2265 self.definitions = dict()
2266
2267 - def add_entry(self, key, val):
2268 self.definitions[key] = val
2269
2271 for key,val in args:
2272 self.add_entry(key, val)
2273
2275 """
2276 Write the GlossaryTab HTML frame.
2277 """
2278 self.frame = htmlutils.write_glossary(self.definitions)
2279
2299
2302
2307
2308 @property
2310 """datetime.datetime start date for this CalendarTab."""
2311 return self._start_date
2312 @start_date.setter
2314 if isinstance(date, str):
2315 if re.search("/", startdate):
2316 self._start_date = datetime.datetime.strptime(date, "%Y/%m/%d")
2317 else:
2318 self._start_date = datetime.datetime.strptime(date, "%Y%m%d")
2319 elif isinstance(date, int):
2320 self._start_date = datetime.date(*lal.GPSToUTC(int(date))[:3])
2321 elif isinstance(date, datetime.datetime)\
2322 or isinstance(date, datetime.date):
2323 self._start_date = date
2324
2325 @property
2327 """datetime.datetime end date for this CalendarTab."""
2328 return self._end_date
2329 @end_date.setter
2331 if isinstance(date, str):
2332 if re.search("/", enddate):
2333 self._end_date = datetime.datetime.strptime(date, "%Y/%m/%d")
2334 else:
2335 self._end_date = datetime.datetime.strptime(date, "%Y%m%d")
2336 elif isinstance(date, int):
2337 self._end_date = datetime.date(*lal.GPSToUTC(int(date))[:3])
2338 elif isinstance(date, datetime.datetime)\
2339 or isinstance(date, datetime.date):
2340 self._end_date = date
2341
2342
2343
2344
2345
2347 """
2348 Returns a glue.markup.page containing a nested HTML table of links
2349 for the given SummaryTab.
2350 """
2351
2352 years = numpy.arange(self.start_date.year, self.end_date.year+1)
2353
2354
2355 self.frame = markup.page()
2356 self.frame.h1('Calendar')
2357 for i,y in enumerate(years[::-1]):
2358 startdate = datetime.date(y, 1, 1)
2359 enddate = min(self.end_date, datetime.date(y, 12, 31))
2360 self.frame.h2(y, id="h2_%d" % i, onclick="toggleVisible();",\
2361 class_="calendar %s" % (i==0 and 'open' or 'closed'))
2362 self.frame.div(id="div_%d" % i, class_="calendar",\
2363 style="display: %s;" % (i==0 and 'block' or 'none'))
2364 self.frame.add(calendar_page(startdate, enddate,\
2365 weekday=self.weekday)())
2366 self.frame.div.close()
2367
2370 """
2371 SummaryTab representing the online data page.
2372 """
2374 SummaryTab.__init__(self, *args, **kwargs)
2375 self.tabs = ""
2376 self.states = list()
2377 self.sections = list()
2378 self.plots = dict()
2379 self.refresh = None
2380
2381 @property
2383 """dict of plots for this OnlineSummaryTab."""
2384 return self._plotdict
2385 @plots.setter
2386 - def plots(self, plotdict):
2387 self._plotdict = plotdict
2388 if isinstance(plotdict, dict):
2389 for key,val in plotdict.iteritems():
2390 for key2,val2 in val.iteritems():
2391 self._plotdict[key][key2] =\
2392 map(os.path.normpath(plotdict[key][key2]))
2393 @plots.deleter
2396
2398 self.states.append(statelist)
2399 for state in statelist:
2400 if not state in self.plots.keys():
2401 self.plots[state] = dict()
2402
2404 state = SummaryState(str(state))
2405 if not state in self.states:
2406 self.states.append(state)
2407 self.plots[state] = dict()
2408 for key,plot in plotlist:
2409 if key not in self.sections:
2410 self.sections.append(key)
2411 if key not in self.plots[state].keys():
2412 self.plots[state][key] = []
2413 self.plots[state][key].extend(plot.split(','))
2414
2416 """
2417 Write the tabbar used for this OnlineSummaryTab.
2418 """
2419 self.tabs = markup.page()
2420 self.tabs.ul(class_="buttons")
2421 for i,section in enumerate(sorted(self.sections, key=str.lower)):
2422 self.tabs.li(section, class_="open", onclick="toggleVisible();",\
2423 id_="button_%s" % _r_cchar.sub("-", section), \
2424 title="Hide/show %s" % section)
2425 self.tabs.ul.close()
2426
2428 """
2429 Write the HTML frame for this OnlineSummaryTab.
2430 """
2431 if not self.tabs:
2432 self.write_tabs()
2433 self.frame = markup.page()
2434 if len(self.states) == 0:
2435 self.frame.p("No online monitors configured.", class_="line")
2436 else:
2437 self.frame.p("This frame shows the current status of this "+\
2438 "instrument. Select which sections to view using the "+\
2439 "buttons above.", class_="line", id_="online")
2440 if self.refresh:
2441 self.frame.p("Plots will auto refresh every %d seconds"\
2442 % self.refresh, class_="line")
2443 for i,state in enumerate(self.states):
2444 style = i==0 and "block" or "none"
2445 self.frame.div(id_="div_%s"\
2446 % _r_cchar.sub("-", state.name.lower()),\
2447 style="display: %s;" % style)
2448 for j,section in enumerate(sorted(self.plots[state].keys(),
2449 key=str.lower)):
2450 self.frame.div(class_="toggle_%s"% _r_cchar.sub("-", section),\
2451 style="display: block;")
2452 self.frame.h2(section, id_="h2_%d" % i, class_="open",\
2453 onclick="toggleVisible();")
2454 self.frame.div(id_="div_%d" % i, style="display: block;")
2455 c = plotclass(len(self.plots[state][section]))
2456 for k,plot in enumerate(self.plots[state][section]):
2457 self.frame.a(id_="img_%d-%d" % (i,k), href=plot, rel=c)
2458 self.frame.img(src=plot, id_="imd_%d-%d" % (i,k),\
2459 class_="%s online" % c)
2460 self.frame.a.close()
2461 self.frame.div.close()
2462 self.frame.div.close()
2463 self.frame.div.close()
2464 if self.refresh:
2465 self.frame.script("refreshImages(%s);" % self.refresh,
2466 type="text/javascript")
2467
2473 """
2474 Object representing a choice of IFO state.
2475 """
2477 """
2478 Define a new SummaryState with the given name
2479
2480 @param name: descriptive name for this SummaryState
2481 @type name: C{str}
2482 @return: a new SummaryState object
2483 @rtype: C{summary.SummaryState}
2484 """
2485
2486 self.name = name
2487 self.definition = None
2488 self.segments = segments.segmentlist()
2489 self.set = False
2490 self.segment_buffer = 0
2491 self.event_buffer = 0
2492 self.minimum_segment_length = None
2493
2494
2495 self.tag = _r_cchar.sub("_", name.lower()).upper()
2496 self.match = re.compile("%s\Z" % self.tag, re.I).match
2497
2498 @property
2500 """GPS start time for this Tab."""
2501 return self._start_time
2502 @start_time.setter
2505 @start_time.deleter
2507 del self._start_time
2508
2509 @property
2511 """GPS end time for this Tab."""
2512 return self._end_time
2513 @end_time.setter
2516 @end_time.deleter
2519
2520 @property
2524 @span.setter
2525 - def span(self, seg):
2528 @span.deleter
2531
2532 @property
2534 """glue.segments.segmentlist describing the valid segments for
2535 this SummaryState.
2536 """
2537 return self._segments
2538 @segments.setter
2540 self._segments =\
2541 segments.segmentlist([segments.segment(map(float, s))\
2542 for s in seglist])
2543 @segments.deleter
2546
2547
2548
2549
2550
2551 -def calendar_page(startdate, enddate, path=None, jobdir=".",\
2552 weekday=calendar.MONDAY, ncol=4, reverse=False):
2553 """
2554 Write an HTML calendar for the given [gpsstart, gpsend) interval.
2555 One table per month, one link per day.
2556 """
2557 d = datetime.date(startdate.year, 1, 1)
2558 calendar.setfirstweekday(weekday)
2559
2560 if reverse:
2561 m = enddate
2562 else:
2563 m = datetime.date(startdate.year, 1, 1)
2564
2565 page = markup.page()
2566
2567 if not path:
2568 path = os.path.sep
2569 else:
2570 path = os.path.normpath(path)
2571 path = os.path.join(*re.split(os.path.sep, path)[-2:])
2572 if re.match("\d+/", path):
2573 path = os.path.join(*os.path.split(path)[1:])
2574 if path == "/":
2575 path = ""
2576
2577
2578 i = 0
2579 if ncol==1:
2580 page.table(class_="calendar")
2581 else:
2582 page.table(class_="calendar year")
2583 while startdate.year <= m.year < enddate.year+1:
2584
2585 if i==0 or (i % ncol == 0 and ((reverse and m.month==12)\
2586 or (not reverse and m.month==1))):
2587 page.tr()
2588 Y = m.year
2589 idx = os.path.join(jobdir, "archive_yearly", str(m.year),
2590 path, "index.html")
2591 if os.path.isfile(os.path.expanduser(idx)):
2592 href = "%s%s" % (os.path.split(idx)[0], os.path.sep)
2593 page.th(markup.oneliner.a(Y, href=href),
2594 class_="year", colspan="100%")
2595 else:
2596 page.th(Y, class_="year", colspan="100%")
2597 page.tr.close()
2598
2599
2600
2601 if i % ncol == 0:
2602 page.tr()
2603
2604 if reverse and m.month == 1:
2605 delta = datetime.timedelta(days=-calendar.monthrange(m.year-1,\
2606 12)[1])
2607 elif reverse:
2608 delta = datetime.timedelta(days=-calendar.monthrange(m.year,\
2609 m.month-1)[1])
2610 else:
2611 delta = datetime.timedelta(days=calendar.monthrange(m.year,\
2612 m.month)[1])
2613
2614
2615 if (m.year == startdate.year and m.month < startdate.month)\
2616 or (m.year == enddate.year and m.month > enddate.month):
2617 if ncol==1:
2618 page.td(str())
2619 else:
2620 page.td(str(), class_="calendar month")
2621
2622
2623 else:
2624 if ncol==1:
2625 page.td()
2626 page.table(class_="calendar")
2627 else:
2628 page.td(class_="calendar month")
2629 page.table(class_="calendar month")
2630
2631 month = calendar.monthcalendar(m.year, m.month)
2632
2633
2634 page.tr()
2635 H = "%s %s" % (calendar.month_name[m.month], m.year)
2636 href = None
2637 idx = os.path.join(jobdir, "archive_monthly", m.strftime("%Y%m"),
2638 path, "index.html")
2639 if os.path.isfile(os.path.expanduser(idx)):
2640 href = "%s%s" % (os.path.split(idx)[0], os.path.sep)
2641 page.th(markup.oneliner.a(H, class_="day", href=href),
2642 colspan="100%")
2643 else:
2644 page.th(H, colspan="100%")
2645 page.tr.close()
2646
2647
2648 for week in month:
2649 page.tr()
2650 for idx,day in enumerate(week):
2651 if day != 0:
2652 break
2653 w = (datetime.date(m.year, m.month, day)\
2654 - datetime.timedelta(days=idx)).strftime("%Y%m%d")
2655 href = None
2656 idx = os.path.join(jobdir, "archive_weekly", w,
2657 path, "index.html")
2658 if os.path.isfile(os.path.expanduser(idx)):
2659 href = "%s%s" % (os.path.split(idx)[0], os.path.sep)
2660 page.td(markup.oneliner.a("w", class_="day", href=href))
2661 else:
2662 page.td("w")
2663
2664 for day in week:
2665
2666 if day == 0:
2667 page.td("")
2668 continue
2669
2670 d = datetime.date(m.year, m.month, day).strftime("%Y%m%d")
2671 href = None
2672 idx = os.path.join(jobdir, "archive_daily", d,
2673 path, "index.html")
2674 if os.path.isfile(os.path.expanduser(idx)):
2675 href = "%s%s" % (os.path.split(idx)[0], os.path.sep)
2676 page.td(markup.oneliner.a(str(day), class_="day",\
2677 href=href))
2678 else:
2679 page.td(str(day))
2680 page.tr.close()
2681 page.td.close()
2682 page.table.close()
2683
2684
2685 if i % ncol == ncol -1:
2686 page.tr.close()
2687
2688
2689 m += delta
2690 i += 1
2691
2692 page.table.close()
2693 return page
2694
2696 """
2697 Guess the plot class to use from the number of plots
2698 """
2699 if n % 5 == 0:
2700 return "fifth"
2701 elif n % 4 == 0:
2702 return "quarter"
2703 elif n % 3 == 0:
2704 return "third"
2705 elif n % 2 == 0:
2706 return "half"
2707 else:
2708 return "full"
2709
2710
2711 -def div(page, id_, header, display=True):
2712 """Write a new <div> tag to the give markup.page object
2713 """
2714 if isinstance(id_, int):
2715 id_ = str(id_)
2716 elif not isinstance(id_, str):
2717 id_ = ".".join(list(map(str, id_)))
2718 N = len(re.split("\.", id_))
2719
2720 if N == 1:
2721 title = header
2722 else:
2723 title = "%s %s" % (id_.split(".", 1)[1], header)
2724
2725 if not display:
2726 display = "display: none;"
2727 class_ = "closed"
2728 else:
2729 display = "display: block;"
2730 class_ = "open"
2731
2732 getattr(page, "h%d" % N)(title, onclick=TOGGLE,\
2733 id_="h%d_%s" % (N, id_.replace(".","-")),\
2734 class_=class_)
2735 page.div(id_="div_%s" % id_.replace(".","-"), style=display)
2736