class Markers(object):
    MIN, MAX, AVG, GMEAN, \
        HP, HFS, HFE, \
        OP, OFS, OFE = range(10) class PlotFunc(object):
    NONE, AVG, MIN, MAX, VAR, SMOOTH, DIFF, DELTA = range(8) class EventThread(wx.PyEvent):
    def __init__(self, status, arg1=None, arg2=None):
        wx.PyEvent.__init__(self)
        self.SetEventType(EVENT_THREAD)
        self.data = Status(status, arg1, arg2) class Event(object):
    STARTING, STEPS, INFO, DATA, STOPPED, ERROR, FINISHED, PROCESSED, \
        CAL, LEVEL, UPDATED, DRAW, \
        DELAY_COUNT, DELAY_START, \
        LOC, LOC_RAW, LOC_WARN, LOC_ERR, LOC_SAT = range(19) def post_event(destination, status):
    if isinstance(destination, Queue.Queue):
        destination.put(status)
    elif isinstance(destination, wx.EvtHandler):
        wx.PostEvent(destination, status) def format_time(timeStamp, withDate=False):
    if timeStamp <= 1:
        return 'Unknown'

    if withDate:
        return time.strftime('%c', time.localtime(timeStamp))

    return time.strftime('%H:%M:%S', time.localtime(timeStamp)) def format_precision(settings, freq=None, level=None,
                     units=True, fancyUnits=False):
    textFreq = None
    textLevel = None

    if freq is not None:
        prec = settings.precisionFreq
        width = 4 + prec
        textFreq = '{:{width}.{prec}f}'.format(freq, width=width, prec=prec)
        if units or fancyUnits:
            textFreq += " MHz"
    if level is not None:
        prec = settings.precisionLevel
        width = 4 + prec
        textLevel = '{:{width}.{prec}f}'.format(level, width=width, prec=prec)
        if fancyUnits:
            textLevel += r" dB/Hz"
        elif units:
            textLevel += " dB/Hz"

    if textFreq and textLevel:
        return (textFreq, textLevel)
    if textFreq:
        return textFreq
    if textLevel:
        return textLevel

    return None def split_spectrum(spectrum):
    freqs = spectrum.keys()
    powers = map(spectrum.get, freqs)

    return freqs, powers class Measure(object):
    MIN, MAX, AVG, GMEAN, HBW, OBW = range(6)

    def __init__(self, spectrum, start, end):
        self.isValid = False
        self.minF = None
        self.maxF = None
        self.minP = None
        self.maxP = None
        self.avgP = None
        self.gMeanP = None
        self.flatness = None
        self.hbw = None
        self.obw = None

        self.__calculate(spectrum, start, end)

    def __calculate(self, spectrum, start, end):
        sweep = slice_spectrum(spectrum, start, end)
        if sweep is None or len(sweep) == 0:
            return

        self.minF = min(sweep)[0]
        self.maxF = max(sweep)[0]
        self.minP = min(sweep, key=lambda v: v[1])
        self.maxP = max(sweep, key=lambda v: v[1])

        powers = [Decimal(db_to_level(p[1])) for p in sweep]
        length = len(powers)

        avg = sum(powers, Decimal(0)) / length
        self.avgP = level_to_db(avg)

        product = reduce(mul, iter(powers))
        gMean = product ** (Decimal(1.0) / length)
        self.gMeanP = level_to_db(gMean)

        self.flatness = gMean / avg

        self.__calc_hbw(sweep)
        self.__calc_obw(sweep)

        self.isValid = True

    def __calc_hbw(self, sweep):
        power = self.maxP[1] - 3
        self.hbw = [None, None, power]

        if power >= self.minP[1]:
            for (f, p) in sweep:
                if p >= power:
                    self.hbw[0] = f
                    break
            for (f, p) in reversed(sweep):
                if p >= power:
                    self.hbw[1] = f
                    break

    def __calc_obw(self, sweep):
        self.obw = [None, None, None]

        totalP = 0
        for (_f, p) in sweep:
            totalP += p
        power = totalP * 0.005
        self.obw[2] = power

        if power >= self.minP[1]:
            for (f, p) in sweep:
                if p >= power:
                    self.obw[0] = f
                    break
            for (f, p) in reversed(sweep):
                if p >= power:
                    self.obw[1] = f
                    break

    def is_valid(self):
        return self.isValid

    def get_f(self):
        return self.minF, self.maxF

    def get_min_p(self):
        return self.minP

    def get_max_p(self):
        return self.maxP

    def get_avg_p(self):
        return self.avgP

    def get_gmean_p(self):
        return self.gMeanP

    def get_flatness(self):
        return self.flatness

    def get_hpw(self):
        return self.hbw

    def get_obw(self):
        return self.obw def smooth_spectrum(spectrum, winFunc, ratio):
    data = OrderedDict()
    for timeStamp, sweep in spectrum.items():
        if len(sweep):
            data[timeStamp] = smooth_sweep(sweep, winFunc, ratio)

    return data class Extent(object):
    def __init__(self, spectrum):
        self.__clear()
        self.__calc_extent(spectrum)

    def __clear(self):
        self.fMin = float('inf')
        self.fMax = float('-inf')
        self.lMin = float('inf')
        self.lMax = float('-inf')
        self.tMin = float('inf')
        self.tMax = float('-inf')
        self.fPeak = None
        self.lPeak = None
        self.tPeak = None

    def __calc_extent(self, spectrum):
        self.tMin = min(spectrum)
        self.tMax = max(spectrum)

        for timeStamp in spectrum:
            points = spectrum[timeStamp].items()
            if len(points) > 0:
                fMin = min(points, key=itemgetter(0))[0]
                fMax = max(points, key=itemgetter(0))[0]
                lMin = min(points, key=itemgetter(1))[1]
                lMax = max(points, key=itemgetter(1))[1]
                self.fMin = min(self.fMin, fMin)
                self.fMax = max(self.fMax, fMax)
                self.lMin = min(self.lMin, lMin)
                if(lMax >= self.lMax):
                    self.lMax = lMax
                    self.fPeak, self.lPeak = max(points, key=lambda(_f, l): l)
                    self.tPeak = timeStamp

    def get_f(self):
        if self.fMin == self.fMax:
            return self.fMin, self.fMax - 0.001
        return self.fMin, self.fMax

    def get_l(self):
        if self.lMin == self.lMax:
            return self.lMin, self.lMax + 0.001
        return self.lMin, self.lMax

    def get_t(self):
        return utc_to_mpl(self.tMax), utc_to_mpl(self.tMin - 1)

    def get_ft(self):
        tExtent = self.get_t()
        return [self.fMin, self.fMax, tExtent[0], tExtent[1]]

    def get_peak_fl(self):
        return self.fPeak, self.lPeak

    def get_peak_flt(self):
        return self.fPeak, self.lPeak, self.tPeak def diff_spectrum(spectrum):
    data = OrderedDict()
    for timeStamp, sweep in spectrum.items():
        diff = numpy.diff(sweep.values())
        data[timeStamp] = OrderedDict(zip(sweep.keys(), diff))

    return data def get_peaks(spectrum, threshold):
    sweep = OrderedDict(spectrum[max(spectrum)])
    for freq, level in sweep.items():
        if level < threshold:
            del sweep[freq]

    indices = (numpy.diff(numpy.sign(numpy.diff(sweep.values()))) < 0).nonzero()[0] + 1

    return sweep, indices
import threading
import time
import matplotlib
import numpy
from matplotlib import cm, patheffects
from matplotlib.colorbar import ColorbarBase
from matplotlib.colors import Normalize
from matplotlib.dates import DateFormatter
from matplotlib.gridspec import GridSpec
from matplotlib.lines import Line2D
from matplotlib.text import Text
from matplotlib.ticker import ScalarFormatter, AutoMinorLocator
from rtlsdr_scanner.constants import Markers, PlotFunc
from rtlsdr_scanner.events import EventThread, Event, post_event
from rtlsdr_scanner.misc import format_time, format_precision
from rtlsdr_scanner.spectrum import split_spectrum, Measure, smooth_spectrum, Extent, \
    diff_spectrum, get_peaks
from rtlsdr_scanner.utils_mpl import utc_to_mpl
        self.axes.set_ylim(utc_to_mpl(now), utc_to_mpl(now - 10))

        self.bar = self.figure.add_subplot(gs[1])
        norm = Normalize(vmin=-50, vmax=0)
        self.barBase = ColorbarBase(self.bar, norm=norm,
                                    cmap=cm.get_cmap(self.settings.colourMap))

        self.__setup_measure()
        self.__setup_overflow()
        self.hide_measure()

    def __setup_measure(self):
        dashesHalf = [1, 5, 5, 5, 5, 5]
        self.lines[Markers.HFS] = Line2D([0, 0], [0, 0], dashes=dashesHalf,
                                         color='purple')
        self.lines[Markers.HFE] = Line2D([0, 0], [0, 0], dashes=dashesHalf,
                                         color='purple')
        self.lines[Markers.OFS] = Line2D([0, 0], [0, 0], dashes=dashesHalf,
                                         color='#996600')
        self.lines[Markers.OFE] = Line2D([0, 0], [0, 0], dashes=dashesHalf,
                                         color='#996600')
        if matplotlib.__version__ >= '1.3':
            effect = patheffects.withStroke(linewidth=3, foreground="w",
                                            alpha=0.75)
            self.lines[Markers.HFS].set_path_effects([effect])
            self.lines[Markers.HFE].set_path_effects([effect])
            self.lines[Markers.OFS].set_path_effects([effect])
            self.lines[Markers.OFE].set_path_effects([effect])

        for line in self.lines.itervalues():
            self.axes.add_line(line)

        bbox = self.axes.bbox
        box = dict(boxstyle='round', fc='white', ec='purple', clip_box=bbox)
        self.labels[Markers.HFS] = Text(0, 0, '-3dB', fontsize='xx-small',
                                        ha="center", va="top", bbox=box,
                                        color='purple')
        self.labels[Markers.HFE] = Text(0, 0, '-3dB', fontsize='xx-small',
                                        ha="center", va="top", bbox=box,
                                        color='purple')
        box['ec'] = '#996600'
        self.labels[Markers.OFS] = Text(0, 0, 'OBW', fontsize='xx-small',
                                        ha="center", va="top", bbox=box,
                                        color='#996600')
        self.labels[Markers.OFE] = Text(0, 0, 'OBW', fontsize='xx-small',
                                        ha="center", va="top", bbox=box,
                                        color='#996600')

        for label in self.labels.itervalues():
            self.axes.add_artist(label)

    def __setup_overflow(self):
        bbox = self.axes.bbox
        box = dict(boxstyle='round', fc='white', ec='black', alpha=0.5,
                   clip_box=bbox)
        self.overflowLabels['left'] = Text(0, 0.9, '', fontsize='xx-small',
                                           ha="left", va="top", bbox=box,
                                           transform=self.axes.transAxes,
                                           alpha=0.5)
        self.overflowLabels['right'] = Text(1, 0.9, '', fontsize='xx-small',
                                            ha="right", va="top", bbox=box,
                                            transform=self.axes.transAxes,
                                            alpha=0.5)

        for label in self.overflowLabels.itervalues():
            self.axes.add_artist(label)

    def __clear_overflow(self):
        for label in self.overflowLabels:
            self.overflow[label] = []

    def __draw_vline(self, marker, x):
        line = self.lines[marker]
        label = self.labels[marker]
        yLim = self.axes.get_ylim()
        xLim = self.axes.get_xlim()
        if xLim[0] < x < xLim[1]:
            line.set_visible(True)
            line.set_xdata([x, x])
            line.set_ydata([yLim[0], yLim[1]])
            self.axes.draw_artist(line)
            label.set_visible(True)
            label.set_position((x, yLim[1]))
            self.axes.draw_artist(label)
        elif x is not None and x < xLim[0]:
            self.overflow['left'].append(marker)
        elif x is not None and x > xLim[1]:
            self.overflow['right'].append(marker)

    def __draw_overflow(self):
        for pos, overflow in self.overflow.iteritems():
            if len(overflow) > 0:
                text = ''
                for measure in overflow:
                    if len(text) > 0:
                        text += '\n'
                    text += self.labels[measure].get_text()

                label = self.overflowLabels[pos]
                if pos == 'left':
                    textMath = '$\\blacktriangleleft$\n' + text
                elif pos == 'right':
                    textMath = '$\\blacktriangleright$\n' + text

                label.set_text(textMath)
                label.set_visible(True)
                self.axes.draw_artist(label)

    def draw_measure(self, measure, show):
        if self.axes.get_renderer_cache() is None:
            return

        self.hide_measure()
        self.__clear_overflow()

        if show[Measure.HBW]:
            xStart, xEnd, _y = measure.get_hpw()
            self.__draw_vline(Markers.HFS, xStart)
            self.__draw_vline(Markers.HFE, xEnd)


        if show[Measure.OBW]: