# -*- coding: utf-8 -*-
# Copyright (C) Duncan Macleod (2018)
#
# This file is part of GWSumm.
#
# GWSumm is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GWSumm is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GWSumm. If not, see <http://www.gnu.org/licenses/>.
"""Plots of Guardian data
"""
from collections import OrderedDict
from gwpy.plot.colors import tint
from gwpy.plot.segments import SegmentRectangle
from gwpy.segments import (Segment, SegmentList)
from gwdetchar.plot import texify
from ...data import get_timeseries
from ...segments import get_segments
from ...utils import re_quote
from ..registry import (get_plot, register_plot)
__author__ = 'Duncan Macleod <duncan.macleod@ligo.org>'
[docs]
class GuardianStatePlot(get_plot('segments')):
type = 'guardian'
defaults = get_plot('segments').defaults.copy()
defaults.update({
'color': None,
'linewidth': 0.5,
'requestcolor': '#0066ff',
'nominalcolor': '#ffb200',
'legend_loc': 'upper left',
'legend_bbox_to_anchor': (1., 1.),
'legend_borderaxespad': 0.,
'legend_frameon': False,
'legend_fontsize': 12,
'ytick.labelsize': 10,
})
def __init__(self, *args, **kwargs):
super(GuardianStatePlot, self).__init__(*args, **kwargs)
self.preview_labels = True
@property
def node(self):
return self.flags[0].split(' ', 1)[0][3:]
@property
def ifo(self):
return list(self.ifos)[0]
[docs]
def draw(self):
from ...tabs.guardian import (REQUESTSTUB, NOMINALSTUB,
re_guardian_index)
plot = self.init_plot()
ax = plot.gca()
# get labels
flags = [texify(str(f)) for f in self.flags]
labels = self.pargs.pop('labels', self.pargs.pop('label', flags))
ax.set_insetlabels(self.pargs.pop('insetlabels', True))
if isinstance(labels, str):
labels = labels.split(',')
labels = [re_quote.sub('', str(s).strip('\n ')) for s in labels]
# parse plotting arguments
legendargs = self.parse_legend_kwargs()
plotargs = self.parse_plot_kwargs()[0]
plotargs.pop('label')
height = plotargs.pop('height', .8)
activecolor = plotargs.pop('facecolor')
nominalcolor = self.pargs.pop('nominalcolor')
requestcolor = self.pargs.pop('requestcolor')
actargs = plotargs.copy()
plotargs.update({
'facecolor': nominalcolor,
'edgecolor': 'none',
'known': {'alpha': 0.1, 'facecolor': 'lightgray'},
})
reqargs = plotargs.copy()
reqargs.update({
'facecolor': requestcolor,
'known': None,
'height': height,
})
actargs.update({
'facecolor': activecolor,
'known': None,
})
if self.state and not self.all_data:
valid = self.state.active
else:
valid = SegmentList([self.span])
# plot segments
for y, (flag, label) in enumerate(list(zip(self.flags, labels))[::-1]):
inreq = str(flag) + REQUESTSTUB
nominal = str(flag) + NOMINALSTUB
segs = get_segments([flag, inreq, nominal], validity=valid,
query=False)
# format label
if self.fileformat != 'svg':
try:
idx, label = re_guardian_index.match(label).groups()
except AttributeError:
pass
else:
x = float(self.span[0]) - (float(abs(self.span)) * 0.005)
ax.text(x, y, '[%s]' % idx, ha='right', va='center',
fontsize=12)
# plot segments
ax.plot(segs[nominal], label=label, y=y, height=1., **plotargs)
ax.plot(segs[inreq], label=label, y=y, collection='ignore',
**reqargs)
ax.plot(segs[flag], label=label, y=y, collection='ignore',
height=.6, **actargs)
# make custom legend
seg = Segment(self.start - 10, self.start - 9)
v = plotargs.pop('known', None)
n = SegmentRectangle(seg, 0, facecolor=nominalcolor,
edgecolor=nominalcolor)
a = SegmentRectangle(seg, 0, facecolor=requestcolor,
edgecolor=requestcolor)
b = SegmentRectangle(seg, 0, facecolor=activecolor,
edgecolor=actargs['edgecolor'])
handles = [n, a, b]
labels = ['Nominal', 'Request', 'Active']
if v:
v.pop('collection', None)
v['edgecolor'] = v.get('edgecolor') or tint(v['facecolor'], .5)
handles.insert(0, SegmentRectangle(seg, 0, **v))
labels.insert(0, 'Alive')
ax.legend(handles, labels, title='Node state', **legendargs)
# customise plot
for key, val in self.pargs.items():
try:
getattr(ax, 'set_%s' % key)(val)
except AttributeError:
setattr(ax, key, val)
if 'ylim' not in self.pargs:
ax.set_ylim(-0.5, len(self.flags) - 0.5)
epoch = ax.get_epoch()
# add node MODE along the bottom
sax = None
seg_kw = {'y': 0, 'edgecolor': 'none', 'label': 'Mode'}
legentry = OrderedDict()
colors = iter(('#0066ff', '#8000bf', 'hotpink', 'yellow'))
for ctag, mstate in [
# bit listing for channels (Nones are ignored)
('MODE', ('EXEC', 'MANAGED', 'MANUAL')),
('OP', (None, 'PAUSE', None)),
]:
# get data
data = get_timeseries(
'{0.ifo}:GRD-{0.node}_{1}'.format(self, ctag), valid,
query=False).join(gap='pad', pad=-1)
for i, m in filter(lambda x: x[1] is not None, enumerate(mstate)):
x = (data == i).to_dqflag()
fc = next(colors)
if sax is None:
sax = plot.add_segments_bar(
x.active, facecolor=fc, **seg_kw)
else:
sax.plot_segmentlist(
x.active, facecolor=fc, **seg_kw)
legentry[m.title()] = SegmentRectangle(seg, 0, facecolor=fc,
edgecolor=fc)
seg_kw.update({'collection': 'ignore', 'label': None})
# add OK segments along the bottom
ok = get_segments(flag.split(' ', 1)[0] + ' OK', validity=valid,
query=False)
seg_kw.pop('edgecolor', None)
sax.plot_segmentlist(ok.active, facecolor=activecolor,
edgecolor=actargs['edgecolor'],
**seg_kw)
legentry['`OK\''] = SegmentRectangle(seg, 0, facecolor=activecolor,
edgecolor=actargs['edgecolor'])
# make custom legend
legendargs.update({
'bbox_to_anchor': (1., 0.),
'loc': 'lower left',
})
sax.legend(list(legentry.values()), list(legentry),
title='Node mode', **legendargs)
sax.tick_params(axis='y', which='major', labelsize=12)
for ax_ in (ax, sax):
ax_.set_epoch(epoch)
return self.finalize()
register_plot(GuardianStatePlot)