F_MIN = 0 F_MAX = 9999 class Cal(object):
    START, DONE, OK, CANCEL = range(4) WINFUNC = ["Bartlett", numpy.bartlett,
           "Blackman", numpy.blackman,
           "Hamming", numpy.hamming,
           "Hanning", numpy.hanning] class PlotFunc(object):
    NONE, AVG, MIN, MAX, VAR, SMOOTH, DIFF, DELTA = range(8) 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) class File(object):
    class Types(object):
        SAVE, PLOT, IMAGE, GEO, GMAP, TRACK, CONT = range(7)

    class SaveType(object):
        RFS = 0

    class PlotType(object):
        CSV, GNUPLOT, FREEMAT, WWB = range(4)

    class ImageType(object):
        BMP, EPS, GIF, JPEG, PDF, PNG, PPM, TIFF = range(8)

    class GeoType(object):
        KMZ, CSV, BMP, EPS, GIF, JPEG, PDF, PNG, PPM, TIFF = range(10)

    class GMapType(object):
        HTML = 0

    class TrackType(object):
        GPX = 0

    SAVE = [''] * 1
    SAVE[SaveType.RFS] = 'RTLSDR frequency scan (*.rfs)|*.rfs'

    PLOT = [''] * 4
    PLOT[PlotType.CSV] = "CSV table (*.csv)|*.csv"
    PLOT[PlotType.GNUPLOT] = "gnuplot script (*.plt)|*.plt"
    PLOT[PlotType.FREEMAT] = "FreeMat script (*.m)|*.m"
    PLOT[PlotType.WWB] = "Wireless Workbench (*.sdb2)|*.sdb2"

    IMAGE = [''] * 8
    IMAGE[ImageType.BMP] = 'Bitmap image (*.bmp)|*.bmp'
    IMAGE[ImageType.EPS] = 'Encapsulated PostScript (*.eps)|*.eps'
    IMAGE[ImageType.GIF] = 'GIF image (*.gif)|*.gif'
    IMAGE[ImageType.JPEG] = 'JPEG image (*.jpeg)|*.jpeg'
    IMAGE[ImageType.PDF] = 'Portable Document (*.pdf)|*.pdf'
    IMAGE[ImageType.PNG] = 'Portable Network Graphics Image (*.png)|*.png'
    IMAGE[ImageType.PPM] = 'Portable Pixmap image (*.ppm)|*.ppm'
    IMAGE[ImageType.TIFF] = 'Tagged Image File (*.tiff)|*.tiff'

    GEO = [''] * 10
    GEO[GeoType.BMP] = 'Bitmap image (*.bmp)|*.bmp'
    GEO[GeoType.CSV] = 'CSV Table (*.csv)|*.csv'
    GEO[GeoType.EPS] = 'Encapsulated PostScript (*.eps)|*.eps'
    GEO[GeoType.GIF] = 'GIF image (*.gif)|*.gif'
    GEO[GeoType.JPEG] = 'JPEG image (*.jpeg)|*.jpeg'
    GEO[GeoType.KMZ] = 'Google Earth (*.kmz)|*.kmz'
    GEO[GeoType.PDF] = 'Portable Document (*.pdf)|*.pdf'
    GEO[GeoType.PNG] = 'Portable Network Graphics Image (*.png)|*.png'
    GEO[GeoType.PPM] = 'Portable Pixmap image (*.ppm)|*.ppm'
    GEO[GeoType.TIFF] = 'Tagged Image File (*.tiff)|*.tiff'

    GMAP = [''] * 1
    GMAP[GMapType.HTML] = 'HTML Document (*.html)|*.html'

    TRACK = [''] * 1
    TRACK[TrackType.GPX] = 'GPX track (*.gpx)|*.gpx'

    CONT = [''] * 1
    CONT[PlotType.CSV] = PLOT[PlotType.CSV]

    HEADER = APP_NAME
    VERSION = 9

    @staticmethod
    def __get_types(type):
        return [File.SAVE, File.PLOT, File.IMAGE,
                File.GEO, File.GMAP, File.TRACK, File.CONT][type]

    @staticmethod
    def get_type_ext(index, type=Types.PLOT):
        types = File.__get_types(type)
        filter = types[index]
        delim = filter.index('|*')
        return filter[delim + 2:]

    @staticmethod
    def get_type_filters(type=Types.PLOT):
        types = File.__get_types(type)

        filters = ''
        length = len(types)
        for i in xrange(length):
            filters += types[i]
            if i < length - 1:
                filters += '|'

        return filters

    @staticmethod
    def get_type_pretty(type):
        types = File.__get_types(type)

        pretty = ''
        length = len(types)
        for i in xrange(length):
            pretty += File.get_type_ext(i, type)
            if i < length - 2:
                pretty += ', '
            elif i < length - 1:
                pretty += ' or '

        return pretty

    @staticmethod
    def get_type_index(extension, type=Types.PLOT):
        exports = File.__get_types(type)
        for i in xrange(len(exports)):
            if extension == File.get_type_ext(i, type):
                return i

        return -1 def open_plot(dirname, filename):
    pickle = True
    error = False
    dwell = 0.131
    nfft = 1024
    name = None
    gain = None
    lo = None
    calibration = None
    tuner = 0
    spectrum = OrderedDict()
    time = None
    lat = None
    lon = None
    desc = ''
    location = OrderedDict()

    path = os.path.join(dirname, filename)
    if not os.path.exists(path):
        return None, None, None
    handle = open(path, 'rb')
    try:
        header = cPickle.load(handle)
    except cPickle.UnpicklingError:
        pickle = False
    except EOFError:
        pickle = False

    if pickle:
        try:
            _version = cPickle.load(handle)
            start = cPickle.load(handle)
            stop = cPickle.load(handle)
            spectrum[1] = {}
            spectrum[1] = cPickle.load(handle)
        except pickle.PickleError:
            error = True
    else:
        try:
            handle.seek(0)
            data = json.loads(handle.read())
            header = data[0]
            version = data[1]['Version']
            start = data[1]['Start']
            stop = data[1]['Stop']
            if version > 1:
                dwell = data[1]['Dwell']
                nfft = data[1]['Nfft']
            if version > 2:
                name = data[1]['Device']
                gain = data[1]['Gain']
                lo = data[1]['LO']
                calibration = data[1]['Calibration']
            if version > 4:
                tuner = data[1]['Tuner']
            if version > 5:
                time = data[1]['Time']
                lat = data[1]['Latitude']
                lon = data[1]['Longitude']
            if version < 7:
                spectrum[1] = {}
                for f, p in data[1]['Spectrum'].iteritems():
                    spectrum[1][float(f)] = p
            else:
                for t, s in data[1]['Spectrum'].iteritems():
                    spectrum[float(t)] = {}
                    for f, p in s.iteritems():
                        spectrum[float(t)][float(f)] = p
            if version > 7:
                desc = data[1]['Description']
            if version > 8:
                location = {}
                for t, l in data[1]['Location'].iteritems():
                    location[float(t)] = l

        except ValueError:
            error = True
        except KeyError:
            error = True

    handle.close()

    if error or header != File.HEADER:
        wx.MessageBox('Invalid or corrupted file', 'Warning',
                      wx.OK | wx.ICON_WARNING)
        return None, None, None

    scanInfo = ScanInfo()
    scanInfo.start = start
    scanInfo.stop = stop
    scanInfo.dwell = dwell
    scanInfo.nfft = nfft
    scanInfo.name = name
    scanInfo.gain = gain
    scanInfo.lo = lo
    scanInfo.calibration = calibration
    scanInfo.tuner = tuner
    scanInfo.time = time
    scanInfo.lat = lat
    scanInfo.lon = lon
    scanInfo.desc = desc

    spectrum = sort_spectrum(spectrum)

    return scanInfo, spectrum, location 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 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)) class PanelGraphCompare(wx.Panel):

    def __init__(self, parent, callback):
        self.callback = callback

        self.spectrum1 = None
        self.spectrum2 = None
        self.spectrumDiff = None

        self.mouseZoom = None

        formatter = ScalarFormatter(useOffset=False)

        wx.Panel.__init__(self, parent)

        figure = matplotlib.figure.Figure(facecolor='white')
        figure.set_size_inches(8, 4.5)
        if matplotlib.__version__ >= '1.2':
            figure.set_tight_layout(True)

        self.axesScan = figure.add_subplot(111)
        self.axesScan.xaxis.set_minor_locator(AutoMinorLocator(10))
        self.axesScan.yaxis.set_minor_locator(AutoMinorLocator(10))
        self.axesScan.xaxis.set_major_formatter(formatter)
        self.axesScan.yaxis.set_major_formatter(formatter)
        self.axesDiff = self.axesScan.twinx()
        self.axesDiff.yaxis.set_minor_locator(AutoMinorLocator(10))
        self.plotScan1, = self.axesScan.plot([], [], 'b-',
                                                     linewidth=0.4)
        self.plotScan2, = self.axesScan.plot([], [], 'g-',
                                                     linewidth=0.4)
        self.plotDiff, = self.axesDiff.plot([], [], 'r-', linewidth=0.4)
        self.axesScan.set_ylim(auto=True)
        self.axesDiff.set_ylim(auto=True)

        self.axesScan.set_title("Level Comparison")
        self.axesScan.set_xlabel("Frequency (MHz)")
        self.axesScan.set_ylabel('Level (dB/Hz)')
        self.axesDiff.set_ylabel('Difference (dB/Hz)')

        self.canvas = FigureCanvas(self, -1, figure)

        self.set_grid(True)

        self.textIntersect = wx.StaticText(self, label="Intersections: ")

        toolbar = NavigationToolbarCompare(self)
        toolbar.Realize()
        self.mouseZoom = MouseZoom(toolbar, figure=figure)

        vbox = wx.BoxSizer(wx.VERTICAL)
        vbox.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW)
        vbox.Add(self.textIntersect, 0, wx.EXPAND | wx.ALL, border=5)
        vbox.Add(toolbar, 0, wx.EXPAND)

        self.SetSizer(vbox)
        vbox.Fit(self)

        self.canvas.mpl_connect('motion_notify_event', self.__on_motion)
        self.canvas.mpl_connect('axes_leave_event', self.__on_leave)

    def __on_motion(self, event):
        xpos = event.xdata
        ypos = event.ydata
        if xpos is None or ypos is None:
            return

        locs = dict.fromkeys(['x1', 'y1', 'x2', 'y2', 'x3', 'y3'], None)

        if self.spectrum1 is not None and len(self.spectrum1) > 0:
            locs['x1'] = min(self.spectrum1.keys(),
                             key=lambda freq: abs(freq - xpos))
            locs['y1'] = self.spectrum1[locs['x1']]

        if self.spectrum2 is not None and len(self.spectrum2) > 0:
            locs['x2'] = min(self.spectrum2.keys(),
                             key=lambda freq: abs(freq - xpos))
            locs['y2'] = self.spectrum2[locs['x2']]

        if self.spectrumDiff is not None and len(self.spectrumDiff) > 0:
            locs['x3'] = min(self.spectrumDiff.keys(),
                             key=lambda freq: abs(freq - xpos))
            locs['y3'] = self.spectrumDiff[locs['x3']]

        self.callback(locs)

    def __on_leave(self, event):
        self.callback(None)

    def __relim(self):
        self.axesScan.relim()
        self.axesDiff.relim()

    def __plot_diff(self):
        diff = {}
        intersections = 0

        if self.spectrum1 is not None and self.spectrum2 is not None:
            set1 = set(self.spectrum1)
            set2 = set(self.spectrum2)
            intersect = set1.intersection(set2)
            intersections = len(intersect)
            for freq in intersect:
                diff[freq] = self.spectrum1[freq] - self.spectrum2[freq]
            freqs, powers = split_spectrum_sort(diff)
            self.plotDiff.set_xdata(freqs)
            self.plotDiff.set_ydata(powers)
        elif self.spectrum1 is None:
            freqs, powers = split_spectrum_sort(self.spectrum2)
            intersections = len(freqs)
            self.plotDiff.set_xdata(freqs)
            self.plotDiff.set_ydata([0] * intersections)
        else:
            freqs, powers = split_spectrum_sort(self.spectrum1)
            intersections = len(freqs)
            self.plotDiff.set_xdata(freqs)
            self.plotDiff.set_ydata([0] * intersections)

        self.spectrumDiff = diff

        self.textIntersect.SetLabel('Intersections: {}'.format(intersections))

    def get_canvas(self):
        return self.canvas

    def show_plot1(self, enable):
        self.plotScan1.set_visible(enable)
        self.canvas.draw()

    def show_plot2(self, enable):
        self.plotScan2.set_visible(enable)
        self.canvas.draw()

    def show_plotdiff(self, enable):
        self.plotDiff.set_visible(enable)
        self.canvas.draw()

    def set_spectrum1(self, spectrum):
        timeStamp = max(spectrum)
        self.spectrum1 = spectrum[timeStamp]
        freqs, powers = split_spectrum_sort(self.spectrum1)
        self.plotScan1.set_xdata(freqs)
        self.plotScan1.set_ydata(powers)
        self.__plot_diff()
        self.__relim()
        self.autoscale()

    def set_spectrum2(self, spectrum):
        timeStamp = max(spectrum)
        self.spectrum2 = spectrum[timeStamp]
        freqs, powers = split_spectrum_sort(self.spectrum2)
        self.plotScan2.set_xdata(freqs)
        self.plotScan2.set_ydata(powers)
        self.__plot_diff()
        self.__relim()
        self.autoscale()

    def set_grid(self, grid):
        self.axesScan.grid(grid)
        self.canvas.draw()

    def autoscale(self):
        self.axesScan.autoscale_view()
        self.axesDiff.autoscale_view()
        self.canvas.draw() class PanelLine(wx.Panel):

    def __init__(self, parent, colour):
        self.colour = colour

        wx.Panel.__init__(self, parent)
        self.Bind(wx.EVT_PAINT, self.__on_paint)

    def __on_paint(self, _event):
        dc = wx.BufferedPaintDC(self)
        width, height = self.GetClientSize()
        if not width or not height:
            return

        pen = wx.Pen(self.colour, 2)
        dc.SetPen(pen)
        colourBack = self.GetBackgroundColour()
        brush = wx.Brush(colourBack, wx.SOLID)
        dc.SetBackground(brush)

        dc.Clear()
        dc.DrawLine(0, height / 2., width, height / 2.) class Plotter(object):
    def __init__(self, notify, figure, settings):
        self.notify = notify
        self.figure = figure
        self.settings = settings
        self.axes = None
        self.bar = None
        self.barBase = None
        self.threadPlot = None
        self.extent = None
        self.lines = {}
        self.labels = {}
        self.overflowLabels = {}
        self.overflow = {'left': [],
                         'right': [],
                         'top': [],
                         'bottom': []}

        self.__setup_plot()
        self.set_grid(self.settings.grid)

    def __setup_plot(self):
        formatter = ScalarFormatter(useOffset=False)

        gs = GridSpec(1, 2, width_ratios=[9.5, 0.5])

        self.axes = self.figure.add_subplot(gs[0],
                                            facecolor=self.settings.background)
        self.axes.set_xlabel("Frequency (MHz)")
        self.axes.set_ylabel('Level (dB/Hz)')
        self.axes.xaxis.set_major_formatter(formatter)
        self.axes.yaxis.set_major_formatter(formatter)
        self.axes.xaxis.set_minor_locator(AutoMinorLocator(10))
        self.axes.yaxis.set_minor_locator(AutoMinorLocator(10))
        self.axes.set_xlim(self.settings.start, self.settings.stop)
        self.axes.set_ylim(-50, 0)

        self.bar = self.figure.add_subplot(gs[1])
        norm = Normalize(vmin=-50, vmax=0)
        self.barBase = ColorbarBase(self.bar, norm=norm)
        self.set_colourmap_use(self.settings.colourMapUse)

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

    def __setup_measure(self):
        dashesAvg = [4, 5, 1, 5, 1, 5]
        dashesGM = [5, 5, 5, 5, 1, 5, 1, 5]
        dashesHalf = [1, 5, 5, 5, 5, 5]
        self.lines[Markers.MIN] = Line2D([0, 0], [0, 0], linestyle='--',
                                         color='black')
        self.lines[Markers.MAX] = Line2D([0, 0], [0, 0], linestyle='-.',
                                         color='black')
        self.lines[Markers.AVG] = Line2D([0, 0], [0, 0], dashes=dashesAvg,
                                         color='magenta')
        self.lines[Markers.GMEAN] = Line2D([0, 0], [0, 0], dashes=dashesGM,
                                           color='green')
        self.lines[Markers.HP] = Line2D([0, 0], [0, 0], dashes=dashesHalf,
                                        color='purple')
        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.OP] = Line2D([0, 0], [0, 0], dashes=dashesHalf,
                                        color='#996600')
        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.MIN].set_path_effects([effect])
            self.lines[Markers.MAX].set_path_effects([effect])
            self.lines[Markers.AVG].set_path_effects([effect])
            self.lines[Markers.GMEAN].set_path_effects([effect])
            self.lines[Markers.HP].set_path_effects([effect])
            self.lines[Markers.HFS].set_path_effects([effect])
            self.lines[Markers.HFE].set_path_effects([effect])
            self.lines[Markers.OP].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='black', clip_box=bbox)
        self.labels[Markers.MIN] = Text(0, 0, 'Min', fontsize='xx-small',
                                        ha="right", va="bottom", bbox=box,
                                        color='black')
        self.labels[Markers.MAX] = Text(0, 0, 'Max', fontsize='xx-small',
                                        ha="right", va="top", bbox=box,
                                        color='black')
        box['ec'] = 'magenta'
        self.labels[Markers.AVG] = Text(0, 0, 'Mean', fontsize='xx-small',
                                        ha="right", va="center", bbox=box,
                                        color='magenta')
        box['ec'] = 'green'
        self.labels[Markers.GMEAN] = Text(0, 0, 'GMean', fontsize='xx-small',
                                          ha="right", va="center", bbox=box,
                                          color='green')
        box['ec'] = 'purple'
        self.labels[Markers.HP] = Text(0, 0, '-3dB', fontsize='xx-small',
                                       ha="right", va="center", bbox=box,
                                       color='purple')
        self.labels[Markers.HFS] = Text(0, 0, '-3dB Start', fontsize='xx-small',
                                        ha="center", va="top", bbox=box,
                                        color='purple')
        self.labels[Markers.HFE] = Text(0, 0, '-3dB End', fontsize='xx-small',
                                        ha="center", va="top", bbox=box,
                                        color='purple')
        box['ec'] = '#996600'
        self.labels[Markers.OP] = Text(0, 0, 'OBW', fontsize='xx-small',
                                       ha="right", va="center", bbox=box,
                                       color='#996600')
        self.labels[Markers.OFS] = Text(0, 0, 'OBW Start', fontsize='xx-small',
                                        ha="center", va="top", bbox=box,
                                        color='#996600')
        self.labels[Markers.OFE] = Text(0, 0, 'OBW End', 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)
        self.overflowLabels['top'] = Text(0.9, 1, '', fontsize='xx-small',
                                          ha="right", va="top", bbox=box,
                                          transform=self.axes.transAxes,
                                          alpha=0.5)
        self.overflowLabels['bottom'] = Text(0.9, 0, '', fontsize='xx-small',
                                             ha="right", va="bottom", 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_hline(self, marker, y):
        line = self.lines[marker]
        label = self.labels[marker]
        xLim = self.axes.get_xlim()
        yLim = self.axes.get_ylim()
        if yLim[0] <= y <= yLim[1]:
            line.set_visible(True)
            line.set_xdata([xLim[0], xLim[1]])
            line.set_ydata([y, y])
            self.axes.draw_artist(line)
            label.set_visible(True)
            label.set_position((xLim[1], y))
            self.axes.draw_artist(label)
        elif y is not None and y < yLim[0]:
            self.overflow['bottom'].append(marker)
        elif y is not None and y > yLim[1]:
            self.overflow['top'].append(marker)

    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 == 'top':
                    textMath = '$\\blacktriangle$\n' + text
                elif pos == 'bottom':
                    textMath = '$\\blacktriangledown$\n' + text
                elif 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.MIN]:
            y = measure.get_min_p()[1]
            self.__draw_hline(Markers.MIN, y)

        if show[Measure.MAX]:
            y = measure.get_max_p()[1]
            self.__draw_hline(Markers.MAX, y)

        if show[Measure.AVG]:
            y = measure.get_avg_p()
            self.__draw_hline(Markers.AVG, y)

        if show[Measure.GMEAN]:
            y = measure.get_gmean_p()
            self.__draw_hline(Markers.GMEAN, y)

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

        if show[Measure.OBW]:
            xStart, xEnd, y = measure.get_obw()
            self.__draw_hline(Markers.OP, y)
            self.__draw_vline(Markers.OFE, xStart)
            self.__draw_vline(Markers.OFE, xEnd)

        self.__draw_overflow()

    def hide_measure(self):
        for line in self.lines.itervalues():
            line.set_visible(False)
        for label in self.labels.itervalues():
            label.set_visible(False)
        for label in self.overflowLabels.itervalues():
            label.set_visible(False)

    def scale_plot(self, force=False):
        if self.extent is not None:
            if self.settings.autoF or force:
                self.axes.set_xlim(self.extent.get_f())
            if self.settings.autoL or force:
                self.axes.set_ylim(self.extent.get_l())
                if self.settings.plotFunc == PlotFunc.VAR and len(self.axes.collections) > 0:
                    norm = self.axes.collections[0].norm
                    self.barBase.set_clim((norm.vmin, norm.vmax))
                else:
                    self.barBase.set_clim(self.extent.get_l())
                    norm = Normalize(vmin=self.extent.get_l()[0],
                                     vmax=self.extent.get_l()[1])
                for collection in self.axes.collections:
                    collection.set_norm(norm)
                try:
                    self.barBase.draw_all()
                except:
                    pass

    def redraw_plot(self):
        if self.figure is not None:
            post_event(self.notify, EventThread(Event.DRAW))

    def get_axes(self):
        return self.axes

    def get_axes_bar(self):
        return self.barBase.ax

    def get_bar(self):
        return self.barBase

    def get_plot_thread(self):
        return self.threadPlot

    def set_title(self, title):
        self.axes.set_title(title, fontsize='medium')

    def set_plot(self, spectrum, extent, annotate=False):
        self.extent = extent
        self.threadPlot = ThreadPlot(self, self.settings,
                                     self.axes,
                                     spectrum,
                                     self.extent,
                                     self.barBase,
                                     annotate)
        self.threadPlot.start()

        return self.threadPlot

    def clear_plots(self):
        children = self.axes.get_children()
        for child in children:
            if child.get_gid() is not None:
                if child.get_gid() in ['plot', 'peak', 'peakText',
                                       'peakShadow', 'peakThres']:
                    child.remove()

    def set_grid(self, on):
        self.axes.grid(on)
        self.redraw_plot()

    def set_bar(self, on):
        self.barBase.ax.set_visible(on)
        if on:
            self.axes.change_geometry(1, 2, 1)
            self.axes.get_subplotspec().get_gridspec().set_width_ratios([9.5, 0.5])
        else:
            self.axes.change_geometry(1, 1, 1)

        self.figure.subplots_adjust()

    def set_axes(self, on):
        if on:
            self.axes.set_axis_on()
            self.bar.set_axis_on()
        else:
            self.axes.set_axis_off()
            self.bar.set_axis_off()

    def set_colourmap_use(self, on):
        self.set_bar(on)
        if on:
            colourMap = self.settings.colourMap
        else:
            colourMap = get_colours()[0]

        self.set_colourmap(colourMap)

    def set_colourmap(self, colourMap):
        self.settings.colourMap = colourMap
        for collection in self.axes.collections:
            collection.set_cmap(colourMap)

        if get_colours().index(colourMap) < 4:
            self.set_bar(False)
        else:
            self.set_bar(True)
        self.barBase.set_cmap(colourMap)
        try:
            self.barBase.draw_all()
        except:
            pass

    def close(self):
        self.figure.clear()
        self.figure = None 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 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 def close_modeless():
    for child in wx.GetTopLevelWindows():
        if child.Title == 'Configure subplots':
            child.Close() class SatLevel(wx.PyControl):
    BAR_WIDTH = 10
    BAR_HEIGHT = 75
    PADDING = 5

    def __init__(self, parent, id=wx.ID_ANY, barCount=16):
        wx.PyControl.__init__(self, parent=parent, id=id, size=wx.DefaultSize,
                              style=wx.NO_BORDER)

        self.barCount = barCount
        self.sats = None

        self.Bind(wx.EVT_ERASE_BACKGROUND, self.__on_erase)
        self.Bind(wx.EVT_PAINT, self.__on_paint)

    def __on_erase(self, _event):
        pass

    def __on_paint(self, _event):
        dc = wx.BufferedPaintDC(self)
        self.__draw(dc)

    def __draw(self, dc):
        colour = self.GetBackgroundColour()
        brush = wx.Brush(colour, wx.SOLID)
        dc.SetBackground(brush)
        dc.SetFont(self.GetFont())
        attr = self.GetClassDefaultAttributes()
        dc.SetTextForeground(attr.colFg)
        dc.Clear()

        font = self.GetFont()
        font.SetPointSize(self.BAR_WIDTH)
        dc.SetFont(font)

        width, height = self.GetClientSize()
        widthTextFull, _height = dc.GetTextExtent('###')
        heightBar = height - widthTextFull - (self.PADDING * 2.0)
        widthBar = width / (self.barCount * 2.0)

        gc = wx.GraphicsContext.Create(dc)
        gc.SetPen(wx.GREY_PEN)
        gc.SetBrush(wx.BLUE_BRUSH)

        for i in range(self.barCount):
            x = self.PADDING + (widthBar * i * 2.0)

            if self.sats is not None and i < len(self.sats):
                sat = self.sats.items()[i]
                prn = sat[0]
                level = sat[1][0]
                used = sat[1][1]
                gc.SetBrush(wx.BLUE_BRUSH)
                if level is not None:
                    if used:
                        gc.SetBrush(wx.GREEN_BRUSH)
                    heightLevel = (level / 99.0) * heightBar
                else:
                    gc.SetBrush(wx.Brush(wx.BLUE, wx.CROSSDIAG_HATCH))
                    heightLevel = heightBar

                path = gc.CreatePath()
                path.AddRectangle(x,
                                  heightBar - heightLevel + self.PADDING,
                                  widthBar,
                                  heightLevel)
                gc.FillPath(path)
                text = '{:3d}'.format(prn)
            else:
                text = '  |'

            widthText, heightText = dc.GetTextExtent(text)
            dc.DrawRotatedText(text,
                               x + widthBar / 2 - heightText / 2,
                               height - widthText + self.PADDING * 2,
                               90)

            path = gc.CreatePath()
            path.AddRectangle(x,
                              self.PADDING,
                              widthBar,
                              heightBar)
            gc.StrokePath(path)

    def DoGetBestSize(self):
        font = self.GetFont()
        font.SetPointSize(self.BAR_WIDTH)
        dc = wx.ClientDC(self)
        dc.SetFont(font)
        widthText, heightText = dc.GetTextExtent('###')

        height = widthText + self.BAR_HEIGHT + self.PADDING * 2
        barWidth = max(heightText, self.BAR_WIDTH + self.PADDING)
        width = (barWidth + self.PADDING) * self.barCount

        return wx.Size(width, height)

    def set_sats(self, sats):
        self.sats = OrderedDict(sorted(sats.items()))
        self.Refresh()

    def clear_sats(self):
        self.sats = None
        self.Refresh()
import Queue
import copy
import textwrap
import matplotlib
import wx
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from wx import grid
from wx.lib import masked
from rtlsdr_scanner.constants import F_MIN, F_MAX, Cal, WINFUNC, PlotFunc
from rtlsdr_scanner.events import Event
from rtlsdr_scanner.file import File, open_plot
from rtlsdr_scanner.misc import format_precision, format_time
from rtlsdr_scanner.panels import PanelGraphCompare, PanelLine
from rtlsdr_scanner.plot_line import Plotter
from rtlsdr_scanner.spectrum import Extent, smooth_spectrum
from rtlsdr_scanner.utils_wx import close_modeless
from rtlsdr_scanner.widgets import SatLevel
            self.textLoc2.SetLabel(self.__format_loc(locs['x2'], locs['y2']))
            self.textLocDiff.SetLabel(self.__format_loc(locs['x3'], locs['y3']))

    def __on_load_plot(self, event):
        dlg = wx.FileDialog(self, "Open a scan", self.dirname, self.filename,
                            File.get_type_filters(File.Types.SAVE),
                            wx.OPEN)
        if dlg.ShowModal() == wx.ID_OK:
            self.dirname = dlg.GetDirectory()
            self.filename = dlg.GetFilename()
            _scanInfo, spectrum, _location = open_plot(self.dirname,
                                                       self.filename)
            if event.EventObject == self.buttonPlot1:
                self.textPlot1.SetLabel(self.filename)
                self.graph.set_spectrum1(spectrum)
            else:
                self.textPlot2.SetLabel(self.filename)
                self.graph.set_spectrum2(spectrum)

        dlg.Destroy()

    def __on_check1(self, _event):
        checked = self.checkOne.GetValue()
        self.settings.compareOne = checked
        self.graph.show_plot1(checked)

    def __on_check2(self, _event):
        checked = self.checkTwo.GetValue()
        self.settings.compareTwo = checked
        self.graph.show_plot2(checked)

    def __on_check_diff(self, _event):
        checked = self.checkDiff.GetValue()
        self.settings.compareDiff = checked
        self.graph.show_plotdiff(checked)

    def __on_close(self, _event):
        close_modeless()
        self.Destroy()

    def __format_loc(self, x, y):
        if None in [x, y]:
            return ""

        freq, level = format_precision(self.settings, x, y, units=False)

        return '{} MHz\n{}     dB/Hz'.format(freq, level)


class DialogSmooth(wx.Dialog):
    POLL = 250

    def __init__(self, parent, spectrum, settings):
        self.spectrum = spectrum
        self.settings = settings
        self.smoothed = None

        wx.Dialog.__init__(self, parent=parent, title='Smooth Spectrum',
                           style=wx.RESIZE_BORDER | wx.CAPTION | wx.SYSTEM_MENU |
                           wx.MAXIMIZE_BOX | wx.MINIMIZE_BOX | wx.CLOSE_BOX)

        self.queue = Queue.Queue()
        self.timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.__on_timer, self.timer)
        self.timer.Start(self.POLL)

        self.figure = matplotlib.figure.Figure(facecolor='white')
        self.canvas = FigureCanvas(self, -1, self.figure)
        settings = copy.copy(settings)
        settings.plotFunc = PlotFunc.NONE
        self.plot = Plotter(self.queue, self.figure, settings)

        textFunc = wx.StaticText(self, label='Window function')
        self.choiceFunc = wx.Choice(self, choices=WINFUNC[::2])
        self.choiceFunc.SetSelection(WINFUNC[::2].index(settings.smoothFunc))

        textRatio = wx.StaticText(self, label='Smoothing')
        self.slideRatio = wx.Slider(self, value=settings.smoothRatio,
                                    minValue=2, maxValue=100,
                                    style=wx.SL_INVERSE)

        buttonSmooth = wx.Button(self, label='Smooth')
        self.Bind(wx.EVT_BUTTON, self.__on_smooth, buttonSmooth)

        sizerButtons = wx.StdDialogButtonSizer()
        self.buttonOk = wx.Button(self, wx.ID_OK)
        self.buttonOk.Disable()
        buttonCancel = wx.Button(self, wx.ID_CANCEL)
        sizerButtons.AddButton(self.buttonOk)
        sizerButtons.AddButton(buttonCancel)
        sizerButtons.Realize()
        self.Bind(wx.EVT_BUTTON, self.__on_ok, self.buttonOk)

        sizerGrid = wx.GridBagSizer(5, 5)
        sizerGrid.Add(self.canvas, pos=(0, 0), span=(10, 6),
                      flag=wx.EXPAND | wx.ALL, border=5)
        sizerGrid.Add(textFunc, pos=(1, 6), border=5)
        sizerGrid.Add(self.choiceFunc, pos=(2, 6), span=(1, 2),
                      flag=wx.ALL, border=5)
        sizerGrid.Add(textRatio, pos=(3, 6),
                      flag=wx.ALL, border=5)
        sizerGrid.Add(self.slideRatio, pos=(4, 6), span=(1, 2),
                      flag=wx.ALL, border=5)
        sizerGrid.Add(buttonSmooth, pos=(5, 6), span=(1, 2),
                      flag=wx.ALL, border=5)
        sizerGrid.Add(sizerButtons, pos=(11, 6), span=(1, 2),
                      flag=wx.ALIGN_RIGHT | wx.ALL, border=5)
        sizerGrid.AddGrowableCol(0)
        sizerGrid.AddGrowableRow(0)

        self.SetSizerAndFit(sizerGrid)

        self.__draw_plot(self.spectrum)

    def __on_timer(self, _event):
        self.timer.Stop()
        while not self.queue.empty():
            event = self.queue.get()
            status = event.data.get_status()


            if status == Event.DRAW: