def RunTestWithTimeout(test_timeout, errmsg='Test Timed-out'): """ Context manager to execute tests with a timeout :param: test_timeout : int :param: errmsg : str :rtype: None """ try: with TestTimeout(seconds=test_timeout): yield except Exception: LOGGER.exception(errmsg) Aqf.failed(errmsg) Aqf.end(traceback=True)
def aqf_plot_channels( channelisation, plot_filename='', plot_title='', caption="", log_dynamic_range=90, log_normalise_to=1, normalise=False, hlines=None, vlines=None, ylimits=None, xlabel=None, ylabel=None, plot_type='channel', hline_strt_idx=0, cutoff=None, show=False, ): """ Simple magnitude plot of a channelised result return: None Example ------- aqf_plot_channels(nomalised_magnintude(dump['xeng_raw'][:, 0, :]), 'chan_plot_file', 'Channelisation plot') If `channelisation` is a tuple it is interpreted as a multi-line plot with `channelisation` containing: `((plot1_data, legend1), (plot2_data, legend2), ... )` If a legend is None it is ignored. if `log_dynamic_range` is not None, a log plot will be made with values normalised to the peak value of less than -`log_dynamic_range` dB set to -`log_dynamic_range` Normalise log dynamic range to `log_normalise_to`. If None, each line is normalised to it's own max value, which can be confusing if they don't all have the same max... If Normalise = True the maximum log value will be subtracted from the loggerised data. plot_type: channel = Channelisation test plot eff = Efficiency plot bf = Beamformer response plot hline_strt_idx: Horisontal line colour will be matched to the actual line colour. If multiple hlines will be plotted, use this index to indicate at which actual line to start matching colours. """ try: if not isinstance(channelisation[0], tuple): channelisation = ((channelisation, None), ) except IndexError: Aqf.failed('List of channel responses out of range: {}'.format( channelisation)) has_legend = False plt_line = [] try: ax = plt.gca() except tkinter.TclError: LOGGER.exception( 'No display on $DISPLAY enviroment variable, check matplotlib backend' ) return False try: vlines_plotd = False if len(vlines) > 3: annotate_text = vlines[-1] vlines = vlines[:-1] if type(vlines) is list: _vlines = iter(vlines) else: _vlines = vlines except: pass plt.grid(True) for plot_data, legend in channelisation: kwargs = {} if legend: has_legend = True kwargs['label'] = legend if log_dynamic_range is not None: plot_data = loggerise(plot_data, log_dynamic_range, normalise_to=log_normalise_to, normalise=normalise) ylbl = 'Channel response [dB]' else: if plot_type == 'eff': ylbl = 'Efficiency [%]' else: ylbl = 'Channel response (linear)' plt_color = ax._get_lines.prop_cycler.next().values()[0] try: plt_line_obj = plt.plot(plot_data, color=plt_color, **kwargs) except tkinter.TclError: LOGGER.exception( 'No display on $DISPLAY enviroment variable, check matplotlib backend' ) return False if type(vlines) is list: try: plt.axvline(x=next(_vlines), linestyle='dashdot', color=plt_color) vlines_plotd = True except StopIteration: pass except TypeError: plt.axvline(x=_vlines, linestyle='dashdot', color=plt_color) vlines_plotd = True plt_line.append(plt_line_obj) if ylabel: plt.ylabel(ylabel) else: plt.ylabel(ylbl) if xlabel: plt.xlabel(xlabel) else: plt.xlabel('Channel number') if cutoff: msg = ('CBF channel isolation: {:.3f}dB'.format(cutoff)) plt.axhline(cutoff, color='red', linestyle='dotted', linewidth=1.5) plt.annotate(msg, xy=(len(plot_data) / 2, cutoff), xytext=(-20, -30), textcoords='offset points', ha='center', va='bottom', bbox=dict(boxstyle='round, pad=0.2', alpha=0.3), arrowprops=dict(arrowstyle='->', fc='yellow', connectionstyle='arc3, rad=0.5', color='red')) if plot_title: plt.title(plot_title) if ylimits: plt.ylim(ylimits) if caption: plt.figtext(.1, -.25, ' \n'.join(textwrap.wrap(caption)), horizontalalignment='left') if vlines_plotd: ymid = np.min(plot_data) / 2. plt.annotate('', xy=[vlines[0], ymid], xytext=(vlines[1], ymid), arrowprops=dict(arrowstyle='<->')) plt.annotate('', xy=[vlines[1], ymid], xytext=(vlines[2], ymid), arrowprops=dict(arrowstyle='<->')) plt.text(vlines[0], ymid + 1, annotate_text) if hlines: if type(hlines) is not list: lines = hlines msg = ('{:.3f}dB'.format(lines)) plt.axhline(lines, linestyle='dotted', linewidth=1.5) else: for idx, lines in enumerate(hlines): try: color = plt_line[idx + hline_strt_idx][0].get_color() except: color = 'red' plt.axhline(lines, linestyle='dotted', color=color, linewidth=1.5) if plot_type == 'eff': msg = ('Requirement: {}%'.format(lines)) elif plot_type == 'bf': msg = ('Expected: {:.2f}dB'.format(lines)) else: msg = ('{:.2f} dB'.format(lines)) plt.annotate(msg, xy=(len(plot_data) / 2, lines), xytext=(-20, -30), textcoords='offset points', ha='center', va='bottom', bbox=dict(boxstyle='round, pad=0.2', alpha=0.3), arrowprops=dict(arrowstyle='->', fc='yellow', connectionstyle='arc3, rad=0.5', color='red')) if has_legend: plt.legend(fontsize=9, fancybox=True, loc='center left', bbox_to_anchor=(1, .8), borderaxespad=0.).set_alpha(0.5) Aqf.matplotlib_fig(plot_filename, caption=caption) if show: fig1 = plt.gcf() # Get Current Figure plt.show(block=False) plt.draw() fig1.savefig(plot_filename, bbox_inches='tight', dpi=100) plt.cla() plt.clf()