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