def loudest_event(segments, before, after=None): """Percentage reduction in the amplitude of the loudest event by %s Parameters ---------- segments : `DataQualityFlag`, `~glue.segments.segmentlist` the set of segments to test before : `~glue.ligolw.table.Table` the event trigger table to test after : `~glue.ligolw.table.Table`, optional the remaining triggers after vetoes. This is calculated is not given Returns ------ reduction : `float` the percentage reduction in the amplitude of the loudest event """ if after is None: after = before.veto(segments.active) try: brank = get_table_column(before, column).max() except ValueError: # no triggers to start with return 0 try: arank = get_table_column(after, column).max() except ValueError: # no triggers after veto return 100 return (brank - arank) / brank * 100
def test_get_table_row_methods(self): testfile = SnglBurstTableTestCase.TEST_XML_FILE table = GWRecArray.read(SnglBurstTableTestCase.TEST_XML_FILE, format='sngl_burst') # test simple column snr = get_table_column(table, 'snr') nptest.assert_array_equal(snr, table['snr']) # test 'time' special-case time = get_table_column(table, 'time') nptest.assert_array_equal( time, table['peak_time'] + table['peak_time_ns'] * 1e-9) # test row row = table[0] self.assertEqual(get_row_value(row, 'snr'), row['snr']) self.assertEqual(get_row_value(row, 'time'), row['peak_time'] + row['peak_time_ns'] * 1e-9)
def get_times(table, etg): # allow user to have selected the time column if table.meta.get('timecolumn'): return table[table.meta['timecolumn']] # otherwise search for it try: return table['time'] except KeyError: # shortcut pycbc if etg == 'pycbc_live': return table['end_time'] # guess from mapped LIGO_LW table try: TableClass = get_etg_table(etg) except KeyError: pass else: tablename = TableClass.TableName(TableClass.tableName) if tablename.endswith('_burst'): return table['peak_time'] + table['peak_time_ns'] * 1e-9 if tablename.endswith('_inspiral'): return table['end_time'] + table['end_time_ns'] * 1e-9 if tablename.endswith('_ringdown'): return table['start_time'] + table['start_time_ns'] * 1e-9 # use gwpy method (not guaranteed to work) return get_table_column(table, 'time').astype(float)
def get_reduced_table(table, column, op, threshold): """Return a masked version of a column with an operator and threshold """ data = get_table_column(table, column) mask = op(data, threshold) new = table.copy() new.extend(t for t, m in izip(table, mask) if m) return new
def use_percentage(segments, before, after=None): """The decimal fraction of segments that are used to veto triggers """ times = get_table_column(before, 'time').astype(float) used = 0 for seg in segments.active: if numpy.logical_and(times >= float(seg[0]), times < float(seg[1])).any(): used += 1 try: return used / len(segments.active) * 100 except ZeroDivisionError: return 0.
def get_times(table, etg): if etg == 'pycbc_live': return table['end_time'] # guess from mapped LIGO_LW table try: TableClass = get_etg_table(etg) except KeyError: pass else: tablename = strip_table_name(TableClass.tableName) if tablename.endswith('_burst'): return table['peak_time'] + table['peak_time_ns'] * 1e-9 if tablename.endswith('_inspiral'): return table['end_time'] + table['end_time_ns'] * 1e-9 if tablename.endswith('_ringdown'): return table['start_time'] + table['start_time_ns'] * 1e-9 # use gwpy method (not guaranteed to work) return get_table_column(table, 'time').astype(float)
def add_loudest(self, table, rank, x, y, *columns, **kwargs): """Display the loudest event according to some rank. The loudest event is displayed as a gold star at its position given by the values in columns ``x``, and ``y``, and those values are displayed in a text box. Parameters ---------- table : `EventTable` event table in which to find the loudest event rank : `str` name of column to use for ranking x : `str` name of column to display on the X-axis y : `str` name of column to display on the Y-axis color : `str`, optional name of column by which to colour the data **kwargs any other arguments applicable to :meth:`~matplotlib.axes.Axes.text` Returns ------- out : `tuple` (`collection`, `text`) tuple of items added to the `Axes` """ ylim = self.get_ylim() try: idx = table[rank].argmax() except TypeError: if hasattr(table, 'tableName'): # glue.ligolw.table.Table from gwpy.table.utils import (get_table_column, get_row_value) warnings.warn('EventTableAxes.add_loudest will stop ' 'supporting glue.ligolw.table.Table objects ' 'before the 1.0 release of GWpy, please move ' 'to using the gwpy.table.EventTable') use_ligolw = True idx = get_table_column(table, rank).argmax() else: raise else: use_ligolw = False row = table[idx] disp = "Loudest event:" columns = [x, y, rank] + list(columns) scat = [] for i, column in enumerate(columns): if not column or column in columns[:i]: continue if i: disp += ',' try: val = row[column] except TypeError: if use_ligolw: # DEPRECATED - remove before 1.0 release val = get_row_value(row, column) else: raise if i < 2: scat.append([float(val)]) column = get_column_string(column) if pyplot.rcParams['text.usetex'] and column.endswith('Time'): disp += (r" %s$= %s$" % (column, LIGOTimeGPS(float(val)))) elif pyplot.rcParams['text.usetex']: disp += (r" %s$=$ %s" % (column, float_to_latex(val, '%.3g'))) else: disp += " %s = %.2g" % (column, val) disp = disp.rstrip(',') pos = kwargs.pop('position', [0.5, 1.00]) kwargs.setdefault('transform', self.axes.transAxes) kwargs.setdefault('verticalalignment', 'bottom') kwargs.setdefault('horizontalalignment', 'center') args = pos + [disp] self.scatter(*scat, marker='*', zorder=1000, facecolor='gold', edgecolor='black', s=200) self.text(*args, **kwargs) if self.get_title(): pos = self.title.get_position() self.title.set_position((pos[0], pos[1] + 0.05)) self.set_ylim(*ylim)
def draw(self): """Get data and generate the figure. """ # get histogram parameters (plot, ax) = self.init_plot() # extract histogram arguments histargs = self.parse_plot_kwargs() legendargs = self.parse_legend_kwargs() # add data data = [] livetime = [] for channel in self.channels: try: channel = get_channel(channel) except ValueError: pass if self.state and not self.all_data: valid = self.state.active else: valid = SegmentList([self.span]) if '#' in str(channel) or '@' in str(channel): key = '%s,%s' % (str(channel), self.state and str(self.state) or 'All') else: key = str(channel) table_ = get_triggers(key, self.etg, valid, query=False) livetime.append(float(abs(table_.segments))) data.append(get_table_column(table_, self.column)) # allow channel data to set parameters if hasattr(channel, 'amplitude_range'): self.pargs.setdefault('xlim', channel.amplitude_range) # get range if not 'range' in histargs[0]: for kwset in histargs: kwset['range'] = ax.common_limits(data) # plot for arr, d, kwargs in zip(data, livetime, histargs): weights = kwargs.pop('weights', None) direction = kwargs.get('orientation', 'vertical') if weights is True: try: weights = 1/d except ZeroDivisionError: pass if direction == 'horizontal': self.pargs.setdefault( 'xbound', 1/float(abs(self.span)) * .5) else: self.pargs.setdefault( 'ybound', 1/float(abs(self.span)) * .5) if (kwargs.get('logy', False) or kwargs.get('yscale', 'linear') == 'log'): kwargs.setdefault('bottom', 1e-100) label = kwargs.pop('label', None) if arr.size: ax.hist(arr, label=label, weights=weights, **kwargs) else: ax.plot([], label=label) # tight scale the axes if len(data) and direction == 'vertical' or True: ax.autoscale_view(tight=True, scaley=False) if len(data) and direction == 'horizontal' or False: ax.autoscale_view(tight=True, scalex=False) # customise plot self.apply_parameters(ax, **self.pargs) if len(self.channels) > 1: plot.add_legend(ax=ax, **legendargs) # add extra axes and finalise if not plot.colorbars: plot.add_colorbar(ax=ax, visible=False) return self.finalize()
def _plot_ligolw_tiles(self, table, x, y, width, height, color=None, anchor='center', edgecolors='face', linewidth=0.8, **kwargs): from ..table.utils import (get_table_column, get_row_value) warnings.warn('Plotting LIGO_LW tables has been deprecated and ' 'will likely be removed before the 1.0 release, please ' 'update all codes to use the astropy.table.Table or ' 'gwpy.table.EventTable objects') from ..table.utils import (get_table_column, get_row_value) # get x/y data xdata = get_table_column(table, x) ydata = get_table_column(table, y) wdata = get_table_column(table, width) hdata = get_table_column(table, height) # get color and sort if color: cdata = get_table_column(table, color) zipped = zip(xdata, ydata, wdata, hdata, cdata) zipped.sort(key=lambda row: row[-1]) try: xdata, ydata, wdata, hdata, cdata = map(numpy.asarray, zip(*zipped)) except ValueError: pass # construct vertices if anchor == 'll': verts = [((x, y), (x, y+height), (x+width, y+height), (x+width, y)) for (x, y, width, height) in zip(xdata, ydata, wdata, hdata)] elif anchor == 'lr': verts = [((x-width, y), (x-width, y+height), (x, y+height), (x, y)) for (x, y, width, height) in zip(xdata, ydata, wdata, hdata)] elif anchor == 'ul': verts = [((x, y-height), (x, y), (x+width, y), (x+width, y-height)) for (x, y, width, height) in zip(xdata, ydata, wdata, hdata)] elif anchor == 'ur': verts = [((x-width, y-height), (x-width, y), (x, y), (x, y-height)) for (x, y, width, height) in zip(xdata, ydata, wdata, hdata)] elif anchor == 'center': verts = [((x-width/2., y-height/2.), (x-width/2., y+height/2.), (x+width/2., y+height/2.), (x+width/2., y-height/2.)) for (x, y, width, height) in zip(xdata, ydata, wdata, hdata)] else: raise ValueError("Unrecognised tile anchor '%s'." % anchor) # build collection cmap = kwargs.pop('cmap', pyplot.rcParams['image.cmap']) coll = collections.PolyCollection(verts, edgecolors=edgecolors, linewidth=linewidth, **kwargs) if color: coll.set_array(cdata) coll.set_cmap(cmap) return self.add_collection(coll)
def _plot_ligolw_table(self, table, x, y, color=None, size_by=None, size_by_log=None, size_range=None, **kwargs): """Plot a LIGO_LW-format event `Table` onto these `Axes` Parameters ---------- table : :class:`~glue.ligolw.table.Table` LIGO_LW-format XML event `Table` to display x : `str` name of column to display on the X-axis y : `str` name of column to display on the Y-axis c : `str`, optional name of column by which to colour the data **kwargs any other arguments applicable to :meth:`~matplotlib.axes.Axes.scatter` Returns ------- collection """ from ..table.utils import (get_table_column, get_row_value) warnings.warn('Plotting LIGO_LW tables has been deprecated and ' 'will likely be removed before the 1.0 release, please ' 'update all codes to use the astropy.table.Table or ' 'gwpy.table.EventTable objects') if size_by is not None and size_by_log is not None: raise ValueError("size_by_color and size_by_log_color are " "mutually exclusive options, please select one") # get x-y data xdata = get_table_column(table, x) ydata = get_table_column(table, y) # rank data by size or colour sizecol = size_by or size_by_log or (size_range and color) if color: cdata = get_table_column(table, color) if sizecol: sdata = get_table_column(table, sizecol) if color and sizecol: zipped = zip(xdata, ydata, cdata, sdata) zipped.sort(key=lambda row: row[2]) try: xdata, ydata, cdata, sdata = map(numpy.asarray, zip(*zipped)) except ValueError: pass elif sizecol: zipped = zip(xdata, ydata, sdata) zipped.sort(key=lambda row: row[-1]) try: xdata, ydata, sdata = map(numpy.asarray, zip(*zipped)) except ValueError: pass elif color: zipped = zip(xdata, ydata, cdata) zipped.sort(key=lambda row: row[-1]) try: xdata, ydata, cdata = map(numpy.asarray, zip(*zipped)) except ValueError: pass # work out sizing if sizecol: if size_range is None and sdata.size: size_range = [sdata.min(), sdata.max()] if size_range: # convert color value into a size between the given min and max s = kwargs.pop('s', 20) sizes = [s/10., s] sp = (sdata - size_range[0]) / (size_range[1] - size_range[0]) sp[sp < 0] = 0 sp[sp > 1] = 1 if size_by_log is None: sarray = sizes[0] + sp * (sizes[1] - sizes[0]) else: logsizes = numpy.log10(sizes) sarray = 10 ** ( logsizes[0] + sp * (logsizes[1] - logsizes[0])) kwargs.setdefault('s', sarray) if color: return self.scatter(xdata, ydata, c=cdata, **kwargs) else: return self.scatter(xdata, ydata, **kwargs)
def process(self): """Get data and generate the figure. """ # get histogram parameters (plot, ax) = self.init_plot() # extract histogram arguments histargs = self.parse_plot_kwargs() legendargs = self.parse_legend_kwargs() # add data data = [] livetime = [] for channel in self.channels: try: channel = get_channel(channel) except ValueError: pass if self.state and not self.all_data: valid = self.state.active else: valid = SegmentList([self.span]) if '#' in str(channel) or '@' in str(channel): key = '%s,%s' % (str(channel), self.state and str(self.state) or 'All') else: key = str(channel) table_ = get_triggers(key, self.etg, valid, query=False) livetime.append(float(abs(table_.segments))) data.append(get_table_column(table_, self.column)) # allow channel data to set parameters if hasattr(channel, 'amplitude_range'): self.pargs.setdefault('xlim', channel.amplitude_range) # get range if not 'range' in histargs[0]: for kwset in histargs: kwset['range'] = ax.common_limits(data) # plot for arr, d, kwargs in zip(data, livetime, histargs): weights = kwargs.pop('weights', None) direction = kwargs.get('orientation', 'vertical') if weights is True: try: weights = 1 / d except ZeroDivisionError: pass if direction == 'horizontal': self.pargs.setdefault('xbound', 1 / float(abs(self.span)) * .5) else: self.pargs.setdefault('ybound', 1 / float(abs(self.span)) * .5) if (kwargs.get('logy', False) or kwargs.get('yscale', 'linear') == 'log'): kwargs.setdefault('bottom', 1e-100) label = kwargs.pop('label', None) if arr.size: ax.hist(arr, label=label, weights=weights, **kwargs) else: ax.plot([], label=label) # tight scale the axes if len(data) and direction == 'vertical' or True: ax.autoscale_view(tight=True, scaley=False) if len(data) and direction == 'horizontal' or False: ax.autoscale_view(tight=True, scalex=False) # customise plot for key, val in self.pargs.iteritems(): try: getattr(ax, 'set_%s' % key)(val) except AttributeError: setattr(ax, key, val) if len(self.channels) > 1: plot.add_legend(ax=ax, **legendargs) # add extra axes and finalise if not plot.colorbars: plot.add_colorbar(ax=ax, visible=False) return self.finalize()
def get_reduced_table(table, column, op, threshold): """Return a masked version of a column with an operator and threshold """ data = get_table_column(table, column) mask = op(data, threshold) return table[mask]
def get_triggers(channel, etg, segments, config=ConfigParser(), cache=None, query=True, multiprocess=False, tablename=None, columns=None, contenthandler=None, return_=True): """Read a table of transient event triggers for a given channel. """ key = '%s,%s' % (str(channel), etg.lower()) if isinstance(segments, DataQualityFlag): segments = segments.active segments = SegmentList(segments) # get LIGO_LW table for this etg if tablename: TableClass = lsctables.TableByName[tablename] register_etg_table(etg, TableClass, force=True) elif key in globalv.TRIGGERS: TableClass = type(globalv.TRIGGERS[key]) else: TableClass = get_etg_table(etg) # work out columns if columns is None: try: columns = config.get(etg, 'columns').split(',') except (NoSectionError, NoOptionError): if etg.lower() in ['cwb', 'cwb-ascii']: columns = None else: columns = TableClass.validcolumns.keys() if columns is not None: for col in ['process_id', 'search', 'channel']: if col not in columns: columns.append(col) # read segments from global memory try: havesegs = globalv.TRIGGERS[key].segments except KeyError: new = segments globalv.TRIGGERS.setdefault( key, lsctables.New(TableClass, columns=columns)) globalv.TRIGGERS[key].segments = type(segments)() else: new = segments - havesegs # read new triggers query &= (abs(new) != 0) if query: # store read kwargs kwargs = {'columns': columns} # set content handler if contenthandler is None: contenthandler = get_partial_contenthandler(TableClass) lsctables.use_in(contenthandler) for segment in new: kwargs['filt'] = ( lambda t: float(get_row_value(t, 'time')) in segment) # find trigger files if cache is None and etg.lower() == 'hacr': raise NotImplementedError("HACR parsing has not been " "implemented.") if cache is None and re.match('dmt(.*)omega', etg.lower()): segcache = find_dmt_omega(channel, segment[0], segment[1]) kwargs['format'] = 'ligolw' elif cache is None and etg.lower() in ['kw', 'kleinewelle']: segcache = find_kw(channel, segment[0], segment[1]) kwargs['format'] = 'ligolw' kwargs['filt'] = lambda t: ( float(get_row_value(t, 'time')) in segment and t.channel == str(channel)) elif cache is None: segcache = trigfind.find_trigger_urls(str(channel), etg, segment[0], segment[1]) kwargs['format'] = 'ligolw' elif isinstance(cache, Cache): segcache = cache.sieve(segment=segment) else: segcache = cache if isinstance(segcache, Cache): segcache = segcache.checkfilesexist()[0] if 'format' not in kwargs and 'ahope' not in etg.lower(): kwargs['format'] = etg.lower() if (issubclass(TableClass, lsctables.SnglBurstTable) and etg.lower().startswith('cwb')): kwargs['ifo'] = get_channel(channel).ifo # read triggers and store if len(segcache) == 0: continue if kwargs.get('format', None) == 'ligolw': kwargs['contenthandler'] = contenthandler table = TableClass.read(segcache, **kwargs) globalv.TRIGGERS[key].extend(table) try: csegs = cache_segments(segcache) except AttributeError: csegs = SegmentList() try: globalv.TRIGGERS[key].segments.extend(csegs) except AttributeError: globalv.TRIGGERS[key].segments = csegs finally: globalv.TRIGGERS[key].segments.coalesce() vprint('\r') # work out time function if return_: times = get_table_column(globalv.TRIGGERS[key], 'time').astype(float) # return correct triggers out = lsctables.New(TableClass, columns=columns) out.channel = str(channel) out.etg = str(etg) out.extend(t for (i, t) in enumerate(globalv.TRIGGERS[key]) if times[i] in segments) out.segments = segments & globalv.TRIGGERS[key].segments return out else: return
def _plot_ligolw_table(self, table, x, y, color=None, size_by=None, size_by_log=None, size_range=None, **kwargs): """Plot a LIGO_LW-format event `Table` onto these `Axes` Parameters ---------- table : :class:`~glue.ligolw.table.Table` LIGO_LW-format XML event `Table` to display x : `str` name of column to display on the X-axis y : `str` name of column to display on the Y-axis c : `str`, optional name of column by which to colour the data **kwargs any other arguments applicable to :meth:`~matplotlib.axes.Axes.scatter` Returns ------- collection """ from ..table.utils import (get_table_column, get_row_value) warnings.warn('Plotting LIGO_LW tables has been deprecated and ' 'will likely be removed before the 1.0 release, please ' 'update all codes to use the astropy.table.Table or ' 'gwpy.table.EventTable objects') if size_by is not None and size_by_log is not None: raise ValueError("size_by_color and size_by_log_color are " "mutually exclusive options, please select one") # get x-y data xdata = get_table_column(table, x) ydata = get_table_column(table, y) # rank data by size or colour sizecol = size_by or size_by_log or (size_range and color) if color: cdata = get_table_column(table, color) if sizecol: sdata = get_table_column(table, sizecol) if color and sizecol: zipped = zip(xdata, ydata, cdata, sdata) zipped.sort(key=lambda row: row[2]) try: xdata, ydata, cdata, sdata = map(numpy.asarray, zip(*zipped)) except ValueError: pass elif sizecol: zipped = zip(xdata, ydata, sdata) zipped.sort(key=lambda row: row[-1]) try: xdata, ydata, sdata = map(numpy.asarray, zip(*zipped)) except ValueError: pass elif color: zipped = zip(xdata, ydata, cdata) zipped.sort(key=lambda row: row[-1]) try: xdata, ydata, cdata = map(numpy.asarray, zip(*zipped)) except ValueError: pass # work out sizing if sizecol: if size_range is None and sdata.size: size_range = [sdata.min(), sdata.max()] if size_range: # convert color value into a size between the given min and max s = kwargs.pop('s', 20) sizes = [s / 10., s] sp = (sdata - size_range[0]) / (size_range[1] - size_range[0]) sp[sp < 0] = 0 sp[sp > 1] = 1 if size_by_log is None: sarray = sizes[0] + sp * (sizes[1] - sizes[0]) else: logsizes = numpy.log10(sizes) sarray = 10**(logsizes[0] + sp * (logsizes[1] - logsizes[0])) kwargs.setdefault('s', sarray) if color: return self.scatter(xdata, ydata, c=cdata, **kwargs) else: return self.scatter(xdata, ydata, **kwargs)
def _plot_ligolw_tiles(self, table, x, y, width, height, color=None, anchor='center', edgecolors='face', linewidth=0.8, **kwargs): from ..table.utils import (get_table_column, get_row_value) warnings.warn('Plotting LIGO_LW tables has been deprecated and ' 'will likely be removed before the 1.0 release, please ' 'update all codes to use the astropy.table.Table or ' 'gwpy.table.EventTable objects') from ..table.utils import (get_table_column, get_row_value) # get x/y data xdata = get_table_column(table, x) ydata = get_table_column(table, y) wdata = get_table_column(table, width) hdata = get_table_column(table, height) # get color and sort if color: cdata = get_table_column(table, color) zipped = zip(xdata, ydata, wdata, hdata, cdata) zipped.sort(key=lambda row: row[-1]) try: xdata, ydata, wdata, hdata, cdata = map( numpy.asarray, zip(*zipped)) except ValueError: pass # construct vertices if anchor == 'll': verts = [((x, y), (x, y + height), (x + width, y + height), (x + width, y)) for (x, y, width, height) in zip(xdata, ydata, wdata, hdata)] elif anchor == 'lr': verts = [((x - width, y), (x - width, y + height), (x, y + height), (x, y)) for (x, y, width, height) in zip(xdata, ydata, wdata, hdata)] elif anchor == 'ul': verts = [((x, y - height), (x, y), (x + width, y), (x + width, y - height)) for (x, y, width, height) in zip(xdata, ydata, wdata, hdata)] elif anchor == 'ur': verts = [((x - width, y - height), (x - width, y), (x, y), (x, y - height)) for (x, y, width, height) in zip(xdata, ydata, wdata, hdata)] elif anchor == 'center': verts = [((x - width / 2., y - height / 2.), (x - width / 2., y + height / 2.), (x + width / 2., y + height / 2.), (x + width / 2., y - height / 2.)) for (x, y, width, height) in zip(xdata, ydata, wdata, hdata)] else: raise ValueError("Unrecognised tile anchor '%s'." % anchor) # build collection cmap = kwargs.pop('cmap', pyplot.rcParams['image.cmap']) coll = collections.PolyCollection(verts, edgecolors=edgecolors, linewidth=linewidth, **kwargs) if color: coll.set_array(cdata) coll.set_cmap(cmap) return self.add_collection(coll)
def write_state_html(self, state): """Write the '#main' HTML content for this `DailyAhopeTab`. """ daydir = os.path.split(self.segmentfile)[0] # did it run if not os.path.isdir(daydir): page = html.markup.page() page.div(class_='alert alert-warning') page.p("No analysis was performed for this period, " "please try again later.") page.p("If you believe these data should have been found, please " "contact %s." % html.markup.oneliner.a('the CBC DQ group', class_='alert-link', href='mailto:[email protected]')) page.div.close() elif (not os.path.isfile(self.segmentfile) or len(self.states[0].active) != 0 and not os.path.isfile(self.inspiralcachefile)): page = html.markup.page() page.div(class_='alert alert-danger') page.p("This analysis seems to have failed.") page.p("If you believe these data should have been found, please " "contact %s." % html.markup.oneliner.a('the CBC DQ group', class_='alert-link', href='mailto:[email protected]')) page.div.close() elif len(self.states[0].active) == 0: page = html.markup.page() page.div(class_='alert alert-info') page.p("This analysis found no segments over which to run.") page.p("If you believe this to be an error, please contact %s." % html.markup.oneliner.a('the CBC DQ group', class_='alert-link', href='mailto:[email protected]')) page.div.close() else: # otherwise, carry on... page = self.scaffold_plots(state=state) # link full results page.hr(class_='row-divider') page.div(class_='btn-group') page.a('Click here for the full Daily Ahope results', href=self.ihopepage, rel='external', target='_blank', class_='btn btn-default btn-info btn-xl') page.div.close() page.hr(class_='row-divider') if self.loudest: table = get_triggers(self.channel, self.plots[0].etg, state, query=False) rank = get_table_column(table, self.loudest['rank']).argsort()[::-1] loudest = [] i = 0 while len(loudest) < self.loudest['N'] and i < rank.size: t = table[rank[i]] if i == 0 or all([ abs(float(t.get_end()) - float(t2.get_end())) >= self.loudest['dt'] for t2 in loudest ]): loudest.append(t) i += 1 page.h1('Loudest events') page.p('The following table displays the %d loudest events as ' 'recorded by Daily Ahope (with at least %s-second ' 'separation).' % (self.loudest['N'], self.loudest['dt'])) headers = self.loudest['labels'] if 'time' in headers[0]: headers.insert(1, 'UTC time') date = True else: data = False data = [] for row in loudest: data.append([]) for column in self.loudest['columns']: data[-1].append('%.3f' % float(get_row_value(row, column))) if date: data[-1].insert( 1, from_gps(row.get_end()).strftime( '%B %d %Y, %H:%M:%S.%f')[:-3]) page.add(str(html.table(headers, data, table='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))) # link full results page.hr(class_='row-divider') page.div(class_='btn-group') page.a('Click here for the full Daily Ahope results', href=self.ihopepage, rel='external', target='_blank', class_='btn btn-default btn-info btn-xl') page.div.close() page.hr(class_='row-divider') # write to file idx = self.states.index(state) with open(self.frames[idx], 'w') as fobj: fobj.write(str(page)) return self.frames[idx]