def print_segments(flag, table=False, caption=None): """Print the contents of a `SegmentList` in HTML """ if isinstance(flag, DataQualityFlag): flag = flag.active dtype = float(abs(flag)).is_integer() and int or float if table: headers = [ 'GPS start', 'GPS end', 'UTC start', 'UTC end', 'Duration [s]' ] data = [] for seg in flag: data.append([ dtype(seg[0]), dtype(seg[1]), from_gps(seg[0]).strftime('%B %d %Y %H:%M:%S.%f')[:-3], from_gps(seg[1]).strftime('%B %d %Y %H:%M:%S.%f')[:-3], dtype(abs(seg)), ]) return gwhtml.table(headers, data, id='state-information', caption=caption) else: segwizard = StringIO() flag.write(segwizard, format='segwizard', coltype=dtype) return markup.oneliner.pre(segwizard.getvalue())
def write_state_html(self, state): """Write the HTML for the given state of this `GuardianTab` """ page = self.scaffold_plots(state=state) page.div(class_='row') page.div(class_='col-md-12') # get segment data groups = type(self.modes)((idx, name) for idx, name in self.modes.items() if idx % 10 == 0) modes = type(self.modes)( (idx, name) for idx, name in self.modes.items() if not name.startswith('*')) headers = ['Index', 'Name', 'Active seconds', 'Hours', '%'] prefix = self.ifo.lower() for flags, title, id in zip( [groups, modes], ['Top-level mode information', 'Detailed mode information'], ['%s-top-level-mode' % prefix, '%s-detailed-mode' % prefix]): page.h1(title) data = [] pc = float(abs(state.active) / 100.) tots = 0 toth = 0 totp = 0 for idx, name in flags.items(): flag = get_segments(self.segmenttag % idx, state.active, query=False).copy() actives = abs(flag.active) activeh = actives / 3600. try: activep = actives / pc except ZeroDivisionError: activep = 0 tots += actives toth += activeh totp += activep data.append([str(idx), name.strip('*'), '%.1f' % actives, '%.1f' % activeh, '%.1f' % activep]) data.append(['<strong>%s</strong>' % x for x in [ '', 'Total:', '%.1f' % tots, '%.1f' % toth, '%.1f' % totp]]) page.add(str(html.table( headers, data, id=id, caption="%s observatory mode statistics as recorded in " "<samp>%s</samp>" % (title.split()[0], self.channel)))) return super(ParentTab, self).write_state_html(state, plots=False, pre=page)
def print_segments(flag, table=False, caption=None): """Print the contents of a `SegmentList` in HTML """ if isinstance(flag, DataQualityFlag): flag = flag.active dtype = float(abs(flag)).is_integer() and int or float if table: headers = ['GPS start', 'GPS end', 'UTC start', 'UTC end', 'Duration [s]'] data = [] for seg in flag: data.append([ dtype(seg[0]), dtype(seg[1]), from_gps(seg[0]).strftime('%B %d %Y %H:%M:%S.%f')[:-3], from_gps(seg[1]).strftime('%B %d %Y %H:%M:%S.%f')[:-3], dtype(abs(seg)), ]) return gwhtml.table(headers, data, id='state-information', caption=caption) else: segwizard = StringIO() flag.write(segwizard, format='segwizard', coltype=dtype) return markup.oneliner.pre(segwizard.getvalue())
def write_state_html(self, state): """Build HTML summary of watchdog trips """ # find one example of each channel, and get the bits hepichannel = get_channel(HEPI_LATCH_CHANNEL % (self.ifo, self.chambers[1])) hepimask = hepichannel.bits + ['HEPI Unknown'] if self.chambers == HAMs: isichannels = [ get_channel(HAM_ISI_LATCH_CHANNEL % (self.ifo, self.chambers[0])) ] isimask = isichannels[0].bits + ['ISI Unknown'] else: isichannels = [ get_channel(BSC_ST1_LATCH_CHANNEL % (self.ifo, self.chambers[0])), get_channel(BSC_ST2_LATCH_CHANNEL % (self.ifo, self.chambers[0])) ] isimask = (isichannels[0].bits + ['ISI ST1 Unknown'] + isichannels[1].bits + ['ISI ST2 Unknown']) mask = hepimask + isimask # count trips count = {} for _, chamber, trigger, _ in self.trips: key = (chamber, trigger) try: count[key] += 1 except KeyError: count[key] = 1 page = markup.page() # build summary table page.div(class_='well') chambertype = self.chambers[0][:-1] id_ = '{}-{}'.format(self.ifo.lower(), chambertype.lower()) page.table(class_='table table-condensed table-hover watchdog', id_=id_) page.caption("Number of watch-dog trips per %s chamber (column) and " "trigger (row)" % (chambertype)) page.thead() # add headers page.tr(class_='header') for th in ['WD'] + self.chambers + ['Sub-total']: page.th(th) page.tr.close() page.thead.close() # add rows page.tbody() totals = numpy.zeros((len(mask), len(self.chambers) + 1), dtype=int) rows = [] for i, bit in enumerate(mask): class_ = [] if (i == len(hepimask) or i == len(hepimask + isichannels[0].bits)): class_.append('tdiv') if re_no_count.match(bit): class_.append('ignore') if class_: page.tr(class_=' '.join(class_)) else: page.tr() page.th(bit) for j, chamber in enumerate(self.chambers): try: c = count[(chamber, bit)] except KeyError: c = 0 pass page.td(c or '-') # exclude IOP from total if not re_no_count.match(bit): totals[i][j] = c # add row total totals[i][-1] = totals[i].sum() page.th(str(totals[i][-1])) page.tr.close() page.tbody.close() # add totals page.thead() page.tr(class_='header') page.th('Totals') for i in range(totals.shape[1]): page.th(str(totals[:, i].sum())) page.tr.close() page.thead.close() page.table.close() page.button('Export to CSV', class_='btn btn-default btn-table', onclick="exportTableToCSV('{name}.csv', '{name}')".format( name=id_)) page.div.close() # build trip groups self.trips.sort(key=lambda x: (x[0], x[2] in mask and (mask).index(x[ 2]) or 1000, x[3] is None)) groups = OrderedDict() j = 0 for i in range(len(self.trips)): if i == 0: j = i groups[j] = [] continue t = self.trips[i][0] t2 = self.trips[i - 1][0] if (t - t2) < self.window: groups[j].append(i) else: j = i groups[j] = [] # build trip table page.h1('Trip list') page.div(class_='well') utc = tz.gettz('UTC') if self.ifo in ['H1', 'C1', 'P1']: localzone = tz.gettz('America/Los_Angeles') elif self.ifo in ['L1']: localzone = tz.gettz('America/Chicago') elif self.ifo in ['K1']: localzone = tz.gettz('Asia/Tokyo') else: localzone = tz.gettz('Europe/Berlin') headers = [ 'GPS time', 'UTC time', 'Local time', 'Chamber', 'Trigger', 'Plot', 'Associated' ] rows = [] for id in groups: t, chamber, trigger, plot = self.trips[id] t2 = Time(t, format='gps', scale='utc') tlocal = Time( t2.datetime.replace(tzinfo=utc).astimezone(localzone), format='datetime', scale='utc') rows.append([t, t2.iso, tlocal.iso, chamber, trigger]) if plot: rows[-1].append( markup.oneliner.a('[Click here]', href=plot.href, class_='fancybox plot', **{'data-fancybox-group': '1'})) else: rows[-1].append('-') assoc = [] for id2 in groups[id]: t2, chamber2, trigger2, plot2 = self.trips[id2] dt = t2 - t tag = '%s %s (+%.2fs)' % (chamber2, trigger2, dt) if plot2: assoc.append( markup.oneliner.a(tag, href=plot2.href, class_='fancybox plot', **{'data-fancybox-group': '1'})) else: assoc.append(tag) if assoc: rows[-1].append('<br>'.join(assoc)) else: rows[-1].append('-') page.add( str( html.table( headers, rows, caption= ('List of %s watch-dog trips in interval [%d .. %d) - ' 'trips are considered \'associated\' if they fall within ' '%s seconds of each other.' % (chambertype, self.start, self.end, self.window))))) wdp = [] for i, p in enumerate(self.plots): if 'WATCHDOG_TRIP' in p.href: wdp.append(i) for idx in wdp[::-1]: self.plots.pop(idx) # write trips to data file tripfile = os.path.join(self.path, 'trips.dat') with open(tripfile, 'w') as f: for id in groups: t, chamber, cause, _ = self.trips[id] if cause in hepimask: stage = 'HEPI' elif self.chambers == HAMs: stage = 'ISI' elif cause in isichannels[0].bits: stage = 'ISI1' else: stage = 'ISI2' cause = cause.replace(' ', '_') print(t, chamber, stage, cause, file=f) page.p() page.add('The list of trips can be downloaded ') page.a('here.', href=tripfile, alt=os.path.basename(tripfile), title='Trip data') page.p.close() page.div.close() # write to file idx = self.states.index(state) with open(self.frames[idx], 'w') as fobj: fobj.write(str(page)) return self.frames[idx]
def write_state_html(self, state): """Write the '#main' HTML content for this tab. For now, this function just links all the plots in a 2-column format. """ page = markup.page() # link data if self.subplots: page.hr(class_='row-divider') page.h1('Sub-plots') layout = get_mode() == Mode.week and [7] or [4] plist = [p for p in self.subplots if p.state in [state, None]] page.add(str(self.scaffold_plots(plots=plist, state=state, layout=layout))) page.hr(class_='row-divider') page.div(class_='row') page.div(class_='col-md-12') channels = sorted( (c2 for c in self.get_channels( 'timeseries', 'statevector', 'spectrum', 'spectrogram', 'odc', new=False) for c2 in split_channel_combination(c)), key=str, ) if len(channels): page.h1('Channel information') headers = ['Channel', 'Type', 'Frametype', 'Sample rate', 'Units'] data = [] for channel in channels: # format CIS url and type if channel.frametype: ftype = '<samp>%s</samp>' % channel.frametype else: ftype = 'Unknown' for desc, regex in FRAMETYPE_REGEX.items(): if regex.match(str(channel.frametype)): ftype += ' <small>[%s]</small>' % desc break if re.search(r'\.[a-z]+\Z', channel.name): name, ctype = channel.name.rsplit('.', 1) c2 = get_channel(name) ctype = ctype in ['rms'] and ctype.upper() or ctype.title() else: c2 = channel ctype = 'Raw' c = '<samp>%s</samp>' % str(channel) if c2.url: link = markup.oneliner.a(c, href=c2.url, target='_blank') else: link = c # format sameple rate if channel.sample_rate is None: rate = 'Unknown' elif isclose(channel.sample_rate.value, 1/60.): rate = '1/60 %s' % channel.sample_rate.unit elif channel.sample_rate.value.is_integer(): rate = '{0}{1:s}'.format(int(channel.sample_rate.value), channel.sample_rate._unitstr) else: rate = str(channel.sample_rate) # format unit if hasattr(channel, 'bits'): unit = '-' else: unit = str(channel.unit) if channel.unit else 'Unknown' data.append([link, ctype, ftype, rate, unit]) page.add(str(gwhtml.table( headers, data, id='channel-information', caption="Channels used to generate data on this page"))) allflags = sorted(set([ (f, p) for plot in filter( lambda p: p.data == 'segments' and p.type != 'guardian', self.plots) for (f, p) in plot.padding.items()]), key=lambda x: x[0]) if len(allflags): re_int_decimal = re.compile(r'\.00(?=(\s|\%))') page.h1('Segment information') # make summary table headers = ['Name', 'Defined duration [s]', 'Active duration [s]', 'Padding', 'Description'] data = [] pc = float(abs(self.span) / 100.) if pc.is_integer(): pc = int(pc) for flag, padding in allflags: if padding == (0, 0): padding = None flag = get_segments(flag, [self.span], query=False, padding={flag: padding}) try: valid = '%.2f (%.2f%%)' % (abs(flag.known), abs(flag.known) / pc) except ZeroDivisionError: valid = '0 (0%)' active = '0 (0%)' else: active = '%.2f (%.2f%%)' % (abs(flag.active), abs(flag.active) / pc) valid = re_int_decimal.sub('', valid) active = re_int_decimal.sub('', active) data.append(['<samp>%s</samp>' % flag.name, valid, active, padding and str(padding) or '-', flag.description or '']) page.add(str(gwhtml.table( headers, data, id='segment-information', caption="The following flags were used in " "the above data. This list does not include state " "information or combinations of flags. Percentages " "are calculated relative to the total duration of " "%s seconds." % (pc * 100)))) # print segment lists page.div(class_='panel-group', id="accordion") for i, (flag, padding) in enumerate(allflags): flag = get_segments(flag, [self.span], query=False, padding={flag: padding}) page.div(class_='panel well panel-primary') page.div(class_='panel-heading') page.a(href='#flag%d' % i, **{'data-toggle': 'collapse', 'data-parent': '#accordion'}) page.h4('<samp>%s</samp>' % flag.name, class_='panel-title') page.a.close() page.div.close() page.div(id_='flag%d' % i, class_='panel-collapse collapse') page.div(class_='panel-body') # write segment summary page.p('This flag was defined and had a known state during ' 'the following segments:') page.add(str(self.print_segments(flag.known))) # write segment table page.p('This flag was active during the following segments:') page.add(str(self.print_segments(flag.active))) page.div.close() page.div.close() page.div.close() page.div.close() # write state information page.add(str(self.write_state_information(state))) page.div.close() page.div.close() return super(DataTab, self).write_state_html(state, plots=True, pre=self.foreword, post=page)
def write_state_html(self, state): """Write the '#main' HTML content for this tab. For now, this function just links all the plots in a 2-column format. """ page = markup.page() # link data if self.subplots: page.hr(class_='row-divider') page.h1('Sub-plots') layout = get_mode() == Mode.week and [7] or [4] plist = [p for p in self.subplots if p.state in [state, None]] page.add( str( self.scaffold_plots(plots=plist, state=state, layout=layout))) page.hr(class_='row-divider') page.div(class_='row') page.div(class_='col-md-12') channels = sorted( (c2 for c in self.get_channels('timeseries', 'statevector', 'spectrum', 'spectrogram', 'odc', new=False) for c2 in split_channel_combination(c)), key=str, ) if len(channels): page.h1('Channel information') headers = ['Channel', 'Type', 'Frametype', 'Sample rate', 'Units'] data = [] for channel in channels: # format CIS url and type if channel.frametype: ftype = '<samp>%s</samp>' % channel.frametype else: ftype = 'Unknown' for desc, regex in FRAMETYPE_REGEX.items(): if regex.match(str(channel.frametype)): ftype += ' <small>[%s]</small>' % desc break if re.search(r'\.[a-z]+\Z', channel.name): name, ctype = channel.name.rsplit('.', 1) c2 = get_channel(name) ctype = ctype in ['rms'] and ctype.upper() or ctype.title() else: c2 = channel ctype = 'Raw' c = '<samp>%s</samp>' % str(channel) if c2.url: link = markup.oneliner.a(c, href=c2.url, target='_blank') else: link = c # format sameple rate if channel.sample_rate is None: rate = 'Unknown' elif isclose(channel.sample_rate.value, 1 / 60.): rate = '1/60 %s' % channel.sample_rate.unit elif channel.sample_rate.value.is_integer(): rate = '{0}{1:s}'.format(int(channel.sample_rate.value), channel.sample_rate._unitstr) else: rate = str(channel.sample_rate) # format unit if hasattr(channel, 'bits'): unit = '-' else: unit = str(channel.unit) if channel.unit else 'Unknown' data.append([link, ctype, ftype, rate, unit]) page.add( str( gwhtml.table( headers, data, id='channel-information', caption="Channels used to generate data on this page")) ) allflags = sorted(set([(f, p) for plot in filter( lambda p: p.data == 'segments' and p.type != 'guardian', self.plots) for (f, p) in plot.padding.items()]), key=lambda x: x[0]) if len(allflags): re_int_decimal = re.compile(r'\.00(?=(\s|\%))') page.h1('Segment information') # make summary table headers = [ 'Name', 'Defined duration [s]', 'Active duration [s]', 'Padding', 'Description' ] data = [] pc = float(abs(self.span) / 100.) if pc.is_integer(): pc = int(pc) for flag, padding in allflags: if padding == (0, 0): padding = None flag = get_segments(flag, [self.span], query=False, padding={flag: padding}) try: valid = '%.2f (%.2f%%)' % (abs( flag.known), abs(flag.known) / pc) except ZeroDivisionError: valid = '0 (0%)' active = '0 (0%)' else: active = '%.2f (%.2f%%)' % (abs( flag.active), abs(flag.active) / pc) valid = re_int_decimal.sub('', valid) active = re_int_decimal.sub('', active) data.append([ '<samp>%s</samp>' % flag.name, valid, active, padding and str(padding) or '-', flag.description or '' ]) page.add( str( gwhtml.table( headers, data, id='segment-information', caption="The following flags were used in " "the above data. This list does not include state " "information or combinations of flags. Percentages " "are calculated relative to the total duration of " "%s seconds." % (pc * 100)))) # print segment lists page.div(class_='panel-group', id="accordion") for i, (flag, padding) in enumerate(allflags): flag = get_segments(flag, [self.span], query=False, padding={flag: padding}) page.div(class_='panel well panel-primary') page.div(class_='panel-heading') page.a(href='#flag%d' % i, **{ 'data-toggle': 'collapse', 'data-parent': '#accordion' }) page.h4('<samp>%s</samp>' % flag.name, class_='panel-title') page.a.close() page.div.close() page.div(id_='flag%d' % i, class_='panel-collapse collapse') page.div(class_='panel-body') # write segment summary page.p('This flag was defined and had a known state during ' 'the following segments:') page.add(str(self.print_segments(flag.known))) # write segment table page.p('This flag was active during the following segments:') page.add(str(self.print_segments(flag.active))) page.div.close() page.div.close() page.div.close() page.div.close() # write state information page.add(str(self.write_state_information(state))) page.div.close() page.div.close() return super(DataTab, self).write_state_html(state, plots=True, pre=self.foreword, post=page)
def write_state_html(self, state): """Write the content of inner HTML for the given state """ def format_result(res): fmt = '%d' if ( res.value < 0.01 or (res.unit == Unit('%') and res.value > 99.99)) else '%.2f' return ''.join([fmt % res.value, str(res.unit)]) def add_config_entry(page, title, entry): page.tr() page.th(title) page.td(entry) page.tr.close() # write results table performance = [( str(m), format_result(r), m.description.split('\n')[0], ) for (m, r) in self.results[state].items()] pre = markup.page() pre.p(self.foreword) pre.h4('Flag performance summary', class_='mt-4') pre.add( str( gwhtml.table(['Metric', 'Result', 'Description'], performance, id=self.title))) pre.h2('Figures of Merit', class_='mt-4 mb-2') # write configuration table post = markup.page() post.h2('Analysis configuration', class_='mt-4') post.div() post.table(class_='table table-sm table-hover') add_config_entry(post, 'Flags', '<br>'.join(list(map(str, self.flags)))) if len(self.flags) > 1 and self.intersection: add_config_entry(post, 'Flag combination', 'Intersection (logical AND)') elif len(self.flags) > 1: add_config_entry(post, 'Flag combination', 'Union (logical OR)') add_config_entry( post, 'Analysis start time', '%s (%s)' % (str(Time(float(self.start), format='gps', scale='utc').iso), self.start)) add_config_entry( post, 'Analysis end time', '%s (%s)' % (str(Time(float(self.end), format='gps', scale='utc').iso), self.end)) add_config_entry(post, 'Event trigger channel', str(self.channel)) add_config_entry(post, 'Event trigger generator', str(self.etg)) post.table.close() post.div.close() post.h2('Segment information', class_='mt-4') post.div(class_='mt-2', id="accordion") for i, flag in enumerate([self.metaflag] + self.flags): flag = get_segments(flag, state.active, query=False, padding=self.padding).copy() post.div(class_='card border-info mb-1 shadow-sm') post.div(class_='card-header text-white bg-info') if i == 0: title = self.intersection and 'Intersection' or 'Union' elif self.labels[i - 1] != str(flag): title = '%s (%s)' % (flag.name, self.labels[i - 1]) else: title = flag.name post.a(title, class_='card-link cis-link collapsed', href='#flag%d' % i, **{ 'data-toggle': 'collapse', 'aria-expanded': 'false' }) post.div.close() # card-header post.div(id_='flag%d' % i, class_='collapse', **{'data-parent': '#accordion'}) post.div(class_='card-body') # write segment summary post.p('This flag was defined and had a known state during ' 'the following segments:') post.add(self.print_segments(flag.known)) # write segment table post.p('This flag was active during the following segments:') post.add(self.print_segments(flag.active)) post.div.close() # card-body post.div.close() # collapse post.div.close() # card post.div.close() # then write standard data tab return super(get_tab('default'), self).write_state_html(state, plots=True, pre=pre, post=post)
def write_state_html(self, state): """Write the HTML for the given state of this `GuardianTab` """ page = self.scaffold_plots(state=state) page.div(class_='row') page.div(class_='col-md-12') page.h2('%s state transitions' % self.node, class_='mt-4 mb-4') page.add( html.alert( # add dismissable alert 'For all of the following data, "Unknown" simply labels any ' 'state in this node that was not chosen for display, and does ' 'not mean that the state was unrecognised by the Guardian ' 'system. Transitions from an "Unkown" state are not listed in ' 'the table below, but are included in the totals.', context=self.ifo.lower())) # draw table id_ = '{}-state-transitions'.format(self.ifo.lower()) page.table(class_='table table-sm table-hover transitions mt-2', id_=id_) page.caption('Transitions into each state (row) from each other ' 'state (column). Only those states named in the ' 'configuration are shown, but the \'Total\' includes ' 'transitions from any and all states. A dash ' '(\'—\') indicates no transitions from ' 'the given state.') page.thead() page.tr() for th in ['State'] + list(self.grdstates.values()) + ['Total']: page.th(th) page.tr.close() page.thead.close() page.tbody() for i, bit in enumerate(self.transstates): page.tr() name = self.grdstates[bit].strip('*') page.th(name) for j, bit2 in enumerate(self.grdstates): if i == j: page.td('—', class_='ignore') continue count = len([t for t in self.transitions[bit] if t[1] == bit2]) if count: page.td(str(count)) else: page.td('—') page.th(str(len(self.transitions[bit]))) page.tr.close() page.tbody.close() page.table.close() page.button('Export to CSV', class_='btn btn-outline-secondary btn-table mt-2', **{ 'data-table-id': id_, 'data-filename': '%s.csv' % id_ }) page.div.close() # col-md-12 page.div.close() # row # summarise each state page.div(class_='row') page.div(class_='col-md-12') page.h2('State details', class_='mt-4 mb-2') page.div(id='accordion') for i, bit in enumerate(self.grdstates): name = self.grdstates[bit].strip('*') page.div(class_='card border-info mb-1 shadow-sm', id=str(bit)) # heading page.div(class_='card-header text-white bg-info') page.a('%s [%d]' % (name, bit), href='#collapse-%d' % bit, class_='card-link cis-link collapsed', **{ 'data-toggle': 'collapse', 'aria-expandedt': 'false' }) page.div.close() # card-header # body page.div(id='collapse-%d' % bit, class_='collapse', **{'data-parent': '#accordion'}) page.div(class_='card-body') # print transitions headers = [ 'Transition GPS time', 'UTC time', 'Local time', 'Transition from', 'Exited to' ] data = [] if self.ifo in ['H1', 'C1', 'P1']: localzone = tz.gettz('America/Los_Angeles') elif self.ifo in ['L1']: localzone = tz.gettz('America/Chicago') elif self.ifo in ['K1']: localzone = tz.gettz('Asia/Tokyo') else: localzone = tz.gettz('Europe/Berlin') for t, from_, to_ in self.transitions[bit]: t2 = Time(t, format='gps', scale='utc') tlocal = Time( t2.datetime.replace(tzinfo=UTC).astimezone(localzone), format='datetime', scale='utc') data.append( (t, t2.iso, tlocal.iso, '%s [%d]' % (self.grdstates.get(from_, 'Unknown'), from_), '%s [%d]' % (self.grdstates.get(to_, 'Unknown'), to_))) page.add( str( html.table(headers, data, id='%s-guardian-%s' % (self.ifo.lower(), str(bit)), caption="Transitions for %s %r state" % (self.node, name)))) # print segments flag = get_segments(self.segmenttag % name, state.active, query=False).copy() livetime = abs(flag.active) try: duty = abs(flag.active) / float(abs(flag.known)) * 100. except ZeroDivisionError: duty = 0 page.p('This state was active for %.2f seconds (%.2f%%) during ' 'the following segments:' % (livetime, duty)) page.add(str(self.print_segments(flag))) page.div.close() # card-body page.div.close() # collapse page.div.close() # card page.div.close() # accordion page.div.close() # col-md-12 page.div.close() # row return super(DataTab, self).write_state_html(state, plots=False, pre=page)
def write_state_html(self, state): """Write the HTML for the given state of this `GuardianTab` """ page = self.scaffold_plots(state=state) page.div(class_='row') page.div(class_='col-md-12') # get segment data groups = type(self.modes)( (idx, name) for idx, name in self.modes.items() if idx % 10 == 0) modes = type(self.modes)((idx, name) for idx, name in self.modes.items() if not name.startswith('*')) headers = ['Index', 'Name', 'Active seconds', 'Hours', '%'] prefix = self.ifo.lower() for flags, title, id in zip( [groups, modes], ['Top-level mode information', 'Detailed mode information'], ['%s-top-level-mode' % prefix, '%s-detailed-mode' % prefix]): page.h1(title, class_='mt-4') data = [] pc = float(abs(state.active) / 100.) tots = 0 toth = 0 totp = 0 for idx, name in flags.items(): flag = get_segments(self.segmenttag % idx, state.active, query=False).copy() actives = abs(flag.active) activeh = actives / 3600. try: activep = actives / pc except ZeroDivisionError: activep = 0 tots += actives toth += activeh totp += activep data.append([ str(idx), name.strip('*'), '%.1f' % actives, '%.1f' % activeh, '%.1f' % activep ]) data.append([ '<strong>%s</strong>' % x for x in ['', 'Total:', '%.1f' % tots, '%.1f' % toth, '%.1f' % totp] ]) page.add( str( html.table( headers, data, id=id, caption="%s observatory mode statistics as recorded in " "<samp>%s</samp>" % (title.split()[0], self.channel)))) return super(ParentTab, self).write_state_html(state, plots=False, pre=page)
def write_state_html(self, state, pre=None): """Write the '#main' HTML content for this `EventTriggerTab`. """ page = markup.page() if self.error.get(state, None): level, message = self.error[state] # no segments, print warning page.add( html.alert(( message, "If you believe this to be an error, please contact %s." % markup.oneliner.a('the DetChar group', class_='alert-link', href='mailto:[email protected]'), ), context=level, dismiss=False)) else: # otherwise, carry on... if pre is not None: page.add(str(pre)) elif self.foreword: page.add(str(self.foreword)) page.add(str(self.scaffold_plots(state=state))) # link full results if self.url: page.hr(class_='row-divider') page.div(class_='btn-group') page.a('Click here for the full %s results' % self.name, href=self.url, rel='external', target='_blank', class_='btn btn-info btn-xl') page.div.close() page.hr(class_='row-divider') if self.loudest: # get triggers table = get_triggers(self.channel, self.plots[0].etg, state, query=False) if self.filterstr is not None: table = table.filter(self.filterstr) tcol = get_time_column(table, self.etg) # set table headers headers = list(self.loudest['labels']) + ['LDVW Action'] columns = list(self.loudest['columns']) if tcol in columns: headers.insert(1, 'UTC time') date = True else: date = False # loop over rank columns for rank in self.loudest['rank']: try: rankstr = self.loudest['labels'][columns.index(rank)] except ValueError: rankstr = repr(rank) page.h2('Loudest events by %s' % rankstr, class_='mt-4 mb-4') rank = table[rank].argsort()[::-1] loudest = [] i = 0 dt = self.loudest['dt'] while len(loudest) < self.loudest['N'] and i < rank.size: e = table[rank[i]] t = e[tcol] if i == 0 or all( abs((t - e2[tcol])) >= dt for e2 in loudest): loudest.append(e) i += 1 data = [] for row in loudest: data.append([]) for column in columns: data[-1].append('%.3f' % float(row[column])) if date: data[-1].insert( 1, from_gps(row[tcol]).strftime( '%B %d %Y %H:%M:%S.%f')[:-3]) data[-1].append(ldvw_qscan(self.channel, data[-1][0])) # construct table times = tuple(row[0] for row in data) launch = ldvw_qscan(self.channel, times) page.add( str( html.table( headers, data, id='%s-loudest-table' % self.etg, caption=( "%d loudest <samp>%s</samp> (%s) events " "by %s with minimum %ss separation. %s" % (self.loudest['N'], self.channel, self.etg, rankstr, self.loudest['dt'], str(launch)))))) if self.subplots: page.h1('Sub-plots', class_='mt-4') layout = get_mode() == Mode.week and [7] or [4] plist = [p for p in self.subplots if p.state in [state, None]] page.add( str( self.scaffold_plots(plots=plist, state=state, layout=layout))) # link full results if self.url: page.hr(class_='row-divider') page.div(class_='btn-group') page.a('Click here for the full %s results' % self.name, href=self.url, rel='external', target='_blank', class_='btn btn-info btn-xl') page.div.close() page.hr(class_='row-divider') # write state information page.add(str(self.write_state_information(state))) # write to file idx = self.states.index(state) with open(self.frames[idx], 'w') as fobj: fobj.write(str(page)) return self.frames[idx]
def write_state_html(self, state, pre=None): """Write the '#main' HTML content for this `EventTriggerTab`. """ page = markup.page() if self.error.get(state, None): level, message = self.error[state] # no segments, print warning page.div(class_='alert alert-%s' % level) page.p(message) page.p("If you believe this to be an error, please contact %s." % markup.oneliner.a('the DetChar group', class_='alert-link', href='mailto:[email protected]')) page.div.close() else: # otherwise, carry on... if pre is not None: page.add(str(pre)) elif self.foreword: page.add(str(self.foreword)) page.add(str(self.scaffold_plots(state=state))) # link full results if self.url: page.hr(class_='row-divider') page.div(class_='btn-group') page.a('Click here for the full %s results' % self.name, href=self.url, rel='external', target='_blank', class_='btn btn-default btn-info btn-xl') page.div.close() page.hr(class_='row-divider') if self.loudest: # get triggers table = get_triggers(self.channel, self.plots[0].etg, state, query=False) if self.filterstr is not None: table = table.filter(self.filterstr) tcol = get_time_column(table, self.etg) # set table headers headers = list(self.loudest['labels']) columns = list(self.loudest['columns']) if tcol in columns: headers.insert(1, 'UTC time') date = True else: date = False # loop over rank columns for rank in self.loudest['rank']: try: rankstr = self.loudest['labels'][columns.index(rank)] except ValueError: rankstr = repr(rank) page.h2('Loudest events by %s' % rankstr) rank = table[rank].argsort()[::-1] loudest = [] i = 0 dt = self.loudest['dt'] while len(loudest) < self.loudest['N'] and i < rank.size: e = table[rank[i]] t = e[tcol] if i == 0 or all( abs((t - e2[tcol])) >= dt for e2 in loudest): loudest.append(e) i += 1 data = [] for row in loudest: data.append([]) for column in columns: data[-1].append( '%.3f' % float(row[column])) if date: data[-1].insert( 1, from_gps(row[tcol]).strftime( '%B %d %Y %H:%M:%S.%f')[:-3]) page.add(str(html.table( headers, data, id='%s-loudest-table' % self.etg, caption=("%d loudest <samp>%s</samp> (%s) events " "by %s with minimum %ss separation" % (self.loudest['N'], self.channel, self.etg, rankstr, self.loudest['dt']))))) if self.subplots: page.hr(class_='row-divider') page.h1('Sub-plots') layout = get_mode() == Mode.week and [7] or [4] plist = [p for p in self.subplots if p.state in [state, None]] page.add(str(self.scaffold_plots(plots=plist, state=state, layout=layout))) # link full results if self.url: page.hr(class_='row-divider') page.div(class_='btn-group') page.a('Click here for the full %s results' % self.name, href=self.url, rel='external', target='_blank', class_='btn btn-default btn-info btn-xl') page.div.close() page.hr(class_='row-divider') # write state information page.add(str(self.write_state_information(state))) # write to file idx = self.states.index(state) with open(self.frames[idx], 'w') as fobj: fobj.write(str(page)) return self.frames[idx]
def write_state_html(self, state): """Build HTML summary of watchdog trips """ # find one example of each channel, and get the bits hepichannel = get_channel(HEPI_LATCH_CHANNEL % (self.ifo, self.chambers[1])) hepimask = hepichannel.bits + ['HEPI Unknown'] if self.chambers == HAMs: isichannels = [get_channel(HAM_ISI_LATCH_CHANNEL % (self.ifo, self.chambers[0]))] isimask = isichannels[0].bits + ['ISI Unknown'] else: isichannels = [get_channel(BSC_ST1_LATCH_CHANNEL % (self.ifo, self.chambers[0])), get_channel(BSC_ST2_LATCH_CHANNEL % (self.ifo, self.chambers[0]))] isimask = (isichannels[0].bits + ['ISI ST1 Unknown'] + isichannels[1].bits + ['ISI ST2 Unknown']) mask = hepimask + isimask # count trips count = {} for _, chamber, trigger, _ in self.trips: key = (chamber, trigger) try: count[key] += 1 except KeyError: count[key] = 1 page = markup.page() # build summary table page.div(class_='well') chambertype = self.chambers[0][:-1] id_ = '{}-{}'.format(self.ifo.lower(), chambertype.lower()) page.table( class_='table table-condensed table-hover watchdog', id_=id_) page.caption("Number of watch-dog trips per %s chamber (column) and " "trigger (row)" % (chambertype)) page.thead() # add headers page.tr(class_='header') for th in ['WD'] + self.chambers + ['Sub-total']: page.th(th) page.tr.close() page.thead.close() # add rows page.tbody() totals = numpy.zeros((len(mask), len(self.chambers) + 1), dtype=int) rows = [] for i, bit in enumerate(mask): class_ = [] if (i == len(hepimask) or i == len(hepimask + isichannels[0].bits)): class_.append('tdiv') if re_no_count.match(bit): class_.append('ignore') if class_: page.tr(class_=' '.join(class_)) else: page.tr() page.th(bit) for j, chamber in enumerate(self.chambers): try: c = count[(chamber, bit)] except KeyError: c = 0 pass page.td(c or '-') # exclude IOP from total if not re_no_count.match(bit): totals[i][j] = c # add row total totals[i][-1] = totals[i].sum() page.th(str(totals[i][-1])) page.tr.close() page.tbody.close() # add totals page.thead() page.tr(class_='header') page.th('Totals') for i in range(totals.shape[1]): page.th(str(totals[:, i].sum())) page.tr.close() page.thead.close() page.table.close() page.button( 'Export to CSV', class_='btn btn-default btn-table', onclick="exportTableToCSV('{name}.csv', '{name}')".format( name=id_)) page.div.close() # build trip groups self.trips.sort( key=lambda x: (x[0], x[2] in mask and (mask).index(x[2]) or 1000, x[3] is None)) groups = OrderedDict() j = 0 for i in range(len(self.trips)): if i == 0: j = i groups[j] = [] continue t = self.trips[i][0] t2 = self.trips[i-1][0] if (t - t2) < self.window: groups[j].append(i) else: j = i groups[j] = [] # build trip table page.h1('Trip list') page.div(class_='well') utc = tz.gettz('UTC') if self.ifo in ['H1', 'C1', 'P1']: localzone = tz.gettz('America/Los_Angeles') elif self.ifo in ['L1']: localzone = tz.gettz('America/Chicago') else: localzone = tz.gettz('Europe/Berlin') headers = ['GPS time', 'UTC time', 'Local time', 'Chamber', 'Trigger', 'Plot', 'Associated'] rows = [] for id in groups: t, chamber, trigger, plot = self.trips[id] t2 = Time(t, format='gps', scale='utc') tlocal = Time( t2.datetime.replace(tzinfo=utc).astimezone(localzone), format='datetime', scale='utc') rows.append([t, t2.iso, tlocal.iso, chamber, trigger]) if plot: rows[-1].append(markup.oneliner.a( '[Click here]', href=plot.href, class_='fancybox plot', **{'data-fancybox-group': '1'})) else: rows[-1].append('-') assoc = [] for id2 in groups[id]: t2, chamber2, trigger2, plot2 = self.trips[id2] dt = t2 - t tag = '%s %s (+%.2fs)' % (chamber2, trigger2, dt) if plot2: assoc.append(markup.oneliner.a( tag, href=plot2.href, class_='fancybox plot', **{'data-fancybox-group': '1'} )) else: assoc.append(tag) if assoc: rows[-1].append('<br>'.join(assoc)) else: rows[-1].append('-') page.add(str(gwhtml.table( headers, rows, caption=('List of %s watch-dog trips in interval [%d .. %d) - ' 'trips are considered \'associated\' if they fall within ' '%s seconds of each other.' % (chambertype, self.start, self.end, self.window))))) wdp = [] for i, p in enumerate(self.plots): if 'WATCHDOG_TRIP' in p.href: wdp.append(i) for idx in wdp[::-1]: self.plots.pop(idx) # write trips to data file tripfile = os.path.join(self.path, 'trips.dat') with open(tripfile, 'w') as f: for id in groups: t, chamber, cause, _ = self.trips[id] if cause in hepimask: stage = 'HEPI' elif self.chambers == HAMs: stage = 'ISI' elif cause in isichannels[0].bits: stage = 'ISI1' else: stage = 'ISI2' cause = cause.replace(' ', '_') print(t, chamber, stage, cause, file=f) page.p() page.add('The list of trips can be downloaded ') page.a('here.', href=tripfile, alt=os.path.basename(tripfile), title='Trip data') page.p.close() page.div.close() # write to file idx = self.states.index(state) with open(self.frames[idx], 'w') as fobj: fobj.write(str(page)) return self.frames[idx]
def write_state_html(self, state): # write results table performance = [(str(m), '%.2f %s' % (r.value, r.unit), m.description.split('\n')[0]) for (m, r) in self.results[state].iteritems()] pre = markup.page() pre.div(class_='scaffold well') pre.strong('Flag performance summary') pre.add(str(gwhtml.table(['Metric', 'Result', 'Description'], performance))) pre.div.close() pre.h2('Figures of Merit') # write configuration table post = markup.page() def add_config_entry(title, entry): post.tr() post.th(title) post.td(entry) post.tr.close() post.h2('Analysis configuration') post.div() post.table(class_='table table-condensed table-hover') add_config_entry('Flags', '<br>'.join(map(str, self.flags))) if len(self.flags) > 1 and self.intersection: add_config_entry('Flag combination', 'Intersection (logical AND)') elif len(self.flags) > 1: add_config_entry('Flag combination', 'Union (logical OR)') add_config_entry('Analysis start time', '%s (%s)' % ( str(Time(float(self.start), format='gps', scale='utc').iso), self.start)) add_config_entry('Analysis end time', '%s (%s)' % ( str(Time(float(self.end), format='gps', scale='utc').iso), self.end)) add_config_entry('Event trigger channel', str(self.channel)) add_config_entry('Event trigger generator', str(self.etg)) post.table.close() post.div.close() post.h2('Segment information') post.div(class_='panel-group', id="accordion") for i, flag in enumerate([self.metaflag] + self.flags): flag = get_segments(flag, state.active, query=False, padding=self.padding).copy() post.div(class_='panel well panel-primary') post.div(class_='panel-heading') post.a(href='#flag%d' % i, **{'data-toggle': 'collapse', 'data-parent': '#accordion'}) if i == 0: post.h4(self.intersection and 'Intersection' or 'Union', class_='panel-title') elif self.labels[i-1] != str(flag): post.h4('%s (%s)' % (flag.name, self.labels[i-1]), class_='panel-title') else: post.h4(flag.name, class_='panel-title') post.a.close() post.div.close() post.div(id_='flag%d' % i, class_='panel-collapse collapse') post.div(class_='panel-body') # write segment summary post.p('This flag was defined and had a known state during ' 'the following segments:') post.add(self.print_segments(flag.known)) # write segment table post.p('This flag was active during the following segments:') post.add(self.print_segments(flag.active)) post.div.close() post.div.close() post.div.close() post.div.close() # then write standard data tab return super(get_tab('default'), self).write_state_html( state, plots=True, pre=pre, post=post)